|
|
|
@@ -44,6 +44,375 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
scan_instruction(struct tgsi_shader_info *info, |
|
|
|
const struct tgsi_full_instruction *fullinst, |
|
|
|
unsigned *current_depth) |
|
|
|
{ |
|
|
|
unsigned 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 (info->processor == 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++; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
scan_declaration(struct tgsi_shader_info *info, |
|
|
|
const struct tgsi_full_declaration *fulldecl) |
|
|
|
{ |
|
|
|
const uint file = fulldecl->Declaration.File; |
|
|
|
const unsigned procType = info->processor; |
|
|
|
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 (semName == TGSI_SEMANTIC_POSITION) |
|
|
|
info->reads_position = TRUE; |
|
|
|
else if (semName == TGSI_SEMANTIC_FACE) |
|
|
|
info->uses_frontface = TRUE; |
|
|
|
else if (semName == TGSI_SEMANTIC_SAMPLEMASK) |
|
|
|
info->reads_samplemask = 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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
scan_immediate(struct tgsi_shader_info *info) |
|
|
|
{ |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
scan_property(struct tgsi_shader_info *info, |
|
|
|
const struct tgsi_full_property *fullprop) |
|
|
|
{ |
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Scan the given TGSI shader to collect information such as number of |
|
|
|
@@ -93,378 +462,20 @@ tgsi_scan_shader(const struct tgsi_token *tokens, |
|
|
|
|
|
|
|
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++; |
|
|
|
} |
|
|
|
scan_instruction(info, &parse.FullToken.FullInstruction, |
|
|
|
¤t_depth); |
|
|
|
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 (semName == TGSI_SEMANTIC_POSITION) |
|
|
|
info->reads_position = TRUE; |
|
|
|
else if (semName == TGSI_SEMANTIC_FACE) |
|
|
|
info->uses_frontface = TRUE; |
|
|
|
else if (semName == TGSI_SEMANTIC_SAMPLEMASK) |
|
|
|
info->reads_samplemask = 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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
scan_declaration(info, &parse.FullToken.FullDeclaration); |
|
|
|
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); |
|
|
|
} |
|
|
|
scan_immediate(info); |
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
scan_property(info, &parse.FullToken.FullProperty); |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
assert( 0 ); |
|
|
|
assert(!"Unexpected TGSI token type"); |
|
|
|
} |
|
|
|
} |
|
|
|
|