const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) { const struct tgsi_token *tokens; emit_header( ureg ); emit_decls( ureg ); copy_instructions( ureg ); fixup_header_size( ureg ); if (ureg->domain[0].tokens == error_tokens || ureg->domain[1].tokens == error_tokens) { debug_printf("%s: error in generated shader\n", __FUNCTION__); assert(0); return NULL; } tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; if (0) { debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, ureg->domain[DOMAIN_DECL].count); tgsi_dump( tokens, 0 ); } #if DEBUG if (tokens && !tgsi_sanity_check(tokens)) { debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); tgsi_dump(tokens, 0); assert(0); } #endif return tokens; }
boolean tgsi_text_translate( const char *text, struct tgsi_token *tokens, uint num_tokens ) { struct translate_ctx ctx = {0}; ctx.text = text; ctx.cur = text; ctx.tokens = tokens; ctx.tokens_cur = tokens; ctx.tokens_end = tokens + num_tokens; if (!translate( &ctx )) return FALSE; return tgsi_sanity_check( tokens ); }
/** * 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; }