/** * Called when a new variant is needed, we need to translate * the ATI fragment shader to TGSI */ enum pipe_error st_translate_atifs_program( struct ureg_program *ureg, struct ati_fragment_shader *atifs, struct gl_program *program, GLuint numInputs, const GLuint inputMapping[], const ubyte inputSemanticName[], const ubyte inputSemanticIndex[], const GLuint interpMode[], GLuint numOutputs, const GLuint outputMapping[], const ubyte outputSemanticName[], const ubyte outputSemanticIndex[]) { enum pipe_error ret = PIPE_OK; unsigned pass, i, r; struct st_translate translate, *t; t = &translate; memset(t, 0, sizeof *t); t->inputMapping = inputMapping; t->outputMapping = outputMapping; t->ureg = ureg; t->atifs = atifs; /* * Declare input attributes. */ for (i = 0; i < numInputs; i++) { t->inputs[i] = ureg_DECL_fs_input(ureg, inputSemanticName[i], inputSemanticIndex[i], interpMode[i]); } /* * Declare output attributes: * we always have numOutputs=1 and it's FRAG_RESULT_COLOR */ t->outputs[0] = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, outputSemanticIndex[0]); /* 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) { ret = PIPE_ERROR_OUT_OF_MEMORY; goto out; } for (i = 0; i < program->Parameters->NumParameters; i++) { switch (program->Parameters->Parameters[i].Type) { case PROGRAM_STATE_VAR: case PROGRAM_UNIFORM: t->constants[i] = ureg_DECL_constant(ureg, i); break; case PROGRAM_CONSTANT: t->constants[i] = ureg_DECL_immediate(ureg, (const float*)program->Parameters->ParameterValues[i], 4); break; default: break; } } } /* texture samplers */ for (i = 0; i < MAX_NUM_FRAGMENT_REGISTERS_ATI; i++) { if (program->SamplersUsed & (1 << i)) { t->samplers[i] = ureg_DECL_sampler(ureg, i); /* the texture target is still unknown, it will be fixed in the draw call */ ureg_DECL_sampler_view(ureg, i, TGSI_TEXTURE_2D, TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT); } } /* emit instructions */ for (pass = 0; pass < atifs->NumPasses; pass++) { t->current_pass = pass; for (r = 0; r < MAX_NUM_FRAGMENT_REGISTERS_ATI; r++) { struct atifs_setupinst *texinst = &atifs->SetupInst[pass][r]; compile_setupinst(t, r, texinst); } for (i = 0; i < atifs->numArithInstr[pass]; i++) { struct atifs_instruction *inst = &atifs->Instructions[pass][i]; compile_instruction(t, inst); } } finalize_shader(t, atifs->NumPasses); out: free(t->constants); if (t->error) { debug_printf("%s: translate error flag set\n", __func__); } return ret; }
/** * Translate Mesa program to TGSI format. * \param program the program to translate * \param numInputs number of input registers used * \param inputMapping maps Mesa fragment program inputs to TGSI generic * input indexes * \param inputSemanticName the TGSI_SEMANTIC flag for each input * \param inputSemanticIndex the semantic index (ex: which texcoord) for * each input * \param interpMode the TGSI_INTERPOLATE_LINEAR/PERSP mode for each input * \param numOutputs number of output registers used * \param outputMapping maps Mesa fragment program outputs to TGSI * generic outputs * \param outputSemanticName the TGSI_SEMANTIC flag for each output * \param outputSemanticIndex the semantic index (ex: which texcoord) for * each output * * \return PIPE_OK or PIPE_ERROR_OUT_OF_MEMORY */ enum pipe_error st_translate_mesa_program( struct gl_context *ctx, uint procType, struct ureg_program *ureg, const struct gl_program *program, GLuint numInputs, const GLuint inputMapping[], const ubyte inputSemanticName[], const ubyte inputSemanticIndex[], const GLuint interpMode[], GLuint numOutputs, const GLuint outputMapping[], const ubyte outputSemanticName[], const ubyte outputSemanticIndex[], boolean passthrough_edgeflags, boolean clamp_color) { struct st_translate translate, *t; unsigned i; enum pipe_error ret = PIPE_OK; assert(numInputs <= ARRAY_SIZE(t->inputs)); assert(numOutputs <= ARRAY_SIZE(t->outputs)); t = &translate; memset(t, 0, sizeof *t); t->procType = procType; t->inputMapping = inputMapping; t->outputMapping = outputMapping; t->ureg = ureg; /*_mesa_print_program(program);*/ /* * Declare input attributes. */ 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->InputsRead & VARYING_BIT_POS) { /* Must do this after setting up t->inputs, and before * emitting constant references, below: */ emit_wpos(st_context(ctx), t, program, ureg); } if (program->InputsRead & VARYING_BIT_FACE) { emit_face_var( t, program ); } /* * Declare output attributes. */ for (i = 0; i < numOutputs; i++) { switch (outputSemanticName[i]) { case TGSI_SEMANTIC_POSITION: t->outputs[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, /* Z / Depth */ outputSemanticIndex[i] ); t->outputs[i] = ureg_writemask( t->outputs[i], TGSI_WRITEMASK_Z ); break; case TGSI_SEMANTIC_STENCIL: t->outputs[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_STENCIL, /* Stencil */ outputSemanticIndex[i] ); t->outputs[i] = ureg_writemask( t->outputs[i], TGSI_WRITEMASK_Y ); break; case TGSI_SEMANTIC_COLOR: t->outputs[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, outputSemanticIndex[i] ); break; default: debug_assert(0); return 0; } } } else if (procType == TGSI_PROCESSOR_GEOMETRY) { for (i = 0; i < numInputs; i++) { t->inputs[i] = ureg_DECL_input(ureg, inputSemanticName[i], inputSemanticIndex[i], 0, 1); } 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); } for (i = 0; i < numOutputs; i++) { t->outputs[i] = ureg_DECL_output( ureg, outputSemanticName[i], outputSemanticIndex[i] ); if (outputSemanticName[i] == TGSI_SEMANTIC_FOG) { /* force register to contain a fog coordinate in the form (F, 0, 0, 1). */ ureg_MOV(ureg, ureg_writemask(t->outputs[i], TGSI_WRITEMASK_YZW), ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f)); t->outputs[i] = ureg_writemask(t->outputs[i], TGSI_WRITEMASK_X); } } if (passthrough_edgeflags) emit_edgeflags( t, program ); } /* Declare address register. */ if (program->NumAddressRegs > 0) { debug_assert( program->NumAddressRegs == 1 ); t->address[0] = ureg_DECL_address( ureg ); } /* Declare misc input registers */ { GLbitfield sysInputs = program->SystemValuesRead; unsigned numSys = 0; for (i = 0; sysInputs; i++) { if (sysInputs & (1 << i)) { unsigned semName = _mesa_sysval_to_semantic[i]; t->systemValues[i] = ureg_DECL_system_value(ureg, numSys, semName, 0); if (semName == TGSI_SEMANTIC_INSTANCEID || semName == TGSI_SEMANTIC_VERTEXID) { /* From Gallium perspective, these system values are always * integer, and require native integer support. However, if * native integer is supported on the vertex stage but not the * pixel stage (e.g, i915g + draw), Mesa will generate IR that * assumes these system values are floats. To resolve the * inconsistency, we insert a U2F. */ struct st_context *st = st_context(ctx); struct pipe_screen *pscreen = st->pipe->screen; assert(procType == TGSI_PROCESSOR_VERTEX); assert(pscreen->get_shader_param(pscreen, PIPE_SHADER_VERTEX, PIPE_SHADER_CAP_INTEGERS)); (void) pscreen; /* silence non-debug build warnings */ if (!ctx->Const.NativeIntegers) { struct ureg_dst temp = ureg_DECL_local_temporary(t->ureg); ureg_U2F( t->ureg, ureg_writemask(temp, TGSI_WRITEMASK_X), t->systemValues[i]); t->systemValues[i] = ureg_scalar(ureg_src(temp), 0); } } numSys++; sysInputs &= ~(1 << i); } } } 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) { ret = PIPE_ERROR_OUT_OF_MEMORY; goto out; } for (i = 0; i < program->Parameters->NumParameters; i++) { switch (program->Parameters->Parameters[i].Type) { case PROGRAM_STATE_VAR: case PROGRAM_UNIFORM: t->constants[i] = ureg_DECL_constant( ureg, i ); break; /* 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->IndirectRegisterFiles & PROGRAM_ANY_CONST) t->constants[i] = ureg_DECL_constant( ureg, i ); else t->constants[i] = ureg_DECL_immediate( ureg, (const float*) program->Parameters->ParameterValues[i], 4 ); break; default: break; } } } /* texture samplers */ for (i = 0; i < ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits; i++) { if (program->SamplersUsed & (1 << i)) { t->samplers[i] = ureg_DECL_sampler( ureg, i ); } } /* Emit each instruction in turn: */ for (i = 0; i < program->NumInstructions; i++) { set_insn_start( t, ureg_get_instruction_number( ureg )); compile_instruction( ctx, t, &program->Instructions[i], clamp_color ); } /* Fix up all emitted labels: */ for (i = 0; i < t->labels_count; i++) { ureg_fixup_label( ureg, t->labels[i].token, t->insn[t->labels[i].branch_target] ); } out: free(t->insn); free(t->labels); free(t->constants); if (t->error) { debug_printf("%s: translate error flag set\n", __func__); } return ret; }
/** * Translate Mesa program to TGSI format. * \param program the program to translate * \param numInputs number of input registers used * \param inputMapping maps Mesa fragment program inputs to TGSI generic * input indexes * \param inputSemanticName the TGSI_SEMANTIC flag for each input * \param inputSemanticIndex the semantic index (ex: which texcoord) for each input * \param interpMode the TGSI_INTERPOLATE_LINEAR/PERSP mode for each input * \param numOutputs number of output registers used * \param outputMapping maps Mesa fragment program outputs to TGSI * generic outputs * \param outputSemanticName the TGSI_SEMANTIC flag for each output * \param outputSemanticIndex the semantic index (ex: which texcoord) for each output * \param tokens array to store translated tokens in * \param maxTokens size of the tokens array * * \return number of tokens placed in 'tokens' buffer, or zero if error */ GLuint st_translate_mesa_program( GLcontext *ctx, uint procType, const struct gl_program *program, GLuint numInputs, const GLuint inputMapping[], const ubyte inputSemanticName[], const ubyte inputSemanticIndex[], const GLuint interpMode[], const GLbitfield inputFlags[], GLuint numOutputs, const GLuint outputMapping[], const ubyte outputSemanticName[], const ubyte outputSemanticIndex[], const GLbitfield outputFlags[], struct tgsi_token *tokens, GLuint maxTokens ) { GLuint i; GLuint ti; /* token index */ struct tgsi_header *header; struct tgsi_processor *processor; GLuint preamble_size = 0; GLuint immediates[1000]; GLuint numImmediates = 0; GLboolean insideSubroutine = GL_FALSE; GLboolean indirectAccess = GL_FALSE; GLboolean tempsUsed[MAX_PROGRAM_TEMPS + 1]; GLint wposTemp = -1, winHeightConst = -1; assert(procType == TGSI_PROCESSOR_FRAGMENT || procType == TGSI_PROCESSOR_VERTEX); find_temporaries(program, tempsUsed); if (procType == TGSI_PROCESSOR_FRAGMENT) { if (program->InputsRead & FRAG_BIT_WPOS) { /* Fragment program uses fragment position input. * Need to replace instances of INPUT[WPOS] with temp T * where T = INPUT[WPOS] by y is inverted. */ static const gl_state_index winSizeState[STATE_LENGTH] = { STATE_INTERNAL, STATE_FB_SIZE, 0, 0, 0 }; winHeightConst = _mesa_add_state_reference(program->Parameters, winSizeState); wposTemp = find_free_temporary(tempsUsed); } } *(struct tgsi_version *) &tokens[0] = tgsi_build_version(); header = (struct tgsi_header *) &tokens[1]; *header = tgsi_build_header(); processor = (struct tgsi_processor *) &tokens[2]; *processor = tgsi_build_processor( procType, header ); ti = 3; /* * Declare input attributes. */ if (procType == TGSI_PROCESSOR_FRAGMENT) { for (i = 0; i < numInputs; i++) { struct tgsi_full_declaration fulldecl; fulldecl = make_input_decl(i, GL_TRUE, interpMode[i], TGSI_WRITEMASK_XYZW, GL_TRUE, inputSemanticName[i], inputSemanticIndex[i], inputFlags[i]); ti += tgsi_build_full_declaration(&fulldecl, &tokens[ti], header, maxTokens - ti ); } } else { /* vertex prog */ /* XXX: this could probaby be merged with the clause above. * the only difference is the semantic tags. */ for (i = 0; i < numInputs; i++) { struct tgsi_full_declaration fulldecl; fulldecl = make_input_decl(i, GL_FALSE, 0, TGSI_WRITEMASK_XYZW, GL_FALSE, 0, 0, inputFlags[i]); ti += tgsi_build_full_declaration(&fulldecl, &tokens[ti], header, maxTokens - ti ); } } /* * Declare output attributes. */ if (procType == TGSI_PROCESSOR_FRAGMENT) { for (i = 0; i < numOutputs; i++) { struct tgsi_full_declaration fulldecl; switch (outputSemanticName[i]) { case TGSI_SEMANTIC_POSITION: fulldecl = make_output_decl(i, TGSI_SEMANTIC_POSITION, /* Z / Depth */ outputSemanticIndex[i], TGSI_WRITEMASK_Z, outputFlags[i]); break; case TGSI_SEMANTIC_COLOR: fulldecl = make_output_decl(i, TGSI_SEMANTIC_COLOR, outputSemanticIndex[i], TGSI_WRITEMASK_XYZW, outputFlags[i]); break; default: assert(0); return 0; } ti += tgsi_build_full_declaration(&fulldecl, &tokens[ti], header, maxTokens - ti ); } } else { /* vertex prog */ for (i = 0; i < numOutputs; i++) { struct tgsi_full_declaration fulldecl; fulldecl = make_output_decl(i, outputSemanticName[i], outputSemanticIndex[i], TGSI_WRITEMASK_XYZW, outputFlags[i]); ti += tgsi_build_full_declaration(&fulldecl, &tokens[ti], header, maxTokens - ti ); } } /* temporary decls */ { GLboolean inside_range = GL_FALSE; GLuint start_range = 0; tempsUsed[MAX_PROGRAM_TEMPS] = GL_FALSE; for (i = 0; i < MAX_PROGRAM_TEMPS + 1; i++) { if (tempsUsed[i] && !inside_range) { inside_range = GL_TRUE; start_range = i; } else if (!tempsUsed[i] && inside_range) { struct tgsi_full_declaration fulldecl; inside_range = GL_FALSE; fulldecl = make_temp_decl( start_range, i - 1 ); ti += tgsi_build_full_declaration( &fulldecl, &tokens[ti], header, maxTokens - ti ); } } } /* Declare address register. */ if (program->NumAddressRegs > 0) { struct tgsi_full_declaration fulldecl; assert( program->NumAddressRegs == 1 ); fulldecl = make_addr_decl( 0, 0 ); ti += tgsi_build_full_declaration( &fulldecl, &tokens[ti], header, maxTokens - ti ); indirectAccess = GL_TRUE; } /* immediates/literals */ memset(immediates, ~0, sizeof(immediates)); /* Emit immediates only when there is no address register in use. * FIXME: Be smarter and recognize param arrays -- indirect addressing is * only valid within the referenced array. */ if (program->Parameters && !indirectAccess) { for (i = 0; i < program->Parameters->NumParameters; i++) { if (program->Parameters->Parameters[i].Type == PROGRAM_CONSTANT) { struct tgsi_full_immediate fullimm; fullimm = make_immediate( program->Parameters->ParameterValues[i], 4 ); ti += tgsi_build_full_immediate( &fullimm, &tokens[ti], header, maxTokens - ti ); immediates[i] = numImmediates; numImmediates++; } } } /* constant buffer refs */ if (program->Parameters) { GLint start = -1, end = -1; for (i = 0; i < program->Parameters->NumParameters; i++) { GLboolean emit = (i == program->Parameters->NumParameters - 1); GLboolean matches; switch (program->Parameters->Parameters[i].Type) { case PROGRAM_ENV_PARAM: case PROGRAM_STATE_VAR: case PROGRAM_NAMED_PARAM: case PROGRAM_UNIFORM: matches = GL_TRUE; break; case PROGRAM_CONSTANT: matches = indirectAccess; break; default: matches = GL_FALSE; } if (matches) { if (start == -1) { /* begin a sequence */ start = i; end = i; } else { /* continue sequence */ end = i; } } else { if (start != -1) { /* end of sequence */ emit = GL_TRUE; } } if (emit && start >= 0) { struct tgsi_full_declaration fulldecl; fulldecl = make_constant_decl( start, end ); ti += tgsi_build_full_declaration( &fulldecl, &tokens[ti], header, maxTokens - ti ); start = end = -1; } } } /* texture samplers */ for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) { if (program->SamplersUsed & (1 << i)) { struct tgsi_full_declaration fulldecl; fulldecl = make_sampler_decl( i ); ti += tgsi_build_full_declaration( &fulldecl, &tokens[ti], header, maxTokens - ti ); } } /* invert WPOS fragment input */ if (wposTemp >= 0) { ti += emit_inverted_wpos(&tokens[ti], wposTemp, winHeightConst, inputMapping[FRAG_ATTRIB_WPOS], header, maxTokens - ti); preamble_size = 2; /* two instructions added */ } for (i = 0; i < program->NumInstructions; i++) { struct tgsi_full_instruction fullinst; compile_instruction( &program->Instructions[i], &fullinst, inputMapping, outputMapping, immediates, indirectAccess, preamble_size, procType, &insideSubroutine, wposTemp); ti += tgsi_build_full_instruction( &fullinst, &tokens[ti], header, maxTokens - ti ); } #if DEBUG if(!tgsi_sanity_check(tokens)) { debug_printf("Due to sanity check failure(s) above the following shader program is invalid:\n"); debug_printf("\nOriginal program:\n%s", program->String); debug_printf("\nMesa program:\n"); _mesa_print_program(program); debug_printf("\nTGSI program:\n"); tgsi_dump(tokens, 0); assert(0); } #endif return ti; }