X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_mesa_to_tgsi.c;h=a19dcc92534a0be9932fcfd58764a1e8c09a3f8d;hb=f717fd25cc44d7dda5a49dc05337c7ee7c8d2d2f;hp=1611d53e2fe644fc981217aa2b129868152074e1;hpb=4ebc54795dc93f7eee200312abfa2da1b49506e3;p=mesa.git diff --git a/src/mesa/state_tracker/st_mesa_to_tgsi.c b/src/mesa/state_tracker/st_mesa_to_tgsi.c index 1611d53e2fe..a19dcc92534 100644 --- a/src/mesa/state_tracker/st_mesa_to_tgsi.c +++ b/src/mesa/state_tracker/st_mesa_to_tgsi.c @@ -34,20 +34,34 @@ #include "pipe/p_compiler.h" #include "pipe/p_shader_tokens.h" #include "pipe/p_state.h" +#include "pipe/p_context.h" #include "tgsi/tgsi_ureg.h" #include "st_mesa_to_tgsi.h" -#include "shader/prog_instruction.h" -#include "shader/prog_parameter.h" -#include "shader/prog_print.h" +#include "st_context.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" #include "util/u_debug.h" #include "util/u_math.h" #include "util/u_memory.h" + +#define PROGRAM_ANY_CONST ((1 << PROGRAM_LOCAL_PARAM) | \ + (1 << PROGRAM_ENV_PARAM) | \ + (1 << PROGRAM_STATE_VAR) | \ + (1 << PROGRAM_NAMED_PARAM) | \ + (1 << PROGRAM_CONSTANT) | \ + (1 << PROGRAM_UNIFORM)) + + struct label { unsigned branch_target; unsigned token; }; + +/** + * Intermediate state used during shader translation. + */ struct st_translate { struct ureg_program *ureg; @@ -58,6 +72,12 @@ struct st_translate { struct ureg_dst address[1]; struct ureg_src samplers[PIPE_MAX_SAMPLERS]; + /* Extra info for handling point size clamping in vertex shader */ + struct ureg_dst pointSizeResult; /**< Actual point size output register */ + struct ureg_src pointSizeConst; /**< Point size range constant register */ + GLint pointSizeOutIndex; /**< Temp point size output register */ + GLboolean prevInstWrotePointSize; + const GLuint *inputMapping; const GLuint *outputMapping; @@ -83,6 +103,12 @@ struct st_translate { }; +/** + * Make note of a branch to a label in the TGSI code. + * After we've emitted all instructions, we'll go over the list + * of labels built here and patch the TGSI code with the actual + * location of each label. + */ static unsigned *get_label( struct st_translate *t, unsigned branch_target ) { @@ -107,6 +133,12 @@ static unsigned *get_label( struct st_translate *t, } +/** + * Called prior to emitting the TGSI code for each Mesa instruction. + * Allocate additional space for instructions if needed. + * Update the insn[] array so the next Mesa instruction points to + * the next TGSI instruction. + */ static void set_insn_start( struct st_translate *t, unsigned start ) { @@ -126,8 +158,8 @@ static void set_insn_start( struct st_translate *t, } -/* - * Map mesa register file to TGSI register file. +/** + * Map a Mesa dst register to a TGSI ureg_dst register. */ static struct ureg_dst dst_register( struct st_translate *t, @@ -145,6 +177,18 @@ dst_register( struct st_translate *t, return t->temps[index]; case PROGRAM_OUTPUT: + if (t->procType == TGSI_PROCESSOR_VERTEX && index == VERT_RESULT_PSIZ) + t->prevInstWrotePointSize = GL_TRUE; + + if (t->procType == TGSI_PROCESSOR_VERTEX) + assert(index < VERT_RESULT_MAX); + else if (t->procType == TGSI_PROCESSOR_FRAGMENT) + assert(index < FRAG_RESULT_MAX); + else + assert(index < GEOM_RESULT_MAX); + + assert(t->outputMapping[index] < Elements(t->outputs)); + return t->outputs[t->outputMapping[index]]; case PROGRAM_ADDRESS: @@ -157,31 +201,44 @@ dst_register( struct st_translate *t, } +/** + * Map a Mesa src register to a TGSI ureg_src register. + */ static struct ureg_src src_register( struct st_translate *t, gl_register_file file, - GLuint index ) + GLint index ) { switch( file ) { case PROGRAM_UNDEFINED: return ureg_src_undef(); case PROGRAM_TEMPORARY: + assert(index >= 0); if (ureg_dst_is_undef(t->temps[index])) t->temps[index] = ureg_DECL_temporary( t->ureg ); + assert(index < Elements(t->temps)); return ureg_src(t->temps[index]); - case PROGRAM_STATE_VAR: case PROGRAM_NAMED_PARAM: case PROGRAM_ENV_PARAM: + case PROGRAM_LOCAL_PARAM: case PROGRAM_UNIFORM: - case PROGRAM_CONSTANT: /* ie, immediate */ + assert(index >= 0); return t->constants[index]; + case PROGRAM_STATE_VAR: + case PROGRAM_CONSTANT: /* ie, immediate */ + if (index < 0) + return ureg_DECL_constant( t->ureg, 0 ); + else + return t->constants[index]; case PROGRAM_INPUT: + assert(t->inputMapping[index] < Elements(t->inputs)); return t->inputs[t->inputMapping[index]]; case PROGRAM_OUTPUT: + assert(t->outputMapping[index] < Elements(t->outputs)); return ureg_src(t->outputs[t->outputMapping[index]]); /* not needed? */ case PROGRAM_ADDRESS: @@ -223,6 +280,9 @@ translate_texture_target( GLuint textarget, } +/** + * Create a TGSI ureg_dst register from a Mesa dest register. + */ static struct ureg_dst translate_dst( struct st_translate *t, const struct prog_dst_register *DstReg, @@ -245,12 +305,24 @@ translate_dst( struct st_translate *t, } +/** + * Create a TGSI ureg_src register from a Mesa src register. + */ static struct ureg_src translate_src( struct st_translate *t, const struct prog_src_register *SrcReg ) { struct ureg_src src = src_register( t, SrcReg->File, SrcReg->Index ); + if (t->procType == TGSI_PROCESSOR_GEOMETRY && SrcReg->HasIndex2) { + src = src_register( t, SrcReg->File, SrcReg->Index2 ); + if (SrcReg->RelAddr2) + src = ureg_src_dimension_indirect( src, ureg_src(t->address[0]), + SrcReg->Index); + else + src = ureg_src_dimension( src, SrcReg->Index); + } + src = ureg_swizzle( src, GET_SWZ( SrcReg->Swizzle, 0 ) & 0x3, GET_SWZ( SrcReg->Swizzle, 1 ) & 0x3, @@ -263,9 +335,19 @@ translate_src( struct st_translate *t, if (SrcReg->Abs) src = ureg_abs(src); - if (SrcReg->RelAddr) + if (SrcReg->RelAddr) { src = ureg_src_indirect( src, ureg_src(t->address[0])); - + if (SrcReg->File != PROGRAM_INPUT && + SrcReg->File != PROGRAM_OUTPUT) { + /* If SrcReg->Index was negative, it was set to zero in + * src_register(). Reassign it now. But don't do this + * for input/output regs since they get remapped while + * const buffers don't. + */ + src.Index = SrcReg->Index; + } + } + return src; } @@ -458,6 +540,10 @@ translate_opcode( unsigned op ) return TGSI_OPCODE_DST; case OPCODE_ELSE: return TGSI_OPCODE_ELSE; + case OPCODE_EMIT_VERTEX: + return TGSI_OPCODE_EMIT; + case OPCODE_END_PRIMITIVE: + return TGSI_OPCODE_ENDPRIM; case OPCODE_ENDIF: return TGSI_OPCODE_ENDIF; case OPCODE_ENDLOOP: @@ -650,6 +736,27 @@ compile_instruction( } +/** + * Emit the TGSI instructions to adjust the WPOS pixel center convention + */ +static void +emit_adjusted_wpos( struct st_translate *t, + const struct gl_program *program, GLfloat value) +{ + struct ureg_program *ureg = t->ureg; + struct ureg_dst wpos_temp = ureg_DECL_temporary(ureg); + struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]]; + + /* Note that we bias X and Y and pass Z and W through unchanged. + * The shader might also use gl_FragCoord.w and .z. + */ + ureg_ADD(ureg, wpos_temp, wpos_input, + ureg_imm4f(ureg, value, value, 0.0f, 0.0f)); + + t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]] = ureg_src(wpos_temp); +} + + /** * Emit the TGSI instructions for inverting the WPOS y coordinate. */ @@ -674,12 +781,17 @@ emit_inverted_wpos( struct st_translate *t, winSizeState); struct ureg_src winsize = ureg_DECL_constant( ureg, winHeightConst ); - struct ureg_dst wpos_temp = ureg_DECL_temporary( ureg ); + struct ureg_dst wpos_temp; struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]]; /* MOV wpos_temp, input[wpos] */ - ureg_MOV( ureg, wpos_temp, wpos_input ); + if (wpos_input.File == TGSI_FILE_TEMPORARY) + wpos_temp = ureg_dst(wpos_input); + else { + wpos_temp = ureg_DECL_temporary( ureg ); + ureg_MOV( ureg, wpos_temp, wpos_input ); + } /* SUB wpos_temp.y, winsize_const, wpos_input */ @@ -694,6 +806,65 @@ emit_inverted_wpos( struct st_translate *t, } +/** + * Emit fragment position/ooordinate code. + */ +static void +emit_wpos(struct st_context *st, + struct st_translate *t, + const struct gl_program *program, + struct ureg_program *ureg) +{ + const struct gl_fragment_program *fp = + (const struct gl_fragment_program *) program; + struct pipe_screen *pscreen = st->pipe->screen; + boolean invert = FALSE; + + if (fp->OriginUpperLeft) { + if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT)) { + } + else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT)) { + ureg_property_fs_coord_origin(ureg, TGSI_FS_COORD_ORIGIN_LOWER_LEFT); + invert = TRUE; + } + else + assert(0); + } + else { + if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT)) + ureg_property_fs_coord_origin(ureg, TGSI_FS_COORD_ORIGIN_LOWER_LEFT); + else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT)) + invert = TRUE; + else + assert(0); + } + + if (fp->PixelCenterInteger) { + if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) + ureg_property_fs_coord_pixel_center(ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER); + else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER)) + emit_adjusted_wpos(t, program, invert ? 0.5f : -0.5f); + else + assert(0); + } + else { + if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER)) { + } + else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) { + ureg_property_fs_coord_pixel_center(ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER); + emit_adjusted_wpos(t, program, invert ? -0.5f : 0.5f); + } + else + assert(0); + } + + /* we invert after adjustment so that we avoid the MOV to temporary, + * and reuse the adjustment ADD instead */ + if (invert) + emit_inverted_wpos(t, program); +} + + /** * OpenGL's fragment gl_FrontFace input is 1 for front-facing, 0 for back. * TGSI uses +1 for front, -1 for back. @@ -719,6 +890,18 @@ emit_face_var( struct st_translate *t, } +static void +emit_edgeflags( struct st_translate *t, + const struct gl_program *program ) +{ + struct ureg_program *ureg = t->ureg; + struct ureg_dst edge_dst = t->outputs[t->outputMapping[VERT_RESULT_EDGE]]; + struct ureg_src edge_src = t->inputs[t->inputMapping[VERT_ATTRIB_EDGEFLAG]]; + + ureg_MOV( ureg, edge_dst, edge_src ); +} + + /** * Translate Mesa program to TGSI format. * \param program the program to translate @@ -736,12 +919,13 @@ emit_face_var( struct st_translate *t, * \param outputSemanticIndex the semantic index (ex: which texcoord) for * each output * - * \return array of translated tokens, caller's responsibility to free + * \return PIPE_OK or PIPE_ERROR_OUT_OF_MEMORY */ -const struct tgsi_token * +enum pipe_error st_translate_mesa_program( GLcontext *ctx, uint procType, + struct ureg_program *ureg, const struct gl_program *program, GLuint numInputs, const GLuint inputMapping[], @@ -751,12 +935,15 @@ st_translate_mesa_program( GLuint numOutputs, const GLuint outputMapping[], const ubyte outputSemanticName[], - const ubyte outputSemanticIndex[] ) + const ubyte outputSemanticIndex[], + boolean passthrough_edgeflags ) { struct st_translate translate, *t; - struct ureg_program *ureg; - const struct tgsi_token *tokens = NULL; unsigned i; + enum pipe_error ret = PIPE_OK; + + assert(numInputs <= Elements(t->inputs)); + assert(numOutputs <= Elements(t->outputs)); t = &translate; memset(t, 0, sizeof *t); @@ -764,11 +951,9 @@ st_translate_mesa_program( t->procType = procType; t->inputMapping = inputMapping; t->outputMapping = outputMapping; - t->ureg = ureg_create( procType ); - if (t->ureg == NULL) - return NULL; - - ureg = t->ureg; + t->ureg = ureg; + t->pointSizeOutIndex = -1; + t->prevInstWrotePointSize = GL_FALSE; /*_mesa_print_program(program);*/ @@ -777,17 +962,26 @@ st_translate_mesa_program( */ if (procType == TGSI_PROCESSOR_FRAGMENT) { for (i = 0; i < numInputs; i++) { - t->inputs[i] = ureg_DECL_fs_input(ureg, - inputSemanticName[i], - inputSemanticIndex[i], - interpMode[i]); + if (program->InputFlags[0] & PROG_PARAM_BIT_CYL_WRAP) { + t->inputs[i] = ureg_DECL_fs_input_cyl(ureg, + inputSemanticName[i], + inputSemanticIndex[i], + interpMode[i], + TGSI_CYLINDRICAL_WRAP_X); + } + else { + t->inputs[i] = ureg_DECL_fs_input(ureg, + inputSemanticName[i], + inputSemanticIndex[i], + interpMode[i]); + } } if (program->InputsRead & FRAG_BIT_WPOS) { /* Must do this after setting up t->inputs, and before * emitting constant references, below: */ - emit_inverted_wpos( t, program ); + emit_wpos(st_context(ctx), t, program, ureg); } if (program->InputsRead & FRAG_BIT_FACE) { @@ -818,7 +1012,23 @@ st_translate_mesa_program( } } } + else if (procType == TGSI_PROCESSOR_GEOMETRY) { + for (i = 0; i < numInputs; i++) { + t->inputs[i] = ureg_DECL_gs_input(ureg, + i, + inputSemanticName[i], + inputSemanticIndex[i]); + } + + for (i = 0; i < numOutputs; i++) { + t->outputs[i] = ureg_DECL_output( ureg, + outputSemanticName[i], + outputSemanticIndex[i] ); + } + } else { + assert(procType == TGSI_PROCESSOR_VERTEX); + for (i = 0; i < numInputs; i++) { t->inputs[i] = ureg_DECL_vs_input(ureg, i); } @@ -827,7 +1037,28 @@ st_translate_mesa_program( t->outputs[i] = ureg_DECL_output( ureg, outputSemanticName[i], outputSemanticIndex[i] ); + if ((outputSemanticName[i] == TGSI_SEMANTIC_PSIZE) && program->Id) { + /* Writing to the point size result register requires special + * handling to implement clamping. + */ + static const gl_state_index pointSizeClampState[STATE_LENGTH] + = { STATE_INTERNAL, STATE_POINT_SIZE_IMPL_CLAMP, 0, 0, 0 }; + /* XXX: note we are modifying the incoming shader here! Need to + * do this before emitting the constant decls below, or this + * will be missed: + */ + unsigned pointSizeClampConst = + _mesa_add_state_reference(program->Parameters, + pointSizeClampState); + struct ureg_dst psizregtemp = ureg_DECL_temporary( ureg ); + t->pointSizeConst = ureg_DECL_constant( ureg, pointSizeClampConst ); + t->pointSizeResult = t->outputs[i]; + t->pointSizeOutIndex = i; + t->outputs[i] = psizregtemp; + } } + if (passthrough_edgeflags) + emit_edgeflags( t, program ); } /* Declare address register. @@ -837,33 +1068,45 @@ st_translate_mesa_program( t->address[0] = ureg_DECL_address( ureg ); } + if (program->IndirectRegisterFiles & (1 << PROGRAM_TEMPORARY)) { + /* If temps are accessed with indirect addressing, declare temporaries + * in sequential order. Else, we declare them on demand elsewhere. + */ + for (i = 0; i < program->NumTemporaries; i++) { + /* XXX use TGSI_FILE_TEMPORARY_ARRAY when it's supported by ureg */ + t->temps[i] = ureg_DECL_temporary( t->ureg ); + } + } /* Emit constants and immediates. Mesa uses a single index space * for these, so we put all the translated regs in t->constants. */ if (program->Parameters) { - t->constants = CALLOC( program->Parameters->NumParameters, sizeof t->constants[0] ); - if (t->constants == NULL) + if (t->constants == NULL) { + ret = PIPE_ERROR_OUT_OF_MEMORY; goto out; - + } + for (i = 0; i < program->Parameters->NumParameters; i++) { switch (program->Parameters->Parameters[i].Type) { case PROGRAM_ENV_PARAM: + case PROGRAM_LOCAL_PARAM: case PROGRAM_STATE_VAR: case PROGRAM_NAMED_PARAM: case PROGRAM_UNIFORM: t->constants[i] = ureg_DECL_constant( ureg, i ); break; - /* Emit immediates only when there is no address register - * in use. FIXME: Be smarter and recognize param arrays: + /* Emit immediates only when there's no indirect addressing of + * the const buffer. + * FIXME: Be smarter and recognize param arrays: * indirect addressing is only valid within the referenced * array. */ case PROGRAM_CONSTANT: - if (program->NumAddressRegs > 0) + if (program->IndirectRegisterFiles & PROGRAM_ANY_CONST) t->constants[i] = ureg_DECL_constant( ureg, i ); else t->constants[i] = @@ -889,6 +1132,25 @@ st_translate_mesa_program( for (i = 0; i < program->NumInstructions; i++) { set_insn_start( t, ureg_get_instruction_number( ureg )); compile_instruction( t, &program->Instructions[i] ); + + if (t->prevInstWrotePointSize && program->Id) { + /* The previous instruction wrote to the (fake) vertex point size + * result register. Now we need to clamp that value to the min/max + * point size range, putting the result into the real point size + * register. + * Note that we can't do this easily at the end of program due to + * possible early return. + */ + set_insn_start( t, ureg_get_instruction_number( ureg )); + ureg_MAX( t->ureg, + ureg_writemask(t->outputs[t->pointSizeOutIndex], WRITEMASK_X), + ureg_src(t->outputs[t->pointSizeOutIndex]), + ureg_swizzle(t->pointSizeConst, 1,1,1,1)); + ureg_MIN( t->ureg, ureg_writemask(t->pointSizeResult, WRITEMASK_X), + ureg_src(t->outputs[t->pointSizeOutIndex]), + ureg_swizzle(t->pointSizeConst, 2,2,2,2)); + } + t->prevInstWrotePointSize = GL_FALSE; } /* Fix up all emitted labels: @@ -899,9 +1161,6 @@ st_translate_mesa_program( t->insn[t->labels[i].branch_target] ); } - tokens = ureg_get_tokens( ureg, NULL ); - ureg_destroy( ureg ); - out: FREE(t->insn); FREE(t->labels); @@ -909,22 +1168,14 @@ out: if (t->error) { debug_printf("%s: translate error flag set\n", __FUNCTION__); - FREE((void *)tokens); - tokens = NULL; - } - - if (!tokens) { - debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__); - _mesa_print_program(program); - debug_assert(0); } - return tokens; + return ret; } /** - * Tokens cannot be free with _mesa_free otherwise the builtin gallium + * Tokens cannot be free with free otherwise the builtin gallium * malloc debugging will get confused. */ void