/* Parse shader header. * Return TRUE for one of the following headers. * FRAG * GEOM * VERT */ static boolean parse_header( struct translate_ctx *ctx ) { uint processor; if (str_match_nocase_whole( &ctx->cur, "FRAG" )) processor = TGSI_PROCESSOR_FRAGMENT; else if (str_match_nocase_whole( &ctx->cur, "VERT" )) processor = TGSI_PROCESSOR_VERTEX; else if (str_match_nocase_whole( &ctx->cur, "GEOM" )) processor = TGSI_PROCESSOR_GEOMETRY; else if (str_match_nocase_whole( &ctx->cur, "COMP" )) processor = TGSI_PROCESSOR_COMPUTE; else { report_error( ctx, "Unknown header" ); return FALSE; } if (ctx->tokens_cur >= ctx->tokens_end) return FALSE; ctx->header = (struct tgsi_header *) ctx->tokens_cur++; *ctx->header = tgsi_build_header(); if (ctx->tokens_cur >= ctx->tokens_end) return FALSE; *(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header ); ctx->processor = processor; return TRUE; }
static boolean match_inst(const char **pcur, unsigned *saturate, const struct tgsi_opcode_info *info) { const char *cur = *pcur; /* simple case: the whole string matches the instruction name */ if (str_match_nocase_whole(&cur, info->mnemonic)) { *pcur = cur; *saturate = 0; return TRUE; } if (str_match_no_case(&cur, info->mnemonic)) { /* the instruction has a suffix, figure it out */ if (str_match_nocase_whole(&cur, "_SAT")) { *pcur = cur; *saturate = 1; return TRUE; } } return FALSE; }
static boolean match_inst(const char **pcur, unsigned *saturate, unsigned *precise, const struct tgsi_opcode_info *info) { const char *cur = *pcur; const char *mnemonic = tgsi_get_opcode_name(info->opcode); /* simple case: the whole string matches the instruction name */ if (str_match_nocase_whole(&cur, mnemonic)) { *pcur = cur; *saturate = 0; *precise = 0; return TRUE; } if (str_match_no_case(&cur, mnemonic)) { /* the instruction has a suffix, figure it out */ if (str_match_no_case(&cur, "_SAT")) { *pcur = cur; *saturate = 1; } if (str_match_no_case(&cur, "_PRECISE")) { *pcur = cur; *precise = 1; } if (!is_digit_alpha_underscore(cur)) return TRUE; } return FALSE; }
/* Return the array index that matches starting at *pcur, where the string at * *pcur is terminated by a non-digit non-letter non-underscore. * Returns -1 if no match is found. * * On success, the pointer to the first string is moved to the end of the read * word. */ static int str_match_name_from_array(const char **pcur, const char * const *array, unsigned array_size) { for (unsigned j = 0; j < array_size; ++j) { if (str_match_nocase_whole(pcur, array[j])) return j; } return -1; }
static boolean translate( struct translate_ctx *ctx ) { eat_opt_white( &ctx->cur ); if (!parse_header( ctx )) return FALSE; if (ctx->processor == TGSI_PROCESSOR_TESS_CTRL || ctx->processor == TGSI_PROCESSOR_TESS_EVAL) ctx->implied_array_size = 32; while (*ctx->cur != '\0') { uint label_val = 0; if (!eat_white( &ctx->cur )) { report_error( ctx, "Syntax error" ); return FALSE; } if (*ctx->cur == '\0') break; if (parse_label( ctx, &label_val )) { if (!parse_instruction( ctx, TRUE )) return FALSE; } else if (str_match_nocase_whole( &ctx->cur, "DCL" )) { if (!parse_declaration( ctx )) return FALSE; } else if (str_match_nocase_whole( &ctx->cur, "IMM" )) { if (!parse_immediate( ctx )) return FALSE; } else if (str_match_nocase_whole( &ctx->cur, "PROPERTY" )) { if (!parse_property( ctx )) return FALSE; } else if (!parse_instruction( ctx, FALSE )) { return FALSE; } } return TRUE; }
/* Return the format corresponding to the name at *pcur. * Returns -1 if there is no format name. * * On success, the pointer to the string is moved to the end of the read format * name. */ static int str_match_format(const char **pcur) { for (unsigned i = 0; i < PIPE_FORMAT_COUNT; i++) { const struct util_format_description *desc = util_format_description(i); if (desc && str_match_nocase_whole(pcur, desc->name)) { return i; } } return -1; }
static boolean parse_file( const char **pcur, uint *file ) { uint i; for (i = 0; i < TGSI_FILE_COUNT; i++) { const char *cur = *pcur; if (str_match_nocase_whole( &cur, tgsi_file_name(i) )) { *pcur = cur; *file = i; return TRUE; } } return FALSE; }
static boolean parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center ) { uint i; for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) { const char *cur = *pcur; if (str_match_nocase_whole( &cur, tgsi_fs_coord_pixel_center_names[i])) { *fs_coord_pixel_center = i; *pcur = cur; return TRUE; } } return FALSE; }
static boolean parse_primitive( const char **pcur, uint *primitive ) { uint i; for (i = 0; i < PIPE_PRIM_MAX; i++) { const char *cur = *pcur; if (str_match_nocase_whole( &cur, tgsi_primitive_names[i])) { *primitive = i; *pcur = cur; return TRUE; } } return FALSE; }
static boolean parse_property_next_shader( const char **pcur, uint *next_shader ) { uint i; for (i = 0; i < ARRAY_SIZE(tgsi_processor_type_names); i++) { const char *cur = *pcur; if (str_match_nocase_whole( &cur, tgsi_processor_type_names[i])) { *next_shader = i; *pcur = cur; return TRUE; } } return FALSE; }
static boolean parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin ) { uint i; for (i = 0; i < ARRAY_SIZE(tgsi_fs_coord_origin_names); i++) { const char *cur = *pcur; if (str_match_nocase_whole( &cur, tgsi_fs_coord_origin_names[i])) { *fs_coord_origin = i; *pcur = cur; return TRUE; } } return FALSE; }
static boolean parse_instruction( struct translate_ctx *ctx, boolean has_label ) { uint i; uint saturate = 0; const struct tgsi_opcode_info *info; struct tgsi_full_instruction inst; const char *cur; uint advance; inst = tgsi_default_full_instruction(); /* Parse predicate. */ eat_opt_white( &ctx->cur ); if (*ctx->cur == '(') { uint file; int index; uint swizzle[4]; boolean parsed_swizzle; inst.Instruction.Predicate = 1; ctx->cur++; if (*ctx->cur == '!') { ctx->cur++; inst.Predicate.Negate = 1; } if (!parse_register_1d( ctx, &file, &index )) return FALSE; if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle, 4 )) { if (parsed_swizzle) { inst.Predicate.SwizzleX = swizzle[0]; inst.Predicate.SwizzleY = swizzle[1]; inst.Predicate.SwizzleZ = swizzle[2]; inst.Predicate.SwizzleW = swizzle[3]; } } if (*ctx->cur != ')') { report_error( ctx, "Expected `)'" ); return FALSE; } ctx->cur++; } /* Parse instruction name. */ eat_opt_white( &ctx->cur ); for (i = 0; i < TGSI_OPCODE_LAST; i++) { cur = ctx->cur; info = tgsi_get_opcode_info( i ); if (match_inst(&cur, &saturate, info)) { if (info->num_dst + info->num_src + info->is_tex == 0) { ctx->cur = cur; break; } else if (*cur == '\0' || eat_white( &cur )) { ctx->cur = cur; break; } } } if (i == TGSI_OPCODE_LAST) { if (has_label) report_error( ctx, "Unknown opcode" ); else report_error( ctx, "Expected `DCL', `IMM' or a label" ); return FALSE; } inst.Instruction.Opcode = i; inst.Instruction.Saturate = saturate; inst.Instruction.NumDstRegs = info->num_dst; inst.Instruction.NumSrcRegs = info->num_src; if (i >= TGSI_OPCODE_SAMPLE && i <= TGSI_OPCODE_GATHER4) { /* * These are not considered tex opcodes here (no additional * target argument) however we're required to set the Texture * bit so we can set the number of tex offsets. */ inst.Instruction.Texture = 1; inst.Texture.Texture = TGSI_TEXTURE_UNKNOWN; } if ((i >= TGSI_OPCODE_LOAD && i <= TGSI_OPCODE_ATOMIMAX) || i == TGSI_OPCODE_RESQ) { inst.Instruction.Memory = 1; inst.Memory.Qualifier = 0; } /* Parse instruction operands. */ for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) { if (i > 0) { eat_opt_white( &ctx->cur ); if (*ctx->cur != ',') { report_error( ctx, "Expected `,'" ); return FALSE; } ctx->cur++; eat_opt_white( &ctx->cur ); } if (i < info->num_dst) { if (!parse_dst_operand( ctx, &inst.Dst[i] )) return FALSE; } else if (i < info->num_dst + info->num_src) { if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] )) return FALSE; } else { uint j; for (j = 0; j < TGSI_TEXTURE_COUNT; j++) { if (str_match_nocase_whole( &ctx->cur, tgsi_texture_names[j] )) { inst.Instruction.Texture = 1; inst.Texture.Texture = j; break; } } if (j == TGSI_TEXTURE_COUNT) { report_error( ctx, "Expected texture target" ); return FALSE; } } } cur = ctx->cur; eat_opt_white( &cur ); for (i = 0; inst.Instruction.Texture && *cur == ','; i++) { cur++; eat_opt_white( &cur ); ctx->cur = cur; if (!parse_texoffset_operand( ctx, &inst.TexOffsets[i] )) return FALSE; cur = ctx->cur; eat_opt_white( &cur ); } inst.Texture.NumOffsets = i; cur = ctx->cur; eat_opt_white(&cur); for (i = 0; inst.Instruction.Memory && *cur == ','; i++) { uint j; cur++; eat_opt_white(&cur); ctx->cur = cur; for (j = 0; j < 3; j++) { if (str_match_nocase_whole(&ctx->cur, tgsi_memory_names[j])) { inst.Memory.Qualifier |= 1U << j; break; } } if (j == 3) { report_error(ctx, "Expected memory qualifier"); return FALSE; } cur = ctx->cur; eat_opt_white(&cur); } cur = ctx->cur; eat_opt_white( &cur ); if (info->is_branch && *cur == ':') { uint target; cur++; eat_opt_white( &cur ); if (!parse_uint( &cur, &target )) { report_error( ctx, "Expected a label" ); return FALSE; } inst.Instruction.Label = 1; inst.Label.Label = target; ctx->cur = cur; } advance = tgsi_build_full_instruction( &inst, ctx->tokens_cur, ctx->header, (uint) (ctx->tokens_end - ctx->tokens_cur) ); if (advance == 0) return FALSE; ctx->tokens_cur += advance; return TRUE; }
static boolean parse_immediate( struct translate_ctx *ctx ) { struct tgsi_full_immediate imm; uint advance; int type; if (*ctx->cur == '[') { uint uindex; ++ctx->cur; eat_opt_white( &ctx->cur ); if (!parse_uint( &ctx->cur, &uindex )) { report_error( ctx, "Expected literal unsigned integer" ); return FALSE; } if (uindex != ctx->num_immediates) { report_error( ctx, "Immediates must be sorted" ); return FALSE; } eat_opt_white( &ctx->cur ); if (*ctx->cur != ']') { report_error( ctx, "Expected `]'" ); return FALSE; } ctx->cur++; } if (!eat_white( &ctx->cur )) { report_error( ctx, "Syntax error" ); return FALSE; } for (type = 0; type < Elements(tgsi_immediate_type_names); ++type) { if (str_match_nocase_whole(&ctx->cur, tgsi_immediate_type_names[type])) break; } if (type == Elements(tgsi_immediate_type_names)) { report_error( ctx, "Expected immediate type" ); return FALSE; } imm = tgsi_default_full_immediate(); imm.Immediate.NrTokens += 4; imm.Immediate.DataType = type; parse_immediate_data(ctx, type, imm.u); advance = tgsi_build_full_immediate( &imm, ctx->tokens_cur, ctx->header, (uint) (ctx->tokens_end - ctx->tokens_cur) ); if (advance == 0) return FALSE; ctx->tokens_cur += advance; ctx->num_immediates++; return TRUE; }
static boolean parse_declaration( struct translate_ctx *ctx ) { struct tgsi_full_declaration decl; uint file; struct parsed_dcl_bracket brackets[2]; int num_brackets; uint writemask; const char *cur, *cur2; uint advance; boolean is_vs_input; if (!eat_white( &ctx->cur )) { report_error( ctx, "Syntax error" ); return FALSE; } if (!parse_register_dcl( ctx, &file, brackets, &num_brackets)) return FALSE; if (!parse_opt_writemask( ctx, &writemask )) return FALSE; decl = tgsi_default_full_declaration(); decl.Declaration.File = file; decl.Declaration.UsageMask = writemask; if (num_brackets == 1) { decl.Range.First = brackets[0].first; decl.Range.Last = brackets[0].last; } else { decl.Range.First = brackets[1].first; decl.Range.Last = brackets[1].last; decl.Declaration.Dimension = 1; decl.Dim.Index2D = brackets[0].first; } is_vs_input = (file == TGSI_FILE_INPUT && ctx->processor == TGSI_PROCESSOR_VERTEX); cur = ctx->cur; eat_opt_white( &cur ); if (*cur == ',') { cur2 = cur; cur2++; eat_opt_white( &cur2 ); if (str_match_nocase_whole( &cur2, "ARRAY" )) { int arrayid; if (*cur2 != '(') { report_error( ctx, "Expected `('" ); return FALSE; } cur2++; eat_opt_white( &cur2 ); if (!parse_int( &cur2, &arrayid )) { report_error( ctx, "Expected `,'" ); return FALSE; } eat_opt_white( &cur2 ); if (*cur2 != ')') { report_error( ctx, "Expected `)'" ); return FALSE; } cur2++; decl.Declaration.Array = 1; decl.Array.ArrayID = arrayid; ctx->cur = cur = cur2; } } if (*cur == ',' && !is_vs_input) { uint i, j; cur++; eat_opt_white( &cur ); if (file == TGSI_FILE_IMAGE) { for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) { decl.Image.Resource = i; break; } } if (i == TGSI_TEXTURE_COUNT) { report_error(ctx, "Expected texture target"); return FALSE; } cur2 = cur; eat_opt_white(&cur2); while (*cur2 == ',') { cur2++; eat_opt_white(&cur2); if (str_match_nocase_whole(&cur2, "RAW")) { decl.Image.Raw = 1; } else if (str_match_nocase_whole(&cur2, "WR")) { decl.Image.Writable = 1; } else { for (i = 0; i < PIPE_FORMAT_COUNT; i++) { const struct util_format_description *desc = util_format_description(i); if (desc && str_match_nocase_whole(&cur2, desc->name)) { decl.Image.Format = i; break; } } if (i == PIPE_FORMAT_COUNT) break; } cur = cur2; eat_opt_white(&cur2); } ctx->cur = cur; } else if (file == TGSI_FILE_SAMPLER_VIEW) { for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) { decl.SamplerView.Resource = i; break; } } if (i == TGSI_TEXTURE_COUNT) { report_error(ctx, "Expected texture target"); return FALSE; } eat_opt_white( &cur ); if (*cur != ',') { report_error( ctx, "Expected `,'" ); return FALSE; } ++cur; eat_opt_white( &cur ); for (j = 0; j < 4; ++j) { for (i = 0; i < TGSI_RETURN_TYPE_COUNT; ++i) { if (str_match_nocase_whole(&cur, tgsi_return_type_names[i])) { switch (j) { case 0: decl.SamplerView.ReturnTypeX = i; break; case 1: decl.SamplerView.ReturnTypeY = i; break; case 2: decl.SamplerView.ReturnTypeZ = i; break; case 3: decl.SamplerView.ReturnTypeW = i; break; default: assert(0); } break; } } if (i == TGSI_RETURN_TYPE_COUNT) { if (j == 0 || j > 2) { report_error(ctx, "Expected type name"); return FALSE; } break; } else { cur2 = cur; eat_opt_white( &cur2 ); if (*cur2 == ',') { cur2++; eat_opt_white( &cur2 ); cur = cur2; continue; } else break; } } if (j < 4) { decl.SamplerView.ReturnTypeY = decl.SamplerView.ReturnTypeZ = decl.SamplerView.ReturnTypeW = decl.SamplerView.ReturnTypeX; } ctx->cur = cur; } else if (file == TGSI_FILE_BUFFER) { if (str_match_nocase_whole(&cur, "ATOMIC")) { decl.Declaration.Atomic = 1; ctx->cur = cur; } } else if (file == TGSI_FILE_MEMORY) { if (str_match_nocase_whole(&cur, "SHARED")) { decl.Declaration.Shared = 1; ctx->cur = cur; } } else { if (str_match_nocase_whole(&cur, "LOCAL")) { decl.Declaration.Local = 1; ctx->cur = cur; } cur = ctx->cur; eat_opt_white( &cur ); if (*cur == ',') { cur++; eat_opt_white( &cur ); for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) { if (str_match_nocase_whole(&cur, tgsi_semantic_names[i])) { uint index; cur2 = cur; eat_opt_white( &cur2 ); if (*cur2 == '[') { cur2++; eat_opt_white( &cur2 ); if (!parse_uint( &cur2, &index )) { report_error( ctx, "Expected literal integer" ); return FALSE; } eat_opt_white( &cur2 ); if (*cur2 != ']') { report_error( ctx, "Expected `]'" ); return FALSE; } cur2++; decl.Semantic.Index = index; cur = cur2; } decl.Declaration.Semantic = 1; decl.Semantic.Name = i; ctx->cur = cur; break; } } } } } cur = ctx->cur; eat_opt_white( &cur ); if (*cur == ',' && !is_vs_input) { uint i; cur++; eat_opt_white( &cur ); for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) { if (str_match_nocase_whole( &cur, tgsi_interpolate_names[i] )) { decl.Declaration.Interpolate = 1; decl.Interp.Interpolate = i; ctx->cur = cur; break; } } if (i == TGSI_INTERPOLATE_COUNT) { report_error( ctx, "Expected semantic or interpolate attribute" ); return FALSE; } } cur = ctx->cur; eat_opt_white( &cur ); if (*cur == ',' && !is_vs_input) { uint i; cur++; eat_opt_white( &cur ); for (i = 0; i < TGSI_INTERPOLATE_LOC_COUNT; i++) { if (str_match_nocase_whole( &cur, tgsi_interpolate_locations[i] )) { decl.Interp.Location = i; ctx->cur = cur; break; } } } advance = tgsi_build_full_declaration( &decl, ctx->tokens_cur, ctx->header, (uint) (ctx->tokens_end - ctx->tokens_cur) ); if (advance == 0) return FALSE; ctx->tokens_cur += advance; return TRUE; }
static boolean parse_instruction( struct translate_ctx *ctx, boolean has_label ) { uint i; uint saturate = 0; uint precise = 0; const struct tgsi_opcode_info *info; struct tgsi_full_instruction inst; const char *cur; uint advance; inst = tgsi_default_full_instruction(); /* Parse instruction name. */ eat_opt_white( &ctx->cur ); for (i = 0; i < TGSI_OPCODE_LAST; i++) { cur = ctx->cur; info = tgsi_get_opcode_info( i ); if (match_inst(&cur, &saturate, &precise, info)) { if (info->num_dst + info->num_src + info->is_tex == 0) { ctx->cur = cur; break; } else if (*cur == '\0' || eat_white( &cur )) { ctx->cur = cur; break; } } } if (i == TGSI_OPCODE_LAST) { if (has_label) report_error( ctx, "Unknown opcode" ); else report_error( ctx, "Expected `DCL', `IMM' or a label" ); return FALSE; } inst.Instruction.Opcode = i; inst.Instruction.Saturate = saturate; inst.Instruction.Precise = precise; inst.Instruction.NumDstRegs = info->num_dst; inst.Instruction.NumSrcRegs = info->num_src; if (i >= TGSI_OPCODE_SAMPLE && i <= TGSI_OPCODE_GATHER4) { /* * These are not considered tex opcodes here (no additional * target argument) however we're required to set the Texture * bit so we can set the number of tex offsets. */ inst.Instruction.Texture = 1; inst.Texture.Texture = TGSI_TEXTURE_UNKNOWN; } if ((i >= TGSI_OPCODE_LOAD && i <= TGSI_OPCODE_ATOMIMAX) || i == TGSI_OPCODE_RESQ) { inst.Instruction.Memory = 1; inst.Memory.Qualifier = 0; } assume(info->num_dst <= TGSI_FULL_MAX_DST_REGISTERS); assume(info->num_src <= TGSI_FULL_MAX_SRC_REGISTERS); /* Parse instruction operands. */ for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) { if (i > 0) { eat_opt_white( &ctx->cur ); if (*ctx->cur != ',') { report_error( ctx, "Expected `,'" ); return FALSE; } ctx->cur++; eat_opt_white( &ctx->cur ); } if (i < info->num_dst) { if (!parse_dst_operand( ctx, &inst.Dst[i] )) return FALSE; } else if (i < info->num_dst + info->num_src) { if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] )) return FALSE; } else { uint j; for (j = 0; j < TGSI_TEXTURE_COUNT; j++) { if (str_match_nocase_whole( &ctx->cur, tgsi_texture_names[j] )) { inst.Instruction.Texture = 1; inst.Texture.Texture = j; break; } } if (j == TGSI_TEXTURE_COUNT) { report_error( ctx, "Expected texture target" ); return FALSE; } } } cur = ctx->cur; eat_opt_white( &cur ); for (i = 0; inst.Instruction.Texture && *cur == ',' && i < TGSI_FULL_MAX_TEX_OFFSETS; i++) { cur++; eat_opt_white( &cur ); ctx->cur = cur; if (!parse_texoffset_operand( ctx, &inst.TexOffsets[i] )) return FALSE; cur = ctx->cur; eat_opt_white( &cur ); } inst.Texture.NumOffsets = i; cur = ctx->cur; eat_opt_white(&cur); for (; inst.Instruction.Memory && *cur == ','; ctx->cur = cur, eat_opt_white(&cur)) { int j; cur++; eat_opt_white(&cur); j = str_match_name_from_array(&cur, tgsi_memory_names, ARRAY_SIZE(tgsi_memory_names)); if (j >= 0) { inst.Memory.Qualifier |= 1U << j; continue; } j = str_match_name_from_array(&cur, tgsi_texture_names, ARRAY_SIZE(tgsi_texture_names)); if (j >= 0) { inst.Memory.Texture = j; continue; } j = str_match_format(&cur); if (j >= 0) { inst.Memory.Format = j; continue; } ctx->cur = cur; report_error(ctx, "Expected memory qualifier, texture target, or format\n"); return FALSE; } cur = ctx->cur; eat_opt_white( &cur ); if (info->is_branch && *cur == ':') { uint target; cur++; eat_opt_white( &cur ); if (!parse_uint( &cur, &target )) { report_error( ctx, "Expected a label" ); return FALSE; } inst.Instruction.Label = 1; inst.Label.Label = target; ctx->cur = cur; } advance = tgsi_build_full_instruction( &inst, ctx->tokens_cur, ctx->header, (uint) (ctx->tokens_end - ctx->tokens_cur) ); if (advance == 0) return FALSE; ctx->tokens_cur += advance; return TRUE; }
static boolean parse_declaration( struct translate_ctx *ctx ) { struct tgsi_full_declaration decl; uint file; struct parsed_dcl_bracket brackets[2]; int num_brackets; uint writemask; const char *cur, *cur2; uint advance; boolean is_vs_input; boolean is_imm_array; if (!eat_white( &ctx->cur )) { report_error( ctx, "Syntax error" ); return FALSE; } if (!parse_register_dcl( ctx, &file, brackets, &num_brackets)) return FALSE; if (!parse_opt_writemask( ctx, &writemask )) return FALSE; decl = tgsi_default_full_declaration(); decl.Declaration.File = file; decl.Declaration.UsageMask = writemask; if (num_brackets == 1) { decl.Range.First = brackets[0].first; decl.Range.Last = brackets[0].last; } else { decl.Range.First = brackets[1].first; decl.Range.Last = brackets[1].last; decl.Declaration.Dimension = 1; decl.Dim.Index2D = brackets[0].first; } is_vs_input = (file == TGSI_FILE_INPUT && ctx->processor == TGSI_PROCESSOR_VERTEX); is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY); cur = ctx->cur; eat_opt_white( &cur ); if (*cur == ',' && !is_vs_input) { uint i, j; cur++; eat_opt_white( &cur ); if (file == TGSI_FILE_RESOURCE) { for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) { decl.Resource.Resource = i; break; } } if (i == TGSI_TEXTURE_COUNT) { report_error(ctx, "Expected texture target"); return FALSE; } cur2 = cur; eat_opt_white(&cur2); while (*cur2 == ',') { cur2++; eat_opt_white(&cur2); if (str_match_nocase_whole(&cur2, "RAW")) { decl.Resource.Raw = 1; } else if (str_match_nocase_whole(&cur2, "WR")) { decl.Resource.Writable = 1; } else { break; } cur = cur2; eat_opt_white(&cur2); } ctx->cur = cur; } else if (file == TGSI_FILE_SAMPLER_VIEW) { for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) { decl.SamplerView.Resource = i; break; } } if (i == TGSI_TEXTURE_COUNT) { report_error(ctx, "Expected texture target"); return FALSE; } eat_opt_white( &cur ); if (*cur != ',') { report_error( ctx, "Expected `,'" ); return FALSE; } ++cur; eat_opt_white( &cur ); for (j = 0; j < 4; ++j) { for (i = 0; i < PIPE_TYPE_COUNT; ++i) { if (str_match_nocase_whole(&cur, tgsi_type_names[i])) { switch (j) { case 0: decl.SamplerView.ReturnTypeX = i; break; case 1: decl.SamplerView.ReturnTypeY = i; break; case 2: decl.SamplerView.ReturnTypeZ = i; break; case 3: decl.SamplerView.ReturnTypeW = i; break; default: assert(0); } break; } } if (i == PIPE_TYPE_COUNT) { if (j == 0 || j > 2) { report_error(ctx, "Expected type name"); return FALSE; } break; } else { cur2 = cur; eat_opt_white( &cur2 ); if (*cur2 == ',') { cur2++; eat_opt_white( &cur2 ); cur = cur2; continue; } else break; } } if (j < 4) { decl.SamplerView.ReturnTypeY = decl.SamplerView.ReturnTypeZ = decl.SamplerView.ReturnTypeW = decl.SamplerView.ReturnTypeX; } ctx->cur = cur; } else { if (str_match_nocase_whole(&cur, "LOCAL")) { decl.Declaration.Local = 1; ctx->cur = cur; } cur = ctx->cur; eat_opt_white( &cur ); if (*cur == ',') { cur++; eat_opt_white( &cur ); for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) { if (str_match_nocase_whole(&cur, tgsi_semantic_names[i])) { uint index; cur2 = cur; eat_opt_white( &cur2 ); if (*cur2 == '[') { cur2++; eat_opt_white( &cur2 ); if (!parse_uint( &cur2, &index )) { report_error( ctx, "Expected literal integer" ); return FALSE; } eat_opt_white( &cur2 ); if (*cur2 != ']') { report_error( ctx, "Expected `]'" ); return FALSE; } cur2++; decl.Semantic.Index = index; cur = cur2; } decl.Declaration.Semantic = 1; decl.Semantic.Name = i; ctx->cur = cur; break; } } } } } else if (is_imm_array) { unsigned i; union tgsi_immediate_data *vals_itr; /* we have our immediate data */ if (*cur != '{') { report_error( ctx, "Immediate array without data" ); return FALSE; } ++cur; ctx->cur = cur; decl.ImmediateData.u = MALLOC(sizeof(union tgsi_immediate_data) * 4 * (decl.Range.Last + 1)); vals_itr = decl.ImmediateData.u; for (i = 0; i <= decl.Range.Last; ++i) { if (!parse_immediate_data(ctx, TGSI_IMM_FLOAT32, vals_itr)) { FREE(decl.ImmediateData.u); return FALSE; } vals_itr += 4; eat_opt_white( &ctx->cur ); if (*ctx->cur != ',') { if (i != decl.Range.Last) { report_error( ctx, "Not enough data in immediate array!" ); FREE(decl.ImmediateData.u); return FALSE; } } else ++ctx->cur; } eat_opt_white( &ctx->cur ); if (*ctx->cur != '}') { FREE(decl.ImmediateData.u); report_error( ctx, "Immediate array data missing closing '}'" ); return FALSE; } ++ctx->cur; } cur = ctx->cur; eat_opt_white( &cur ); if (*cur == ',' && !is_vs_input) { uint i; cur++; eat_opt_white( &cur ); for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) { if (str_match_nocase_whole( &cur, tgsi_interpolate_names[i] )) { decl.Declaration.Interpolate = 1; decl.Interp.Interpolate = i; ctx->cur = cur; break; } } if (i == TGSI_INTERPOLATE_COUNT) { report_error( ctx, "Expected semantic or interpolate attribute" ); return FALSE; } } advance = tgsi_build_full_declaration( &decl, ctx->tokens_cur, ctx->header, (uint) (ctx->tokens_end - ctx->tokens_cur) ); if (is_imm_array) FREE(decl.ImmediateData.u); if (advance == 0) return FALSE; ctx->tokens_cur += advance; return TRUE; }