Fragment shader translation seems to basically work now. More testing needed.

This commit is contained in:
Brian 2007-08-21 20:13:31 -06:00
parent d70d41eefc
commit 0d9bcdbeb1
8 changed files with 284 additions and 322 deletions

View file

@ -22,7 +22,6 @@ DRIVER_SOURCES = \
i915_strings.c \
i915_prim_emit.c \
i915_tex_layout.c \
i915_fpc.c \
i915_fpc_debug.c \
i915_fpc_emit.c \
i915_fpc_translate.c \

View file

@ -84,6 +84,11 @@ struct i915_state
{
unsigned immediate[I915_MAX_IMMEDIATE];
unsigned dynamic[I915_MAX_DYNAMIC];
uint *program;
uint program_len;
uint *constants;
uint num_constants;
unsigned id; /* track lost context events */
};
@ -115,6 +120,8 @@ struct i915_context
struct pipe_viewport_state viewport;
struct pipe_vertex_buffer vertex_buffer[PIPE_ATTRIB_MAX];
struct pipe_constant_buffer temp_constants; /*XXX temporary*/
unsigned dirty;
unsigned *batch_start;

View file

@ -35,149 +35,3 @@
#include "i915_fpc.h"
void
i915_program_error(struct i915_fp_compile *p, const char *msg)
{
fprintf(stderr, "i915_program_error: %s", msg);
p->fp->error = 1;
}
static struct i915_fp_compile *
i915_init_compile(struct i915_context *i915, struct i915_fragment_program *fp)
{
struct i915_fp_compile *p = CALLOC_STRUCT(i915_fp_compile);
p->fp = fp;
#if 0
p->env_param = NULL; /*i915->intel.ctx.FragmentProgram.Parameters;*/
#endif
p->constants = i915->fs.constants;
p->nr_tex_indirect = 1; /* correct? */
p->nr_tex_insn = 0;
p->nr_alu_insn = 0;
p->nr_decl_insn = 0;
memset(p->constant_flags, 0, sizeof(p->constant_flags));
p->csr = p->program;
p->decl = p->declarations;
p->decl_s = 0;
p->decl_t = 0;
p->temp_flag = 0xffff000;
p->utemp_flag = ~0x7;
#if 0
p->fp->translated = 0;
p->fp->error = 0;
p->fp->nr_constants = 0;
#endif
p->fp->wpos_tex = -1;
p->fp->nr_params = 0;
*(p->decl++) = _3DSTATE_PIXEL_SHADER_PROGRAM;
return p;
}
/* Copy compile results to the fragment program struct and destroy the
* compilation context.
*/
static void
i915_fini_compile(struct i915_fp_compile *p)
{
uint program_size = p->csr - p->program;
uint decl_size = p->decl - p->declarations;
if (p->nr_tex_indirect > I915_MAX_TEX_INDIRECT)
i915_program_error(p, "Exceeded max nr indirect texture lookups");
if (p->nr_tex_insn > I915_MAX_TEX_INSN)
i915_program_error(p, "Exceeded max TEX instructions");
if (p->nr_alu_insn > I915_MAX_ALU_INSN)
i915_program_error(p, "Exceeded max ALU instructions");
if (p->nr_decl_insn > I915_MAX_DECL_INSN)
i915_program_error(p, "Exceeded max DECL instructions");
if (p->fp->error) {
p->fp->NumNativeInstructions = 0;
p->fp->NumNativeAluInstructions = 0;
p->fp->NumNativeTexInstructions = 0;
p->fp->NumNativeTexIndirections = 0;
return;
}
else {
p->fp->NumNativeInstructions = (p->nr_alu_insn +
p->nr_tex_insn +
p->nr_decl_insn);
p->fp->NumNativeAluInstructions = p->nr_alu_insn;
p->fp->NumNativeTexInstructions = p->nr_tex_insn;
p->fp->NumNativeTexIndirections = p->nr_tex_indirect;
}
p->declarations[0] |= program_size + decl_size - 2;
/* Copy compilation results to fragment program struct:
*/
memcpy(p->fp->program,
p->declarations,
decl_size * sizeof(uint));
memcpy(p->fp->program + decl_size,
p->program,
program_size * sizeof(uint));
p->fp->program_size = program_size + decl_size;
/* Release the compilation struct:
*/
free(p);
}
/**
* Find an unused texture coordinate slot to use for fragment WPOS.
* Update p->fp->wpos_tex with the result (-1 if no used texcoord slot is found).
*/
static void
find_wpos_space(struct i915_fp_compile *p)
{
const uint inputs = p->shader->inputs_read;
uint i;
p->fp->wpos_tex = -1;
if (inputs & FRAG_BIT_WPOS) {
for (i = 0; i < I915_TEX_UNITS; i++) {
if ((inputs & (FRAG_BIT_TEX0 << i)) == 0) {
p->fp->wpos_tex = i;
return;
}
}
i915_program_error(p, "No free texcoord for wpos value");
}
}
void i915_compile_fragment_program( struct i915_context *i915,
struct i915_fragment_program *fp )
{
struct i915_fp_compile *p = i915_init_compile(i915, fp);
struct tgsi_token *tokens = i915->fs.tokens;
find_wpos_space(p);
i915_translate_program(p, tokens);
i915_fixup_depth_write(p);
i915_fini_compile(p);
#if 0
fp->translated = 1;
#endif
}

View file

@ -90,71 +90,10 @@ enum
#if 1 /*XXX temp */
/* Hardware version of a parsed fragment program. "Derived" from the
* mesa fragment_program struct.
/**
* Program translation state
*/
struct i915_fragment_program
{
#if 0
struct gl_fragment_program Base;
#else
uint NumNativeInstructions;
uint NumNativeAluInstructions;
uint NumNativeTexInstructions;
uint NumNativeTexIndirections;
#endif
boolean error; /**< Set if i915_program_error() is called */
#if 0
uint id; /**< String id */
boolean translated;
#endif
/* Decls + instructions:
*/
uint program[I915_PROGRAM_SIZE];
uint program_size;
#if 0
/* Constant buffer:
*/
float constant[I915_MAX_CONSTANT][4];
uint nr_constants;
#endif
/* Some of which are parameters:
*/
struct
{
uint reg; /* Hardware constant idx */
const float *values; /* Pointer to tracked values */
} param[I915_MAX_CONSTANT];
uint nr_params;
#if 0
uint param_state;
#endif
uint wpos_tex;
};
#endif
/***********************************************************************
* Public interface for the compiler
*/
void i915_compile_fragment_program( struct i915_context *i915,
struct i915_fragment_program *fp );
/***********************************************************************
* Private details of the compiler
*/
struct i915_fp_compile {
struct i915_fragment_program *fp;
struct pipe_shader_state *shader;
uint declarations[I915_PROGRAM_SIZE];
@ -186,9 +125,12 @@ struct i915_fp_compile {
uint nr_alu_insn;
uint nr_decl_insn;
#if 0
float (*env_param)[4];
#endif
boolean error; /**< Set if i915_program_error() is called */
uint wpos_tex;
uint NumNativeInstructions;
uint NumNativeAluInstructions;
uint NumNativeTexInstructions;
uint NumNativeTexIndirections;
};
@ -268,6 +210,14 @@ negate(int reg, int x, int y, int z, int w)
}
/***********************************************************************
* Public interface for the compiler
*/
extern void i915_translate_fragment_program( struct i915_context *i915 );
extern uint i915_get_temp(struct i915_fp_compile *p);
extern uint i915_get_utemp(struct i915_fp_compile *p);
extern void i915_release_utemps(struct i915_fp_compile *p);
@ -302,38 +252,21 @@ extern uint i915_emit_const4f(struct i915_fp_compile *p,
float c2, float c3);
#if 0
extern uint i915_emit_param4fv(struct i915_fp_compile *p,
const float * values);
#endif
/*======================================================================
* i915_fpc_debug.c
*/
extern void i915_program_error(struct i915_fp_compile *p,
const char *msg);
/*======================================================================
* i915_fpc_debug.c
*/
extern void i915_disassemble_program(const uint * program, uint sz);
#if 0
extern void i915_print_mesa_instructions( const struct prog_instruction *insn,
uint nr );
#endif
/*======================================================================
* i915_fpc_translate.c
*/
void i915_fixup_depth_write(struct i915_fp_compile *p);
extern void
i915_translate_program(struct i915_fp_compile *p, const struct tgsi_token *token);
i915_program_error(struct i915_fp_compile *p, const char *msg);
extern void
i915_translate_fragment_program(struct i915_context *i915);
#endif

View file

@ -32,6 +32,34 @@
#include "pipe/tgsi/core/tgsi_token.h"
#include "pipe/tgsi/core/tgsi_parse.h"
/**
* Simple pass-through fragment shader to use when we don't have
* a real shader (or it fails to compile for some reason).
*/
static unsigned passthrough[] =
{
_3DSTATE_PIXEL_SHADER_PROGRAM | ((2*3)-1),
/* declare input color:
*/
(D0_DCL |
(REG_TYPE_T << D0_TYPE_SHIFT) |
(T_DIFFUSE << D0_NR_SHIFT) |
D0_CHANNEL_ALL),
0,
0,
/* move to output color:
*/
(A0_MOV |
(REG_TYPE_OC << A0_DEST_TYPE_SHIFT) |
A0_DEST_CHANNEL_ALL |
(REG_TYPE_T << A0_SRC0_TYPE_SHIFT) |
(T_DIFFUSE << A0_SRC0_NR_SHIFT)),
0x01230000, /* .xyzw */
0
};
/* 1, -1/3!, 1/5!, -1/7! */
static const float sin_constants[4] = { 1.0,
@ -48,6 +76,30 @@ static const float cos_constants[4] = { 1.0,
};
static void
i915_use_passthrough_shader(struct i915_context *i915)
{
fprintf(stderr, "**** Using i915 pass-through fragment shader\n");
i915->current.program = (uint *) malloc(sizeof(passthrough));
memcpy(i915->current.program, passthrough, sizeof(passthrough));
i915->current.program_len = Elements(passthrough);
i915->current.constants = NULL;
i915->current.num_constants = 0;
}
void
i915_program_error(struct i915_fp_compile *p, const char *msg)
{
fprintf(stderr, "i915_program_error: %s\n", msg);
p->error = 1;
}
/**
* Construct a ureg for the given source register. Will emit
* constants, apply swizzling and negation as needed.
@ -59,7 +111,7 @@ src_vector(struct i915_fp_compile *p,
const uint index = source->SrcRegister.Index;
uint src;
switch (source->SrcRegisterInd.File) {
switch (source->SrcRegister.File) {
case TGSI_FILE_TEMPORARY:
if (source->SrcRegister.Index >= I915_MAX_TEMPORARY) {
i915_program_error(p, "Exceeded max temporary reg");
@ -79,7 +131,7 @@ src_vector(struct i915_fp_compile *p,
*/
switch (index) {
case FRAG_ATTRIB_WPOS:
src = i915_emit_decl(p, REG_TYPE_T, p->fp->wpos_tex, D0_CHANNEL_ALL);
src = i915_emit_decl(p, REG_TYPE_T, p->wpos_tex, D0_CHANNEL_ALL);
break;
case FRAG_ATTRIB_COL0:
src = i915_emit_decl(p, REG_TYPE_T, T_DIFFUSE, D0_CHANNEL_ALL);
@ -111,27 +163,9 @@ src_vector(struct i915_fp_compile *p,
}
break;
/* Various parameters and env values. All emitted to
* hardware as program constants.
*/
#if 0
case PROGRAM_LOCAL_PARAM:
src = i915_emit_param4fv(p, program->Base.LocalParams[index]);
break;
case PROGRAM_ENV_PARAM:
src = i915_emit_param4fv(p, p->env_param[index]);
break;
case PROGRAM_CONSTANT:
case PROGRAM_STATE_VAR:
case PROGRAM_NAMED_PARAM:
src = i915_emit_param4fv(
p, program->Base.Parameters->ParameterValues[index]);
break;
#else
case TGSI_FILE_CONSTANT:
src = UREG(REG_TYPE_CONST, index);
break;
#endif
default:
i915_program_error(p, "Bad source->File");
@ -151,26 +185,14 @@ src_vector(struct i915_fp_compile *p,
assert(!source->SrcRegisterExtSwz.NegateW);
assert(!source->SrcRegisterExtMod.Absolute);
assert(!source->SrcRegisterExtMod.Negate);
#if 0
if (source->SrcRegister.Negate)
negate all
if (extended source swiz per component)
src = negate(src,
source->SrcRegisterExtSwz.NegateX,
source->SrcRegisterExtSwz.NegateY,
source->SrcRegisterExtSwz.NegateZ,
source->SrcRegisterExtSwz.NegateW);
if (mod.abs)
absolute value
if (mod.negate)
another negate;
#endif
return src;
}
/**
* Construct a ureg for a destination register.
*/
static uint
get_result_vector(struct i915_fp_compile *p,
const struct tgsi_full_dst_register *dest)
@ -178,9 +200,9 @@ get_result_vector(struct i915_fp_compile *p,
switch (dest->DstRegister.File) {
case TGSI_FILE_OUTPUT:
switch (dest->DstRegister.Index) {
case FRAG_RESULT_COLR:
case 1: /*COLOR*/ /*FRAG_RESULT_COLR:*/
return UREG(REG_TYPE_OC, 0);
case FRAG_RESULT_DEPR:
case 0: /*DEPTH*/ /*FRAG_RESULT_DEPR:*/
return UREG(REG_TYPE_OD, 0);
default:
i915_program_error(p, "Bad inst->DstReg.Index");
@ -296,12 +318,15 @@ emit_simple_arith(struct i915_fp_compile *p,
}
#define EMIT_1ARG_ARITH( OP ) emit_simple_arith(p, inst, OP, 1)
#define EMIT_2ARG_ARITH( OP ) emit_simple_arith(p, inst, OP, 2)
#define EMIT_3ARG_ARITH( OP ) emit_simple_arith(p, inst, OP, 3)
/*
* Translate TGSI instruction to i915 instruction.
*
* Possible concerns:
*
* SIN, COS -- could use another taylor step?
* LIT -- results seem a little different to sw mesa
* LOG -- different to mesa on negative numbers, but this is conformant.
*/
static void
i915_translate_instruction(struct i915_fp_compile *p,
const struct tgsi_full_instruction *inst)
@ -321,7 +346,7 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_ADD:
EMIT_2ARG_ARITH(A0_ADD);
emit_simple_arith(p, inst, A0_ADD, 2);
break;
case TGSI_OPCODE_CMP:
@ -385,11 +410,11 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_DP3:
EMIT_2ARG_ARITH(A0_DP3);
emit_simple_arith(p, inst, A0_DP3, 2);
break;
case TGSI_OPCODE_DP4:
EMIT_2ARG_ARITH(A0_DP4);
emit_simple_arith(p, inst, A0_DP4, 2);
break;
case TGSI_OPCODE_DPH:
@ -431,11 +456,11 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_FLR:
EMIT_1ARG_ARITH(A0_FLR);
emit_simple_arith(p, inst, A0_FLR, 1);
break;
case TGSI_OPCODE_FRC:
EMIT_1ARG_ARITH(A0_FRC);
emit_simple_arith(p, inst, A0_FRC, 1);
break;
case TGSI_OPCODE_KIL:
@ -512,11 +537,11 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_MAD:
EMIT_3ARG_ARITH(A0_MAD);
emit_simple_arith(p, inst, A0_MAD, 3);
break;
case TGSI_OPCODE_MAX:
EMIT_2ARG_ARITH(A0_MAX);
emit_simple_arith(p, inst, A0_MAX, 2);
break;
case TGSI_OPCODE_MIN:
@ -539,11 +564,11 @@ i915_translate_instruction(struct i915_fp_compile *p,
case TGSI_OPCODE_MOV:
/* aka TGSI_OPCODE_SWZ */
EMIT_1ARG_ARITH(A0_MOV);
emit_simple_arith(p, inst, A0_MOV, 1);
break;
case TGSI_OPCODE_MUL:
EMIT_2ARG_ARITH(A0_MUL);
emit_simple_arith(p, inst, A0_MUL, 2);
break;
case TGSI_OPCODE_POW:
@ -652,7 +677,7 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_SGE:
EMIT_2ARG_ARITH(A0_SGE);
emit_simple_arith(p, inst, A0_SGE, 2);
break;
case TGSI_OPCODE_SIN:
@ -706,7 +731,7 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_SLT:
EMIT_2ARG_ARITH(A0_SLT);
emit_simple_arith(p, inst, A0_SLT, 2);
break;
case TGSI_OPCODE_SUB:
@ -769,20 +794,12 @@ i915_translate_instruction(struct i915_fp_compile *p,
/**
* Translate TGSI fragment shader into i915 hardware instructions.
*
* Possible concerns:
*
* SIN, COS -- could use another taylor step?
* LIT -- results seem a little different to sw mesa
* LOG -- different to mesa on negative numbers, but this is conformant.
*
* Parse failures -- Mesa doesn't currently give a good indication
* internally whether a particular program string parsed or not. This
* can lead to confusion -- hopefully we cope with it ok now.
* \param p the translation state
* \param tokens the TGSI token array
*/
void
i915_translate_program(struct i915_fp_compile *p,
const struct tgsi_token *tokens)
static void
i915_translate_instructions(struct i915_fp_compile *p,
const struct tgsi_token *tokens)
{
struct tgsi_parse_context parse;
@ -794,10 +811,11 @@ i915_translate_program(struct i915_fp_compile *p,
switch( parse.FullToken.Token.Type ) {
case TGSI_TOKEN_TYPE_DECLARATION:
assert(0);
/* XXX no-op? */
break;
case TGSI_TOKEN_TYPE_IMMEDIATE:
/* XXX no-op? */
assert(0);
break;
@ -815,13 +833,139 @@ i915_translate_program(struct i915_fp_compile *p,
}
static struct i915_fp_compile *
i915_init_compile(struct i915_context *i915,
struct pipe_shader_state *fs)
{
struct i915_fp_compile *p = CALLOC_STRUCT(i915_fp_compile);
p->shader = &i915->fs;
/* a bit of a hack, need to improve constant buffer infrastructure */
if (i915->fs.constants)
p->constants = i915->fs.constants;
else
p->constants = &i915->temp_constants;
p->nr_tex_indirect = 1; /* correct? */
p->nr_tex_insn = 0;
p->nr_alu_insn = 0;
p->nr_decl_insn = 0;
memset(p->constant_flags, 0, sizeof(p->constant_flags));
p->csr = p->program;
p->decl = p->declarations;
p->decl_s = 0;
p->decl_t = 0;
p->temp_flag = 0xffff000;
p->utemp_flag = ~0x7;
p->wpos_tex = -1;
/* initialize the first program word */
*(p->decl++) = _3DSTATE_PIXEL_SHADER_PROGRAM;
return p;
}
/* Copy compile results to the fragment program struct and destroy the
* compilation context.
*/
static void
i915_fini_compile(struct i915_context *i915, struct i915_fp_compile *p)
{
uint program_size = p->csr - p->program;
uint decl_size = p->decl - p->declarations;
if (p->nr_tex_indirect > I915_MAX_TEX_INDIRECT)
i915_program_error(p, "Exceeded max nr indirect texture lookups");
if (p->nr_tex_insn > I915_MAX_TEX_INSN)
i915_program_error(p, "Exceeded max TEX instructions");
if (p->nr_alu_insn > I915_MAX_ALU_INSN)
i915_program_error(p, "Exceeded max ALU instructions");
if (p->nr_decl_insn > I915_MAX_DECL_INSN)
i915_program_error(p, "Exceeded max DECL instructions");
if (p->error) {
p->NumNativeInstructions = 0;
p->NumNativeAluInstructions = 0;
p->NumNativeTexInstructions = 0;
p->NumNativeTexIndirections = 0;
i915_use_passthrough_shader(i915);
}
else {
p->NumNativeInstructions = (p->nr_alu_insn +
p->nr_tex_insn +
p->nr_decl_insn);
p->NumNativeAluInstructions = p->nr_alu_insn;
p->NumNativeTexInstructions = p->nr_tex_insn;
p->NumNativeTexIndirections = p->nr_tex_indirect;
/* patch in the program length */
p->declarations[0] |= program_size + decl_size - 2;
/* Copy compilation results to fragment program struct:
*/
i915->current.program
= (uint *) malloc((program_size + decl_size) * sizeof(uint));
i915->current.program_len = program_size + decl_size;
memcpy(i915->current.program,
p->declarations,
decl_size * sizeof(uint));
memcpy(i915->current.program + decl_size,
p->program,
program_size * sizeof(uint));
i915->current.constants = (uint *) p->constants->constant;
i915->current.num_constants = p->constants->nr_constants;
}
/* Release the compilation struct:
*/
free(p);
}
/* Rather than trying to intercept and jiggle depth writes during
/**
* Find an unused texture coordinate slot to use for fragment WPOS.
* Update p->fp->wpos_tex with the result (-1 if no used texcoord slot is found).
*/
static void
i915_find_wpos_space(struct i915_fp_compile *p)
{
const uint inputs = p->shader->inputs_read;
uint i;
p->wpos_tex = -1;
if (inputs & FRAG_BIT_WPOS) {
for (i = 0; i < I915_TEX_UNITS; i++) {
if ((inputs & (FRAG_BIT_TEX0 << i)) == 0) {
p->wpos_tex = i;
return;
}
}
i915_program_error(p, "No free texcoord for wpos value");
}
}
/**
* Rather than trying to intercept and jiggle depth writes during
* emit, just move the value into its correct position at the end of
* the program:
*/
void
static void
i915_fixup_depth_write(struct i915_fp_compile *p)
{
if (p->shader->outputs_written & (1<<FRAG_RESULT_DEPR)) {
@ -835,5 +979,16 @@ i915_fixup_depth_write(struct i915_fp_compile *p)
}
void
i915_translate_fragment_program( struct i915_context *i915 )
{
struct i915_fp_compile *p = i915_init_compile(i915, &i915->fs);
const struct tgsi_token *tokens = i915->fs.tokens;
i915_find_wpos_space(p);
i915_translate_instructions(p, tokens);
i915_fixup_depth_write(p);
i915_fini_compile(i915, p);
}

View file

@ -27,7 +27,7 @@
/* Authors: Keith Whitwell <keith@tungstengraphics.com>
*/
//#include "imports.h"
#include "pipe/draw/draw_context.h"

View file

@ -149,6 +149,11 @@ void i915_update_derived( struct i915_context *i915 )
if (i915->dirty)
i915_update_dynamic( i915 );
if (i915->dirty & I915_NEW_FS) {
i915_translate_fragment_program(i915);
i915->hardware_dirty |= I915_HW_PROGRAM; /* XXX right? */
}
/* HW emit currently references framebuffer state directly:
*/
if (i915->dirty & I915_NEW_FRAMEBUFFER)

View file

@ -26,10 +26,6 @@
**************************************************************************/
//#include "glheader.h"
//#include "mtypes.h"
#include "i915_reg.h"
#include "i915_context.h"
#include "i915_winsys.h"
@ -116,9 +112,6 @@ i915_emit_hardware_state(struct i915_context *i915 )
}
if (i915->hardware_dirty & I915_HW_IMMEDIATE)
{
OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
@ -143,8 +136,6 @@ i915_emit_hardware_state(struct i915_context *i915 )
}
}
if (i915->hardware_dirty & I915_HW_STATIC)
{
if (i915->framebuffer.cbufs[0]) {
@ -180,7 +171,6 @@ i915_emit_hardware_state(struct i915_context *i915 )
I915_BUFFER_ACCESS_WRITE,
0);
}
{
unsigned cformat = translate_format( i915->framebuffer.cbufs[0]->format );
@ -198,19 +188,38 @@ i915_emit_hardware_state(struct i915_context *i915 )
cformat |
zformat );
}
}
/* constants */
if (i915->hardware_dirty & I915_HW_PROGRAM)
{
unsigned i, dwords;
unsigned *prog = i915_passthrough_program( &dwords );
for (i = 0; i < dwords; i++)
OUT_BATCH( prog[i] );
const uint nr = i915->current.num_constants;
if (nr > 0) {
const uint *c = (const uint *) i915->current.constants;
uint i;
OUT_BATCH( _3DSTATE_PIXEL_SHADER_CONSTANTS | (nr * 4) );
OUT_BATCH( (1 << (nr - 1)) | ((1 << (nr - 1)) - 1) );
for (i = 0; i < nr; i++) {
OUT_BATCH(*c++);
OUT_BATCH(*c++);
OUT_BATCH(*c++);
OUT_BATCH(*c++);
}
}
}
/* Fragment program */
if (i915->hardware_dirty & I915_HW_PROGRAM)
{
uint i;
/* we should always have, at least, a pass-through program */
assert(i915->current.program_len > 0);
for (i = 0; i < i915->current.program_len; i++) {
OUT_BATCH(i915->current.program[i]);
}
}
/* drawing surface size */
{
int w = i915->framebuffer.cbufs[0]->width;
int h = i915->framebuffer.cbufs[0]->height;