boolean tgsi_iterate_shader( const struct tgsi_token *tokens, struct tgsi_iterate_context *ctx ) { struct tgsi_parse_context parse; if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) return FALSE; ctx->processor = parse.FullHeader.Processor; if (ctx->prolog) if (!ctx->prolog( ctx )) goto fail; while (!tgsi_parse_end_of_tokens( &parse )) { tgsi_parse_token( &parse ); switch (parse.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_INSTRUCTION: if (ctx->iterate_instruction) if (!ctx->iterate_instruction( ctx, &parse.FullToken.FullInstruction )) goto fail; break; case TGSI_TOKEN_TYPE_DECLARATION: if (ctx->iterate_declaration) if (!ctx->iterate_declaration( ctx, &parse.FullToken.FullDeclaration )) goto fail; break; case TGSI_TOKEN_TYPE_IMMEDIATE: if (ctx->iterate_immediate) if (!ctx->iterate_immediate( ctx, &parse.FullToken.FullImmediate )) goto fail; break; case TGSI_TOKEN_TYPE_PROPERTY: if (ctx->iterate_property) if (!ctx->iterate_property( ctx, &parse.FullToken.FullProperty )) goto fail; break; default: assert( 0 ); } } if (ctx->epilog) if (!ctx->epilog( ctx )) goto fail; tgsi_parse_free( &parse ); return TRUE; fail: tgsi_parse_free( &parse ); return FALSE; }
static boolean nv30_vertprog_prepare(struct nv30_vpc *vpc) { struct tgsi_parse_context p; int nr_imm = 0; tgsi_parse_init(&p, vpc->vp->pipe.tokens); while (!tgsi_parse_end_of_tokens(&p)) { const union tgsi_full_token *tok = &p.FullToken; tgsi_parse_token(&p); switch(tok->Token.Type) { case TGSI_TOKEN_TYPE_IMMEDIATE: nr_imm++; break; default: break; } } tgsi_parse_free(&p); if (nr_imm) { vpc->imm = CALLOC(nr_imm, sizeof(struct nv30_sreg)); assert(vpc->imm); } return TRUE; }
void r300_tgsi_to_rc(struct tgsi_to_rc * ttr, const struct tgsi_token * tokens) { struct tgsi_full_instruction *inst; struct tgsi_parse_context parser; unsigned imm_index = 0; int i; /* Allocate constants placeholders. * * Note: What if declared constants are not contiguous? */ for(i = 0; i <= ttr->info->file_max[TGSI_FILE_CONSTANT]; ++i) { struct rc_constant constant; memset(&constant, 0, sizeof(constant)); constant.Type = RC_CONSTANT_EXTERNAL; constant.Size = 4; constant.u.External = i; rc_constants_add(&ttr->compiler->Program.Constants, &constant); } ttr->immediate_offset = ttr->compiler->Program.Constants.Count; ttr->imms_to_swizzle = malloc(ttr->info->immediate_count * sizeof(struct swizzled_imms)); ttr->imms_to_swizzle_count = 0; tgsi_parse_init(&parser, tokens); while (!tgsi_parse_end_of_tokens(&parser)) { tgsi_parse_token(&parser); switch (parser.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_DECLARATION: break; case TGSI_TOKEN_TYPE_IMMEDIATE: handle_immediate(ttr, &parser.FullToken.FullImmediate, imm_index); imm_index++; break; case TGSI_TOKEN_TYPE_INSTRUCTION: inst = &parser.FullToken.FullInstruction; /* This hack with the RET opcode woudn't work with * conditionals. */ if (inst->Instruction.Opcode == TGSI_OPCODE_END || inst->Instruction.Opcode == TGSI_OPCODE_RET) { break; } transform_instruction(ttr, inst); break; } } tgsi_parse_free(&parser); free(ttr->imms_to_swizzle); rc_calculate_inputs_outputs(ttr->compiler); }
int main(int argc, char **argv) { if(argc < 2) { fprintf(stderr, "Must pass shader source name as argument\n"); exit(1); } const char *text = load_text_file(argv[1]); if(!text) { fprintf(stderr, "Unable to open %s\n", argv[1]); exit(1); } struct tgsi_token tokens[1024]; if(tgsi_text_translate(text, tokens, Elements(tokens))) { tgsi_dump(tokens, 0); union { struct tgsi_header h; struct tgsi_token t; } hdr; hdr.t = tokens[0]; printf("Header size: %i\n", hdr.h.HeaderSize); printf("Body size: %i\n", hdr.h.BodySize); int totalSize = hdr.h.HeaderSize + hdr.h.BodySize; for(int i=0; i<totalSize; ++i) { printf("%08x ", *((uint32_t*)&tokens[i])); } printf("\n"); /* Parsing test */ struct tgsi_parse_context ctx = {}; unsigned status = TGSI_PARSE_OK; status = tgsi_parse_init(&ctx, tokens); assert(status == TGSI_PARSE_OK); while(!tgsi_parse_end_of_tokens(&ctx)) { tgsi_parse_token(&ctx); /* declaration / immediate / instruction / property */ printf("Parsed token! %i\n", ctx.FullToken.Token.Type); } tgsi_parse_free(&ctx); } else { fprintf(stderr, "Unable to parse %s\n", argv[1]); } return 0; }
void r300_tgsi_to_rc(struct tgsi_to_rc * ttr, const struct tgsi_token * tokens) { struct tgsi_parse_context parser; int i; /* Allocate constants placeholders. * * Note: What if declared constants are not contiguous? */ for(i = 0; i <= ttr->info->file_max[TGSI_FILE_CONSTANT]; ++i) { struct rc_constant constant; memset(&constant, 0, sizeof(constant)); constant.Type = RC_CONSTANT_EXTERNAL; constant.Size = 4; constant.u.External = i; rc_constants_add(&ttr->compiler->Program.Constants, &constant); } ttr->immediate_offset = ttr->compiler->Program.Constants.Count; tgsi_parse_init(&parser, tokens); while (!tgsi_parse_end_of_tokens(&parser)) { tgsi_parse_token(&parser); switch (parser.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_DECLARATION: break; case TGSI_TOKEN_TYPE_IMMEDIATE: handle_immediate(ttr, &parser.FullToken.FullImmediate); break; case TGSI_TOKEN_TYPE_INSTRUCTION: transform_instruction(ttr, &parser.FullToken.FullInstruction); break; } } tgsi_parse_free(&parser); rc_calculate_inputs_outputs(ttr->compiler); }
/** * Scan the given TGSI shader to collect information such as number of * registers used, special instructions used, etc. * \return info the result of the scan */ void tgsi_scan_shader(const struct tgsi_token *tokens, struct tgsi_shader_info *info) { uint procType, i; struct tgsi_parse_context parse; memset(info, 0, sizeof(*info)); for (i = 0; i < TGSI_FILE_COUNT; i++) info->file_max[i] = -1; /** ** Setup to begin parsing input shader **/ if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) { debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n"); return; } procType = parse.FullHeader.Processor.Processor; assert(procType == TGSI_PROCESSOR_FRAGMENT || procType == TGSI_PROCESSOR_VERTEX || procType == TGSI_PROCESSOR_GEOMETRY || procType == TGSI_PROCESSOR_COMPUTE); info->processor = procType; /** ** Loop over incoming program tokens/instructions */ while( !tgsi_parse_end_of_tokens( &parse ) ) { info->num_tokens++; tgsi_parse_token( &parse ); switch( parse.FullToken.Token.Type ) { case TGSI_TOKEN_TYPE_INSTRUCTION: { const struct tgsi_full_instruction *fullinst = &parse.FullToken.FullInstruction; uint i; assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST); info->opcode_count[fullinst->Instruction.Opcode]++; for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) { const struct tgsi_full_src_register *src = &fullinst->Src[i]; int ind = src->Register.Index; /* Mark which inputs are effectively used */ if (src->Register.File == TGSI_FILE_INPUT) { unsigned usage_mask; usage_mask = tgsi_util_get_inst_usage_mask(fullinst, i); if (src->Register.Indirect) { for (ind = 0; ind < info->num_inputs; ++ind) { info->input_usage_mask[ind] |= usage_mask; } } else { assert(ind >= 0); assert(ind < PIPE_MAX_SHADER_INPUTS); info->input_usage_mask[ind] |= usage_mask; } if (procType == TGSI_PROCESSOR_FRAGMENT && src->Register.File == TGSI_FILE_INPUT && info->reads_position && src->Register.Index == 0 && (src->Register.SwizzleX == TGSI_SWIZZLE_Z || src->Register.SwizzleY == TGSI_SWIZZLE_Z || src->Register.SwizzleZ == TGSI_SWIZZLE_Z || src->Register.SwizzleW == TGSI_SWIZZLE_Z)) { info->reads_z = TRUE; } } /* check for indirect register reads */ if (src->Register.Indirect) { info->indirect_files |= (1 << src->Register.File); } } /* check for indirect register writes */ for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) { const struct tgsi_full_dst_register *dst = &fullinst->Dst[i]; if (dst->Register.Indirect) { info->indirect_files |= (1 << dst->Register.File); } } info->num_instructions++; } break; case TGSI_TOKEN_TYPE_DECLARATION: { const struct tgsi_full_declaration *fulldecl = &parse.FullToken.FullDeclaration; const uint file = fulldecl->Declaration.File; uint reg; for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) { /* only first 32 regs will appear in this bitfield */ info->file_mask[file] |= (1 << reg); info->file_count[file]++; info->file_max[file] = MAX2(info->file_max[file], (int)reg); if (file == TGSI_FILE_INPUT) { info->input_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name; info->input_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index; info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate; info->input_centroid[reg] = (ubyte)fulldecl->Interp.Centroid; info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap; info->num_inputs++; if (procType == TGSI_PROCESSOR_FRAGMENT && fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION) info->reads_position = TRUE; } else if (file == TGSI_FILE_SYSTEM_VALUE) { unsigned index = fulldecl->Range.First; unsigned semName = fulldecl->Semantic.Name; info->system_value_semantic_name[index] = semName; info->num_system_values = MAX2(info->num_system_values, index + 1); /* info->system_value_semantic_name[info->num_system_values++] = fulldecl->Semantic.Name; */ if (fulldecl->Semantic.Name == TGSI_SEMANTIC_INSTANCEID) { info->uses_instanceid = TRUE; } else if (fulldecl->Semantic.Name == TGSI_SEMANTIC_VERTEXID) { info->uses_vertexid = TRUE; } else if (fulldecl->Semantic.Name == TGSI_SEMANTIC_PRIMID) { info->uses_primid = TRUE; } } else if (file == TGSI_FILE_OUTPUT) { info->output_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name; info->output_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index; info->num_outputs++; if ((procType == TGSI_PROCESSOR_VERTEX || procType == TGSI_PROCESSOR_GEOMETRY) && fulldecl->Semantic.Name == TGSI_SEMANTIC_CLIPDIST) { info->num_written_clipdistance += util_bitcount(fulldecl->Declaration.UsageMask); } if ((procType == TGSI_PROCESSOR_VERTEX || procType == TGSI_PROCESSOR_GEOMETRY) && fulldecl->Semantic.Name == TGSI_SEMANTIC_CULLDIST) { info->num_written_culldistance += util_bitcount(fulldecl->Declaration.UsageMask); } /* extra info for special outputs */ if (procType == TGSI_PROCESSOR_FRAGMENT && fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION) info->writes_z = TRUE; if (procType == TGSI_PROCESSOR_FRAGMENT && fulldecl->Semantic.Name == TGSI_SEMANTIC_STENCIL) info->writes_stencil = TRUE; if (procType == TGSI_PROCESSOR_VERTEX && fulldecl->Semantic.Name == TGSI_SEMANTIC_EDGEFLAG) { info->writes_edgeflag = TRUE; } if (procType == TGSI_PROCESSOR_GEOMETRY && fulldecl->Semantic.Name == TGSI_SEMANTIC_VIEWPORT_INDEX) { info->writes_viewport_index = TRUE; } if (procType == TGSI_PROCESSOR_GEOMETRY && fulldecl->Semantic.Name == TGSI_SEMANTIC_LAYER) { info->writes_layer = TRUE; } } } } break; case TGSI_TOKEN_TYPE_IMMEDIATE: { uint reg = info->immediate_count++; uint file = TGSI_FILE_IMMEDIATE; info->file_mask[file] |= (1 << reg); info->file_count[file]++; info->file_max[file] = MAX2(info->file_max[file], (int)reg); } break; case TGSI_TOKEN_TYPE_PROPERTY: { const struct tgsi_full_property *fullprop = &parse.FullToken.FullProperty; info->properties[info->num_properties].name = fullprop->Property.PropertyName; memcpy(info->properties[info->num_properties].data, fullprop->u, 8 * sizeof(unsigned));; ++info->num_properties; } break; default: assert( 0 ); } } info->uses_kill = (info->opcode_count[TGSI_OPCODE_KIL] || info->opcode_count[TGSI_OPCODE_KILP]); /* extract simple properties */ for (i = 0; i < info->num_properties; ++i) { switch (info->properties[i].name) { case TGSI_PROPERTY_FS_COORD_ORIGIN: info->origin_lower_left = info->properties[i].data[0]; break; case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: info->pixel_center_integer = info->properties[i].data[0]; break; case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS: info->color0_writes_all_cbufs = info->properties[i].data[0]; break; case TGSI_PROPERTY_GS_INPUT_PRIM: /* The dimensions of the IN decleration in geometry shader have * to be deduced from the type of the input primitive. */ if (procType == TGSI_PROCESSOR_GEOMETRY) { unsigned input_primitive = info->properties[i].data[0]; int num_verts = u_vertices_per_prim(input_primitive); unsigned j; info->file_count[TGSI_FILE_INPUT] = num_verts; info->file_max[TGSI_FILE_INPUT] = MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1); for (j = 0; j < num_verts; ++j) { info->file_mask[TGSI_FILE_INPUT] |= (1 << j); } } break; default: ; } } tgsi_parse_free (&parse); }
/** * Check if the given shader is a "passthrough" shader consisting of only * MOV instructions of the form: MOV OUT[n], IN[n] * */ boolean tgsi_is_passthrough_shader(const struct tgsi_token *tokens) { struct tgsi_parse_context parse; /** ** Setup to begin parsing input shader **/ if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) { debug_printf("tgsi_parse_init() failed in tgsi_is_passthrough_shader()!\n"); return FALSE; } /** ** Loop over incoming program tokens/instructions */ while (!tgsi_parse_end_of_tokens(&parse)) { tgsi_parse_token(&parse); switch (parse.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_INSTRUCTION: { struct tgsi_full_instruction *fullinst = &parse.FullToken.FullInstruction; const struct tgsi_full_src_register *src = &fullinst->Src[0]; const struct tgsi_full_dst_register *dst = &fullinst->Dst[0]; /* Do a whole bunch of checks for a simple move */ if (fullinst->Instruction.Opcode != TGSI_OPCODE_MOV || (src->Register.File != TGSI_FILE_INPUT && src->Register.File != TGSI_FILE_SYSTEM_VALUE) || dst->Register.File != TGSI_FILE_OUTPUT || src->Register.Index != dst->Register.Index || src->Register.Negate || src->Register.Absolute || src->Register.SwizzleX != TGSI_SWIZZLE_X || src->Register.SwizzleY != TGSI_SWIZZLE_Y || src->Register.SwizzleZ != TGSI_SWIZZLE_Z || src->Register.SwizzleW != TGSI_SWIZZLE_W || dst->Register.WriteMask != TGSI_WRITEMASK_XYZW) { tgsi_parse_free(&parse); return FALSE; } } break; case TGSI_TOKEN_TYPE_DECLARATION: /* fall-through */ case TGSI_TOKEN_TYPE_IMMEDIATE: /* fall-through */ case TGSI_TOKEN_TYPE_PROPERTY: /* fall-through */ default: ; /* no-op */ } } tgsi_parse_free(&parse); /* if we get here, it's a pass-through shader */ return TRUE; }
void lp_build_tgsi_aos(struct gallivm_state *gallivm, const struct tgsi_token *tokens, struct lp_type type, const unsigned char swizzles[4], LLVMValueRef consts_ptr, const LLVMValueRef *inputs, LLVMValueRef *outputs, struct lp_build_sampler_aos *sampler, const struct tgsi_shader_info *info) { struct lp_build_tgsi_aos_context bld; struct tgsi_parse_context parse; uint num_immediates = 0; unsigned chan; int pc = 0; /* Setup build context */ memset(&bld, 0, sizeof bld); lp_build_context_init(&bld.bld_base.base, gallivm, type); lp_build_context_init(&bld.bld_base.uint_bld, gallivm, lp_uint_type(type)); lp_build_context_init(&bld.bld_base.int_bld, gallivm, lp_int_type(type)); lp_build_context_init(&bld.int_bld, gallivm, lp_int_type(type)); for (chan = 0; chan < 4; ++chan) { bld.swizzles[chan] = swizzles[chan]; bld.inv_swizzles[swizzles[chan]] = chan; } bld.inputs = inputs; bld.outputs = outputs; bld.consts_ptr = consts_ptr; bld.sampler = sampler; bld.indirect_files = info->indirect_files; bld.bld_base.emit_swizzle = swizzle_aos; bld.bld_base.info = info; bld.bld_base.emit_fetch_funcs[TGSI_FILE_CONSTANT] = emit_fetch_constant; bld.bld_base.emit_fetch_funcs[TGSI_FILE_IMMEDIATE] = emit_fetch_immediate; bld.bld_base.emit_fetch_funcs[TGSI_FILE_INPUT] = emit_fetch_input; bld.bld_base.emit_fetch_funcs[TGSI_FILE_TEMPORARY] = emit_fetch_temporary; /* Set opcode actions */ lp_set_default_actions_cpu(&bld.bld_base); if (!lp_bld_tgsi_list_init(&bld.bld_base)) { return; } tgsi_parse_init(&parse, tokens); while (!tgsi_parse_end_of_tokens(&parse)) { tgsi_parse_token(&parse); switch(parse.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_DECLARATION: /* Inputs already interpolated */ lp_emit_declaration_aos(&bld, &parse.FullToken.FullDeclaration); break; case TGSI_TOKEN_TYPE_INSTRUCTION: /* save expanded instruction */ lp_bld_tgsi_add_instruction(&bld.bld_base, &parse.FullToken.FullInstruction); break; case TGSI_TOKEN_TYPE_IMMEDIATE: /* simply copy the immediate values into the next immediates[] slot */ { const uint size = parse.FullToken.FullImmediate.Immediate.NrTokens - 1; float imm[4]; assert(size <= 4); assert(num_immediates < LP_MAX_TGSI_IMMEDIATES); for (chan = 0; chan < 4; ++chan) { imm[chan] = 0.0f; } for (chan = 0; chan < size; ++chan) { unsigned swizzle = bld.swizzles[chan]; imm[swizzle] = parse.FullToken.FullImmediate.u[chan].Float; } bld.immediates[num_immediates] = lp_build_const_aos(gallivm, type, imm[0], imm[1], imm[2], imm[3], NULL); num_immediates++; } break; case TGSI_TOKEN_TYPE_PROPERTY: break; default: assert(0); } } while (pc != -1) { struct tgsi_full_instruction *instr = bld.bld_base.instructions + pc; const struct tgsi_opcode_info *opcode_info = tgsi_get_opcode_info(instr->Instruction.Opcode); if (!lp_emit_instruction_aos(&bld, instr, opcode_info, &pc)) _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n", opcode_info->mnemonic); } if (0) { LLVMBasicBlockRef block = LLVMGetInsertBlock(gallivm->builder); LLVMValueRef function = LLVMGetBasicBlockParent(block); debug_printf("11111111111111111111111111111 \n"); tgsi_dump(tokens, 0); lp_debug_dump_value(function); debug_printf("2222222222222222222222222222 \n"); } tgsi_parse_free(&parse); FREE(bld.bld_base.instructions); if (0) { LLVMModuleRef module = LLVMGetGlobalParent( LLVMGetBasicBlockParent(LLVMGetInsertBlock(gallivm->builder))); LLVMDumpModule(module); } }
/** * Detect any direct relationship between the output color */ void lp_build_tgsi_info(const struct tgsi_token *tokens, struct lp_tgsi_info *info) { struct tgsi_parse_context parse; struct analysis_context ctx; unsigned index; unsigned chan; memset(info, 0, sizeof *info); tgsi_scan_shader(tokens, &info->base); memset(&ctx, 0, sizeof ctx); ctx.info = info; tgsi_parse_init(&parse, tokens); while (!tgsi_parse_end_of_tokens(&parse)) { tgsi_parse_token(&parse); switch (parse.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_DECLARATION: break; case TGSI_TOKEN_TYPE_INSTRUCTION: { struct tgsi_full_instruction *inst = &parse.FullToken.FullInstruction; if (inst->Instruction.Opcode == TGSI_OPCODE_END || inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) { /* We reached the end of main function body. */ goto finished; } analyse_instruction(&ctx, inst); } break; case TGSI_TOKEN_TYPE_IMMEDIATE: { const unsigned size = parse.FullToken.FullImmediate.Immediate.NrTokens - 1; assert(size <= 4); if (ctx.num_imms < Elements(ctx.imm)) { for (chan = 0; chan < size; ++chan) { float value = parse.FullToken.FullImmediate.u[chan].Float; ctx.imm[ctx.num_imms][chan] = value; if (value < 0.0f || value > 1.0f) { info->unclamped_immediates = TRUE; } } ++ctx.num_imms; } } break; case TGSI_TOKEN_TYPE_PROPERTY: break; default: assert(0); } } finished: tgsi_parse_free(&parse); /* * Link the output color values. */ for (index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) { const struct lp_tgsi_channel_info null_output[4]; info->cbuf[index] = null_output; } for (index = 0; index < info->base.num_outputs; ++index) { unsigned semantic_name = info->base.output_semantic_name[index]; unsigned semantic_index = info->base.output_semantic_index[index]; if (semantic_name == TGSI_SEMANTIC_COLOR && semantic_index < PIPE_MAX_COLOR_BUFS) { info->cbuf[semantic_index] = info->output[index]; } } if (gallivm_debug & GALLIVM_DEBUG_TGSI) { dump_info(tokens, info); } }
void tgsi_dump_c( const struct tgsi_token *tokens, uint flags ) { struct tgsi_parse_context parse; struct tgsi_full_instruction fi; struct tgsi_full_declaration fd; uint ignored = flags & TGSI_DUMP_C_IGNORED; uint deflt = flags & TGSI_DUMP_C_DEFAULT; uint instno = 0; tgsi_parse_init( &parse, tokens ); TXT( "tgsi-dump begin -----------------" ); TXT( "\nMajorVersion: " ); UID( parse.FullVersion.Version.MajorVersion ); TXT( "\nMinorVersion: " ); UID( parse.FullVersion.Version.MinorVersion ); EOL(); TXT( "\nHeaderSize: " ); UID( parse.FullHeader.Header.HeaderSize ); TXT( "\nBodySize : " ); UID( parse.FullHeader.Header.BodySize ); TXT( "\nProcessor : " ); ENM( parse.FullHeader.Processor.Processor, TGSI_PROCESSOR_TYPES ); EOL(); fi = tgsi_default_full_instruction(); fd = tgsi_default_full_declaration(); while( !tgsi_parse_end_of_tokens( &parse ) ) { tgsi_parse_token( &parse ); TXT( "\nType : " ); ENM( parse.FullToken.Token.Type, TGSI_TOKEN_TYPES ); if( ignored ) { TXT( "\nSize : " ); UID( parse.FullToken.Token.Size ); if( deflt || parse.FullToken.Token.Extended ) { TXT( "\nExtended : " ); UID( parse.FullToken.Token.Extended ); } } switch( parse.FullToken.Token.Type ) { case TGSI_TOKEN_TYPE_DECLARATION: dump_declaration_verbose( &parse.FullToken.FullDeclaration, ignored, deflt, &fd ); break; case TGSI_TOKEN_TYPE_IMMEDIATE: dump_immediate_verbose( &parse.FullToken.FullImmediate, ignored ); break; case TGSI_TOKEN_TYPE_INSTRUCTION: dump_instruction_verbose( &parse.FullToken.FullInstruction, ignored, deflt, &fi ); break; default: assert( 0 ); } EOL(); } TXT( "\ntgsi-dump end -------------------\n" ); tgsi_parse_free( &parse ); }
/** * Scan the given TGSI shader to collect information such as number of * registers used, special instructions used, etc. * \return info the result of the scan */ void tgsi_scan_shader(const struct tgsi_token *tokens, struct tgsi_shader_info *info) { uint procType, i; struct tgsi_parse_context parse; unsigned current_depth = 0; memset(info, 0, sizeof(*info)); for (i = 0; i < TGSI_FILE_COUNT; i++) info->file_max[i] = -1; for (i = 0; i < ARRAY_SIZE(info->const_file_max); i++) info->const_file_max[i] = -1; info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1; for (i = 0; i < ARRAY_SIZE(info->sampler_targets); i++) info->sampler_targets[i] = TGSI_TEXTURE_UNKNOWN; /** ** Setup to begin parsing input shader **/ if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) { debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n"); return; } procType = parse.FullHeader.Processor.Processor; assert(procType == PIPE_SHADER_FRAGMENT || procType == PIPE_SHADER_VERTEX || procType == PIPE_SHADER_GEOMETRY || procType == PIPE_SHADER_TESS_CTRL || procType == PIPE_SHADER_TESS_EVAL || procType == PIPE_SHADER_COMPUTE); info->processor = procType; /** ** Loop over incoming program tokens/instructions */ while (!tgsi_parse_end_of_tokens(&parse)) { info->num_tokens++; tgsi_parse_token( &parse ); switch( parse.FullToken.Token.Type ) { case TGSI_TOKEN_TYPE_INSTRUCTION: scan_instruction(info, &parse.FullToken.FullInstruction, ¤t_depth); break; case TGSI_TOKEN_TYPE_DECLARATION: scan_declaration(info, &parse.FullToken.FullDeclaration); break; case TGSI_TOKEN_TYPE_IMMEDIATE: scan_immediate(info); break; case TGSI_TOKEN_TYPE_PROPERTY: scan_property(info, &parse.FullToken.FullProperty); break; default: assert(!"Unexpected TGSI token type"); } } info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] || info->opcode_count[TGSI_OPCODE_KILL]); /* The dimensions of the IN decleration in geometry shader have * to be deduced from the type of the input primitive. */ if (procType == PIPE_SHADER_GEOMETRY) { unsigned input_primitive = info->properties[TGSI_PROPERTY_GS_INPUT_PRIM]; int num_verts = u_vertices_per_prim(input_primitive); int j; info->file_count[TGSI_FILE_INPUT] = num_verts; info->file_max[TGSI_FILE_INPUT] = MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1); for (j = 0; j < num_verts; ++j) { info->file_mask[TGSI_FILE_INPUT] |= (1 << j); } } tgsi_parse_free(&parse); }
/** * Scan the given TGSI shader to collect information such as number of * registers used, special instructions used, etc. * \return info the result of the scan */ void tgsi_scan_shader(const struct tgsi_token *tokens, struct tgsi_shader_info *info) { uint procType, i; struct tgsi_parse_context parse; memset(info, 0, sizeof(*info)); for (i = 0; i < TGSI_FILE_COUNT; i++) info->file_max[i] = -1; for (i = 0; i < Elements(info->const_file_max); i++) info->const_file_max[i] = -1; /** ** Setup to begin parsing input shader **/ if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) { debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n"); return; } procType = parse.FullHeader.Processor.Processor; assert(procType == TGSI_PROCESSOR_FRAGMENT || procType == TGSI_PROCESSOR_VERTEX || procType == TGSI_PROCESSOR_GEOMETRY || procType == TGSI_PROCESSOR_COMPUTE); info->processor = procType; /** ** Loop over incoming program tokens/instructions */ while( !tgsi_parse_end_of_tokens( &parse ) ) { info->num_tokens++; tgsi_parse_token( &parse ); switch( parse.FullToken.Token.Type ) { case TGSI_TOKEN_TYPE_INSTRUCTION: { const struct tgsi_full_instruction *fullinst = &parse.FullToken.FullInstruction; uint i; assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST); info->opcode_count[fullinst->Instruction.Opcode]++; for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) { const struct tgsi_full_src_register *src = &fullinst->Src[i]; int ind = src->Register.Index; /* Mark which inputs are effectively used */ if (src->Register.File == TGSI_FILE_INPUT) { unsigned usage_mask; usage_mask = tgsi_util_get_inst_usage_mask(fullinst, i); if (src->Register.Indirect) { for (ind = 0; ind < info->num_inputs; ++ind) { info->input_usage_mask[ind] |= usage_mask; } } else { assert(ind >= 0); assert(ind < PIPE_MAX_SHADER_INPUTS); info->input_usage_mask[ind] |= usage_mask; } if (procType == TGSI_PROCESSOR_FRAGMENT && info->reads_position && src->Register.Index == 0 && (src->Register.SwizzleX == TGSI_SWIZZLE_Z || src->Register.SwizzleY == TGSI_SWIZZLE_Z || src->Register.SwizzleZ == TGSI_SWIZZLE_Z || src->Register.SwizzleW == TGSI_SWIZZLE_Z)) { info->reads_z = TRUE; } } /* check for indirect register reads */ if (src->Register.Indirect) { info->indirect_files |= (1 << src->Register.File); } /* MSAA samplers */ if (src->Register.File == TGSI_FILE_SAMPLER) { assert(fullinst->Instruction.Texture); assert(src->Register.Index < Elements(info->is_msaa_sampler)); if (fullinst->Instruction.Texture && (fullinst->Texture.Texture == TGSI_TEXTURE_2D_MSAA || fullinst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA)) { info->is_msaa_sampler[src->Register.Index] = TRUE; } } } /* check for indirect register writes */ for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) { const struct tgsi_full_dst_register *dst = &fullinst->Dst[i]; if (dst->Register.Indirect) { info->indirect_files |= (1 << dst->Register.File); } } info->num_instructions++; } break; case TGSI_TOKEN_TYPE_DECLARATION: { const struct tgsi_full_declaration *fulldecl = &parse.FullToken.FullDeclaration; const uint file = fulldecl->Declaration.File; uint reg; for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) { unsigned semName = fulldecl->Semantic.Name; unsigned semIndex = fulldecl->Semantic.Index; /* only first 32 regs will appear in this bitfield */ info->file_mask[file] |= (1 << reg); info->file_count[file]++; info->file_max[file] = MAX2(info->file_max[file], (int)reg); if (file == TGSI_FILE_CONSTANT) { int buffer = 0; if (fulldecl->Declaration.Dimension) buffer = fulldecl->Dim.Index2D; info->const_file_max[buffer] = MAX2(info->const_file_max[buffer], (int)reg); } else if (file == TGSI_FILE_INPUT) { info->input_semantic_name[reg] = (ubyte) semName; info->input_semantic_index[reg] = (ubyte) semIndex; info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate; info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location; info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap; info->num_inputs++; if (semName == TGSI_SEMANTIC_PRIMID) info->uses_primid = TRUE; else if (procType == TGSI_PROCESSOR_FRAGMENT) { if (semName == TGSI_SEMANTIC_POSITION) info->reads_position = TRUE; else if (semName == TGSI_SEMANTIC_FACE) info->uses_frontface = TRUE; } } else if (file == TGSI_FILE_SYSTEM_VALUE) { unsigned index = fulldecl->Range.First; info->system_value_semantic_name[index] = semName; info->num_system_values = MAX2(info->num_system_values, index + 1); if (semName == TGSI_SEMANTIC_INSTANCEID) { info->uses_instanceid = TRUE; } else if (semName == TGSI_SEMANTIC_VERTEXID) { info->uses_vertexid = TRUE; } else if (semName == TGSI_SEMANTIC_PRIMID) { info->uses_primid = TRUE; } } else if (file == TGSI_FILE_OUTPUT) { info->output_semantic_name[reg] = (ubyte) semName; info->output_semantic_index[reg] = (ubyte) semIndex; info->num_outputs++; if (procType == TGSI_PROCESSOR_VERTEX || procType == TGSI_PROCESSOR_GEOMETRY) { if (semName == TGSI_SEMANTIC_CLIPDIST) { info->num_written_clipdistance += util_bitcount(fulldecl->Declaration.UsageMask); } else if (semName == TGSI_SEMANTIC_CULLDIST) { info->num_written_culldistance += util_bitcount(fulldecl->Declaration.UsageMask); } } if (procType == TGSI_PROCESSOR_FRAGMENT) { if (semName == TGSI_SEMANTIC_POSITION) { info->writes_z = TRUE; } else if (semName == TGSI_SEMANTIC_STENCIL) { info->writes_stencil = TRUE; } } if (procType == TGSI_PROCESSOR_VERTEX) { if (semName == TGSI_SEMANTIC_EDGEFLAG) { info->writes_edgeflag = TRUE; } } if (procType == TGSI_PROCESSOR_GEOMETRY) { if (semName == TGSI_SEMANTIC_VIEWPORT_INDEX) { info->writes_viewport_index = TRUE; } else if (semName == TGSI_SEMANTIC_LAYER) { info->writes_layer = TRUE; } } } } } break; case TGSI_TOKEN_TYPE_IMMEDIATE: { uint reg = info->immediate_count++; uint file = TGSI_FILE_IMMEDIATE; info->file_mask[file] |= (1 << reg); info->file_count[file]++; info->file_max[file] = MAX2(info->file_max[file], (int)reg); } break; case TGSI_TOKEN_TYPE_PROPERTY: { const struct tgsi_full_property *fullprop = &parse.FullToken.FullProperty; unsigned name = fullprop->Property.PropertyName; assert(name < Elements(info->properties)); info->properties[name] = fullprop->u[0].Data; } break; default: assert( 0 ); } } info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] || info->opcode_count[TGSI_OPCODE_KILL]); /* The dimensions of the IN decleration in geometry shader have * to be deduced from the type of the input primitive. */ if (procType == TGSI_PROCESSOR_GEOMETRY) { unsigned input_primitive = info->properties[TGSI_PROPERTY_GS_INPUT_PRIM]; int num_verts = u_vertices_per_prim(input_primitive); int j; info->file_count[TGSI_FILE_INPUT] = num_verts; info->file_max[TGSI_FILE_INPUT] = MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1); for (j = 0; j < num_verts; ++j) { info->file_mask[TGSI_FILE_INPUT] |= (1 << j); } } tgsi_parse_free (&parse); }
/** * Scan the given TGSI shader to collect information such as number of * registers used, special instructions used, etc. * \return info the result of the scan */ void tgsi_scan_shader(const struct tgsi_token *tokens, struct tgsi_shader_info *info) { uint procType, i; struct tgsi_parse_context parse; unsigned current_depth = 0; memset(info, 0, sizeof(*info)); for (i = 0; i < TGSI_FILE_COUNT; i++) info->file_max[i] = -1; for (i = 0; i < Elements(info->const_file_max); i++) info->const_file_max[i] = -1; info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1; /** ** Setup to begin parsing input shader **/ if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) { debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n"); return; } procType = parse.FullHeader.Processor.Processor; assert(procType == TGSI_PROCESSOR_FRAGMENT || procType == TGSI_PROCESSOR_VERTEX || procType == TGSI_PROCESSOR_GEOMETRY || procType == TGSI_PROCESSOR_TESS_CTRL || procType == TGSI_PROCESSOR_TESS_EVAL || procType == TGSI_PROCESSOR_COMPUTE); info->processor = procType; /** ** Loop over incoming program tokens/instructions */ while( !tgsi_parse_end_of_tokens( &parse ) ) { info->num_tokens++; tgsi_parse_token( &parse ); switch( parse.FullToken.Token.Type ) { case TGSI_TOKEN_TYPE_INSTRUCTION: { const struct tgsi_full_instruction *fullinst = &parse.FullToken.FullInstruction; uint i; assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST); info->opcode_count[fullinst->Instruction.Opcode]++; switch (fullinst->Instruction.Opcode) { case TGSI_OPCODE_IF: case TGSI_OPCODE_UIF: case TGSI_OPCODE_BGNLOOP: current_depth++; info->max_depth = MAX2(info->max_depth, current_depth); break; case TGSI_OPCODE_ENDIF: case TGSI_OPCODE_ENDLOOP: current_depth--; break; default: break; } if (fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_CENTROID || fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET || fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) { const struct tgsi_full_src_register *src0 = &fullinst->Src[0]; unsigned input; if (src0->Register.Indirect && src0->Indirect.ArrayID) input = info->input_array_first[src0->Indirect.ArrayID]; else input = src0->Register.Index; /* For the INTERP opcodes, the interpolation is always * PERSPECTIVE unless LINEAR is specified. */ switch (info->input_interpolate[input]) { case TGSI_INTERPOLATE_COLOR: case TGSI_INTERPOLATE_CONSTANT: case TGSI_INTERPOLATE_PERSPECTIVE: switch (fullinst->Instruction.Opcode) { case TGSI_OPCODE_INTERP_CENTROID: info->uses_persp_opcode_interp_centroid = true; break; case TGSI_OPCODE_INTERP_OFFSET: info->uses_persp_opcode_interp_offset = true; break; case TGSI_OPCODE_INTERP_SAMPLE: info->uses_persp_opcode_interp_sample = true; break; } break; case TGSI_INTERPOLATE_LINEAR: switch (fullinst->Instruction.Opcode) { case TGSI_OPCODE_INTERP_CENTROID: info->uses_linear_opcode_interp_centroid = true; break; case TGSI_OPCODE_INTERP_OFFSET: info->uses_linear_opcode_interp_offset = true; break; case TGSI_OPCODE_INTERP_SAMPLE: info->uses_linear_opcode_interp_sample = true; break; } break; } } if (fullinst->Instruction.Opcode >= TGSI_OPCODE_F2D && fullinst->Instruction.Opcode <= TGSI_OPCODE_DSSG) info->uses_doubles = true; for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) { const struct tgsi_full_src_register *src = &fullinst->Src[i]; int ind = src->Register.Index; /* Mark which inputs are effectively used */ if (src->Register.File == TGSI_FILE_INPUT) { unsigned usage_mask; usage_mask = tgsi_util_get_inst_usage_mask(fullinst, i); if (src->Register.Indirect) { for (ind = 0; ind < info->num_inputs; ++ind) { info->input_usage_mask[ind] |= usage_mask; } } else { assert(ind >= 0); assert(ind < PIPE_MAX_SHADER_INPUTS); info->input_usage_mask[ind] |= usage_mask; } if (procType == TGSI_PROCESSOR_FRAGMENT && !src->Register.Indirect) { unsigned name = info->input_semantic_name[src->Register.Index]; unsigned index = info->input_semantic_index[src->Register.Index]; if (name == TGSI_SEMANTIC_POSITION && (src->Register.SwizzleX == TGSI_SWIZZLE_Z || src->Register.SwizzleY == TGSI_SWIZZLE_Z || src->Register.SwizzleZ == TGSI_SWIZZLE_Z || src->Register.SwizzleW == TGSI_SWIZZLE_Z)) info->reads_z = TRUE; if (name == TGSI_SEMANTIC_COLOR) { unsigned mask = (1 << src->Register.SwizzleX) | (1 << src->Register.SwizzleY) | (1 << src->Register.SwizzleZ) | (1 << src->Register.SwizzleW); info->colors_read |= mask << (index * 4); } } } /* check for indirect register reads */ if (src->Register.Indirect) { info->indirect_files |= (1 << src->Register.File); info->indirect_files_read |= (1 << src->Register.File); } /* MSAA samplers */ if (src->Register.File == TGSI_FILE_SAMPLER) { assert(fullinst->Instruction.Texture); assert(src->Register.Index < Elements(info->is_msaa_sampler)); if (fullinst->Instruction.Texture && (fullinst->Texture.Texture == TGSI_TEXTURE_2D_MSAA || fullinst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA)) { info->is_msaa_sampler[src->Register.Index] = TRUE; } } } /* check for indirect register writes */ for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) { const struct tgsi_full_dst_register *dst = &fullinst->Dst[i]; if (dst->Register.Indirect) { info->indirect_files |= (1 << dst->Register.File); info->indirect_files_written |= (1 << dst->Register.File); } } info->num_instructions++; } break; case TGSI_TOKEN_TYPE_DECLARATION: { const struct tgsi_full_declaration *fulldecl = &parse.FullToken.FullDeclaration; const uint file = fulldecl->Declaration.File; uint reg; if (fulldecl->Declaration.Array) { unsigned array_id = fulldecl->Array.ArrayID; switch (file) { case TGSI_FILE_INPUT: assert(array_id < ARRAY_SIZE(info->input_array_first)); info->input_array_first[array_id] = fulldecl->Range.First; info->input_array_last[array_id] = fulldecl->Range.Last; break; case TGSI_FILE_OUTPUT: assert(array_id < ARRAY_SIZE(info->output_array_first)); info->output_array_first[array_id] = fulldecl->Range.First; info->output_array_last[array_id] = fulldecl->Range.Last; break; } info->array_max[file] = MAX2(info->array_max[file], array_id); } for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) { unsigned semName = fulldecl->Semantic.Name; unsigned semIndex = fulldecl->Semantic.Index + (reg - fulldecl->Range.First); /* only first 32 regs will appear in this bitfield */ info->file_mask[file] |= (1 << reg); info->file_count[file]++; info->file_max[file] = MAX2(info->file_max[file], (int)reg); if (file == TGSI_FILE_CONSTANT) { int buffer = 0; if (fulldecl->Declaration.Dimension) buffer = fulldecl->Dim.Index2D; info->const_file_max[buffer] = MAX2(info->const_file_max[buffer], (int)reg); } else if (file == TGSI_FILE_INPUT) { info->input_semantic_name[reg] = (ubyte) semName; info->input_semantic_index[reg] = (ubyte) semIndex; info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate; info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location; info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap; info->num_inputs++; /* Only interpolated varyings. Don't include POSITION. * Don't include integer varyings, because they are not * interpolated. */ if (semName == TGSI_SEMANTIC_GENERIC || semName == TGSI_SEMANTIC_TEXCOORD || semName == TGSI_SEMANTIC_COLOR || semName == TGSI_SEMANTIC_BCOLOR || semName == TGSI_SEMANTIC_FOG || semName == TGSI_SEMANTIC_CLIPDIST || semName == TGSI_SEMANTIC_CULLDIST) { switch (fulldecl->Interp.Interpolate) { case TGSI_INTERPOLATE_COLOR: case TGSI_INTERPOLATE_PERSPECTIVE: switch (fulldecl->Interp.Location) { case TGSI_INTERPOLATE_LOC_CENTER: info->uses_persp_center = true; break; case TGSI_INTERPOLATE_LOC_CENTROID: info->uses_persp_centroid = true; break; case TGSI_INTERPOLATE_LOC_SAMPLE: info->uses_persp_sample = true; break; } break; case TGSI_INTERPOLATE_LINEAR: switch (fulldecl->Interp.Location) { case TGSI_INTERPOLATE_LOC_CENTER: info->uses_linear_center = true; break; case TGSI_INTERPOLATE_LOC_CENTROID: info->uses_linear_centroid = true; break; case TGSI_INTERPOLATE_LOC_SAMPLE: info->uses_linear_sample = true; break; } break; /* TGSI_INTERPOLATE_CONSTANT doesn't do any interpolation. */ } } if (semName == TGSI_SEMANTIC_PRIMID) info->uses_primid = TRUE; else if (procType == TGSI_PROCESSOR_FRAGMENT) { if (semName == TGSI_SEMANTIC_POSITION) info->reads_position = TRUE; else if (semName == TGSI_SEMANTIC_FACE) info->uses_frontface = TRUE; } } else if (file == TGSI_FILE_SYSTEM_VALUE) { unsigned index = fulldecl->Range.First; info->system_value_semantic_name[index] = semName; info->num_system_values = MAX2(info->num_system_values, index + 1); if (semName == TGSI_SEMANTIC_INSTANCEID) { info->uses_instanceid = TRUE; } else if (semName == TGSI_SEMANTIC_VERTEXID) { info->uses_vertexid = TRUE; } else if (semName == TGSI_SEMANTIC_VERTEXID_NOBASE) { info->uses_vertexid_nobase = TRUE; } else if (semName == TGSI_SEMANTIC_BASEVERTEX) { info->uses_basevertex = TRUE; } else if (semName == TGSI_SEMANTIC_PRIMID) { info->uses_primid = TRUE; } else if (semName == TGSI_SEMANTIC_INVOCATIONID) { info->uses_invocationid = TRUE; } } else if (file == TGSI_FILE_OUTPUT) { info->output_semantic_name[reg] = (ubyte) semName; info->output_semantic_index[reg] = (ubyte) semIndex; info->num_outputs++; if (semName == TGSI_SEMANTIC_COLOR) info->colors_written |= 1 << semIndex; if (procType == TGSI_PROCESSOR_VERTEX || procType == TGSI_PROCESSOR_GEOMETRY || procType == TGSI_PROCESSOR_TESS_CTRL || procType == TGSI_PROCESSOR_TESS_EVAL) { if (semName == TGSI_SEMANTIC_VIEWPORT_INDEX) { info->writes_viewport_index = TRUE; } else if (semName == TGSI_SEMANTIC_LAYER) { info->writes_layer = TRUE; } else if (semName == TGSI_SEMANTIC_PSIZE) { info->writes_psize = TRUE; } else if (semName == TGSI_SEMANTIC_CLIPVERTEX) { info->writes_clipvertex = TRUE; } } if (procType == TGSI_PROCESSOR_FRAGMENT) { if (semName == TGSI_SEMANTIC_POSITION) { info->writes_z = TRUE; } else if (semName == TGSI_SEMANTIC_STENCIL) { info->writes_stencil = TRUE; } else if (semName == TGSI_SEMANTIC_SAMPLEMASK) { info->writes_samplemask = TRUE; } } if (procType == TGSI_PROCESSOR_VERTEX) { if (semName == TGSI_SEMANTIC_EDGEFLAG) { info->writes_edgeflag = TRUE; } } } else if (file == TGSI_FILE_SAMPLER) { info->samplers_declared |= 1 << reg; } } } break; case TGSI_TOKEN_TYPE_IMMEDIATE: { uint reg = info->immediate_count++; uint file = TGSI_FILE_IMMEDIATE; info->file_mask[file] |= (1 << reg); info->file_count[file]++; info->file_max[file] = MAX2(info->file_max[file], (int)reg); } break; case TGSI_TOKEN_TYPE_PROPERTY: { const struct tgsi_full_property *fullprop = &parse.FullToken.FullProperty; unsigned name = fullprop->Property.PropertyName; unsigned value = fullprop->u[0].Data; assert(name < Elements(info->properties)); info->properties[name] = value; switch (name) { case TGSI_PROPERTY_NUM_CLIPDIST_ENABLED: info->num_written_clipdistance = value; info->clipdist_writemask |= (1 << value) - 1; break; case TGSI_PROPERTY_NUM_CULLDIST_ENABLED: info->num_written_culldistance = value; info->culldist_writemask |= (1 << value) - 1; break; } } break; default: assert( 0 ); } } info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] || info->opcode_count[TGSI_OPCODE_KILL]); /* The dimensions of the IN decleration in geometry shader have * to be deduced from the type of the input primitive. */ if (procType == TGSI_PROCESSOR_GEOMETRY) { unsigned input_primitive = info->properties[TGSI_PROPERTY_GS_INPUT_PRIM]; int num_verts = u_vertices_per_prim(input_primitive); int j; info->file_count[TGSI_FILE_INPUT] = num_verts; info->file_max[TGSI_FILE_INPUT] = MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1); for (j = 0; j < num_verts; ++j) { info->file_mask[TGSI_FILE_INPUT] |= (1 << j); } } tgsi_parse_free (&parse); }
/** * Apply user-defined transformations to the input shader to produce * the output shader. * For example, a register search-and-replace operation could be applied * by defining a transform_instruction() callback that examined and changed * the instruction src/dest regs. * * \return number of tokens emitted */ int tgsi_transform_shader(const struct tgsi_token *tokens_in, struct tgsi_token *tokens_out, uint max_tokens_out, struct tgsi_transform_context *ctx) { uint procType; /* input shader */ struct tgsi_parse_context parse; /* output shader */ struct tgsi_processor *processor; /** ** callback context init **/ ctx->emit_instruction = emit_instruction; ctx->emit_declaration = emit_declaration; ctx->emit_immediate = emit_immediate; ctx->tokens_out = tokens_out; ctx->max_tokens_out = max_tokens_out; /** ** Setup to begin parsing input shader **/ if (tgsi_parse_init( &parse, tokens_in ) != TGSI_PARSE_OK) { debug_printf("tgsi_parse_init() failed in tgsi_transform_shader()!\n"); return -1; } procType = parse.FullHeader.Processor.Processor; assert(procType == TGSI_PROCESSOR_FRAGMENT || procType == TGSI_PROCESSOR_VERTEX || procType == TGSI_PROCESSOR_GEOMETRY); /** ** Setup output shader **/ *(struct tgsi_version *) &tokens_out[0] = tgsi_build_version(); ctx->header = (struct tgsi_header *) (tokens_out + 1); *ctx->header = tgsi_build_header(); processor = (struct tgsi_processor *) (tokens_out + 2); *processor = tgsi_build_processor( procType, ctx->header ); ctx->ti = 3; /** ** Loop over incoming program tokens/instructions */ while( !tgsi_parse_end_of_tokens( &parse ) ) { tgsi_parse_token( &parse ); switch( parse.FullToken.Token.Type ) { case TGSI_TOKEN_TYPE_INSTRUCTION: { struct tgsi_full_instruction *fullinst = &parse.FullToken.FullInstruction; if (ctx->transform_instruction) ctx->transform_instruction(ctx, fullinst); else ctx->emit_instruction(ctx, fullinst); } break; case TGSI_TOKEN_TYPE_DECLARATION: { struct tgsi_full_declaration *fulldecl = &parse.FullToken.FullDeclaration; if (ctx->transform_declaration) ctx->transform_declaration(ctx, fulldecl); else ctx->emit_declaration(ctx, fulldecl); } break; case TGSI_TOKEN_TYPE_IMMEDIATE: { struct tgsi_full_immediate *fullimm = &parse.FullToken.FullImmediate; if (ctx->transform_immediate) ctx->transform_immediate(ctx, fullimm); else ctx->emit_immediate(ctx, fullimm); } break; default: assert( 0 ); } } if (ctx->epilog) { ctx->epilog(ctx); } tgsi_parse_free (&parse); return ctx->ti; }
static void nv30_vertprog_translate(struct nv30_context *nv30, struct nv30_vertex_program *vp) { struct tgsi_parse_context parse; struct nv30_vpc *vpc = NULL; tgsi_dump(vp->pipe.tokens,0); vpc = CALLOC(1, sizeof(struct nv30_vpc)); if (!vpc) return; vpc->vp = vp; vpc->high_temp = -1; if (!nv30_vertprog_prepare(vpc)) { FREE(vpc); return; } tgsi_parse_init(&parse, vp->pipe.tokens); while (!tgsi_parse_end_of_tokens(&parse)) { tgsi_parse_token(&parse); switch (parse.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_DECLARATION: { const struct tgsi_full_declaration *fdec; fdec = &parse.FullToken.FullDeclaration; switch (fdec->Declaration.File) { case TGSI_FILE_OUTPUT: if (!nv30_vertprog_parse_decl_output(vpc, fdec)) goto out_err; break; default: break; } } break; case TGSI_TOKEN_TYPE_IMMEDIATE: { const struct tgsi_full_immediate *imm; imm = &parse.FullToken.FullImmediate; assert(imm->Immediate.DataType == TGSI_IMM_FLOAT32); assert(imm->Immediate.NrTokens == 4 + 1); vpc->imm[vpc->nr_imm++] = constant(vpc, -1, imm->u[0].Float, imm->u[1].Float, imm->u[2].Float, imm->u[3].Float); } break; case TGSI_TOKEN_TYPE_INSTRUCTION: { const struct tgsi_full_instruction *finst; finst = &parse.FullToken.FullInstruction; if (!nv30_vertprog_parse_instruction(vpc, finst)) goto out_err; } break; default: break; } } vp->insns[vp->nr_insns - 1].data[3] |= NV30_VP_INST_LAST; vp->translated = TRUE; out_err: tgsi_parse_free(&parse); FREE(vpc); }
static unsigned compile_init(struct fd2_compile_context *ctx, struct fd_program_stateobj *prog, struct fd2_shader_stateobj *so) { unsigned ret; ctx->prog = prog; ctx->so = so; ctx->cf = NULL; ctx->pred_depth = 0; ret = tgsi_parse_init(&ctx->parser, so->tokens); if (ret != TGSI_PARSE_OK) return ret; ctx->type = ctx->parser.FullHeader.Processor.Processor; ctx->position = ~0; ctx->psize = ~0; ctx->num_position = 0; ctx->num_param = 0; ctx->need_sync = 0; ctx->immediate_idx = 0; ctx->pred_reg = -1; ctx->num_internal_temps = 0; memset(ctx->num_regs, 0, sizeof(ctx->num_regs)); memset(ctx->input_export_idx, 0, sizeof(ctx->input_export_idx)); memset(ctx->output_export_idx, 0, sizeof(ctx->output_export_idx)); /* do first pass to extract declarations: */ while (!tgsi_parse_end_of_tokens(&ctx->parser)) { tgsi_parse_token(&ctx->parser); switch (ctx->parser.FullToken.Token.Type) { case TGSI_TOKEN_TYPE_DECLARATION: { struct tgsi_full_declaration *decl = &ctx->parser.FullToken.FullDeclaration; if (decl->Declaration.File == TGSI_FILE_OUTPUT) { unsigned name = decl->Semantic.Name; assert(decl->Declaration.Semantic); // TODO is this ever not true? ctx->output_export_idx[decl->Range.First] = semantic_idx(&decl->Semantic); if (ctx->type == PIPE_SHADER_VERTEX) { switch (name) { case TGSI_SEMANTIC_POSITION: ctx->position = ctx->num_regs[TGSI_FILE_OUTPUT]; ctx->num_position++; break; case TGSI_SEMANTIC_PSIZE: ctx->psize = ctx->num_regs[TGSI_FILE_OUTPUT]; ctx->num_position++; break; case TGSI_SEMANTIC_COLOR: case TGSI_SEMANTIC_GENERIC: ctx->num_param++; break; default: DBG("unknown VS semantic name: %s", tgsi_semantic_names[name]); assert(0); } } else { switch (name) { case TGSI_SEMANTIC_COLOR: case TGSI_SEMANTIC_GENERIC: ctx->num_param++; break; default: DBG("unknown PS semantic name: %s", tgsi_semantic_names[name]); assert(0); } } } else if (decl->Declaration.File == TGSI_FILE_INPUT) { ctx->input_export_idx[decl->Range.First] = semantic_idx(&decl->Semantic); } ctx->num_regs[decl->Declaration.File] = MAX2(ctx->num_regs[decl->Declaration.File], decl->Range.Last + 1); break; } case TGSI_TOKEN_TYPE_IMMEDIATE: { struct tgsi_full_immediate *imm = &ctx->parser.FullToken.FullImmediate; unsigned n = ctx->so->num_immediates++; memcpy(ctx->so->immediates[n].val, imm->u, 16); break; } default: break; } } /* TGSI generated immediates are always entire vec4's, ones we * generate internally are not: */ ctx->immediate_idx = ctx->so->num_immediates * 4; ctx->so->first_immediate = ctx->num_regs[TGSI_FILE_CONSTANT]; tgsi_parse_free(&ctx->parser); return tgsi_parse_init(&ctx->parser, so->tokens); }
static void compile_free(struct fd2_compile_context *ctx) { tgsi_parse_free(&ctx->parser); }
unsigned util_semantic_set_from_program_file(struct util_semantic_set *set, const struct tgsi_token *tokens, enum tgsi_file_type file) { struct tgsi_shader_info info; struct tgsi_parse_context parse; unsigned count = 0; ubyte *semantic_name; ubyte *semantic_index; tgsi_scan_shader(tokens, &info); if(file == TGSI_FILE_INPUT) { semantic_name = info.input_semantic_name; semantic_index = info.input_semantic_index; } else if(file == TGSI_FILE_OUTPUT) { semantic_name = info.output_semantic_name; semantic_index = info.output_semantic_index; } else { assert(0); semantic_name = NULL; semantic_index = NULL; } tgsi_parse_init(&parse, tokens); memset(set->masks, 0, sizeof(set->masks)); while(!tgsi_parse_end_of_tokens(&parse)) { tgsi_parse_token(&parse); if(parse.FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION) { const struct tgsi_full_instruction *finst = &parse.FullToken.FullInstruction; unsigned i; for(i = 0; i < finst->Instruction.NumDstRegs; ++i) { if(finst->Dst[i].Register.File == file) { unsigned idx = finst->Dst[i].Register.Index; if(semantic_name[idx] == TGSI_SEMANTIC_GENERIC) { if(!util_semantic_set_test_and_set(set, semantic_index[idx])) ++count; } } } for(i = 0; i < finst->Instruction.NumSrcRegs; ++i) { if(finst->Src[i].Register.File == file) { unsigned idx = finst->Src[i].Register.Index; if(semantic_name[idx] == TGSI_SEMANTIC_GENERIC) { if(!util_semantic_set_test_and_set(set, semantic_index[idx])) ++count; } } } } } tgsi_parse_free(&parse); return count; }