939
951
tgsi_parse_free(&parse);
943
* Collect information about the arrays of a given register file.
945
* @param tokens TGSI shader
946
* @param file the register file to scan through
947
* @param max_array_id number of entries in @p arrays; should be equal to the
948
* highest array id, i.e. tgsi_shader_info::array_max[file].
949
* @param arrays info for array of each ID will be written to arrays[ID - 1].
952
tgsi_scan_arrays(const struct tgsi_token *tokens,
954
unsigned max_array_id,
955
struct tgsi_array_info *arrays)
957
struct tgsi_parse_context parse;
959
if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
960
debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n");
964
memset(arrays, 0, sizeof(arrays[0]) * max_array_id);
966
while (!tgsi_parse_end_of_tokens(&parse)) {
967
struct tgsi_full_instruction *inst;
969
tgsi_parse_token(&parse);
971
if (parse.FullToken.Token.Type == TGSI_TOKEN_TYPE_DECLARATION) {
972
struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration;
974
if (decl->Declaration.Array && decl->Declaration.File == file &&
975
decl->Array.ArrayID > 0 && decl->Array.ArrayID <= max_array_id) {
976
struct tgsi_array_info *array = &arrays[decl->Array.ArrayID - 1];
977
assert(!array->declared);
978
array->declared = true;
979
array->range = decl->Range;
983
if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION)
986
inst = &parse.FullToken.FullInstruction;
987
for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {
988
const struct tgsi_full_dst_register *dst = &inst->Dst[i];
989
if (dst->Register.File != file)
992
if (dst->Register.Indirect) {
993
if (dst->Indirect.ArrayID > 0 &&
994
dst->Indirect.ArrayID <= max_array_id) {
995
arrays[dst->Indirect.ArrayID - 1].writemask |= dst->Register.WriteMask;
997
/* Indirect writes without an ArrayID can write anywhere. */
998
for (unsigned j = 0; j < max_array_id; ++j)
999
arrays[j].writemask |= dst->Register.WriteMask;
1002
/* Check whether the write falls into any of the arrays anyway. */
1003
for (unsigned j = 0; j < max_array_id; ++j) {
1004
struct tgsi_array_info *array = &arrays[j];
1005
if (array->declared &&
1006
dst->Register.Index >= array->range.First &&
1007
dst->Register.Index <= array->range.Last)
1008
array->writemask |= dst->Register.WriteMask;
1014
tgsi_parse_free(&parse);
1020
check_no_subroutines(const struct tgsi_full_instruction *inst)
1022
switch (inst->Instruction.Opcode) {
1023
case TGSI_OPCODE_BGNSUB:
1024
case TGSI_OPCODE_ENDSUB:
1025
case TGSI_OPCODE_CAL:
1026
unreachable("subroutines unhandled");
1031
get_inst_tessfactor_writemask(const struct tgsi_shader_info *info,
1032
const struct tgsi_full_instruction *inst)
1034
unsigned writemask = 0;
1036
for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {
1037
const struct tgsi_full_dst_register *dst = &inst->Dst[i];
1039
if (dst->Register.File == TGSI_FILE_OUTPUT &&
1040
!dst->Register.Indirect) {
1041
unsigned name = info->output_semantic_name[dst->Register.Index];
1043
if (name == TGSI_SEMANTIC_TESSINNER)
1044
writemask |= dst->Register.WriteMask;
1045
else if (name == TGSI_SEMANTIC_TESSOUTER)
1046
writemask |= dst->Register.WriteMask << 4;
1053
get_block_tessfactor_writemask(const struct tgsi_shader_info *info,
1054
struct tgsi_parse_context *parse,
1055
unsigned end_opcode)
1057
struct tgsi_full_instruction *inst;
1058
unsigned writemask = 0;
1060
tgsi_parse_token(parse);
1061
assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
1062
inst = &parse->FullToken.FullInstruction;
1063
check_no_subroutines(inst);
1065
while (inst->Instruction.Opcode != end_opcode) {
1067
/* Recursively process nested blocks. */
1068
switch (inst->Instruction.Opcode) {
1069
case TGSI_OPCODE_IF:
1070
case TGSI_OPCODE_UIF:
1072
get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDIF);
1075
case TGSI_OPCODE_BGNLOOP:
1077
get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP);
1080
case TGSI_OPCODE_BARRIER:
1081
unreachable("nested BARRIER is illegal");
1085
writemask |= get_inst_tessfactor_writemask(info, inst);
1088
tgsi_parse_token(parse);
1089
assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
1090
inst = &parse->FullToken.FullInstruction;
1091
check_no_subroutines(inst);
1098
get_if_block_tessfactor_writemask(const struct tgsi_shader_info *info,
1099
struct tgsi_parse_context *parse,
1100
unsigned *upper_block_tf_writemask,
1101
unsigned *cond_block_tf_writemask)
1103
struct tgsi_full_instruction *inst;
1104
unsigned then_tessfactor_writemask = 0;
1105
unsigned else_tessfactor_writemask = 0;
1107
bool is_then = true;
1109
tgsi_parse_token(parse);
1110
assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
1111
inst = &parse->FullToken.FullInstruction;
1112
check_no_subroutines(inst);
1114
while (inst->Instruction.Opcode != TGSI_OPCODE_ENDIF) {
1116
switch (inst->Instruction.Opcode) {
1117
case TGSI_OPCODE_ELSE:
1121
/* Recursively process nested blocks. */
1122
case TGSI_OPCODE_IF:
1123
case TGSI_OPCODE_UIF:
1124
get_if_block_tessfactor_writemask(info, parse,
1125
is_then ? &then_tessfactor_writemask :
1126
&else_tessfactor_writemask,
1127
cond_block_tf_writemask);
1130
case TGSI_OPCODE_BGNLOOP:
1131
*cond_block_tf_writemask |=
1132
get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP);
1135
case TGSI_OPCODE_BARRIER:
1136
unreachable("nested BARRIER is illegal");
1139
/* Process an instruction in the current block. */
1140
writemask = get_inst_tessfactor_writemask(info, inst);
1144
then_tessfactor_writemask |= writemask;
1146
else_tessfactor_writemask |= writemask;
1150
tgsi_parse_token(parse);
1151
assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
1152
inst = &parse->FullToken.FullInstruction;
1153
check_no_subroutines(inst);
1156
if (then_tessfactor_writemask || else_tessfactor_writemask) {
1157
/* If both statements write the same tess factor channels,
1158
* we can say that the upper block writes them too. */
1159
*upper_block_tf_writemask |= then_tessfactor_writemask &
1160
else_tessfactor_writemask;
1161
*cond_block_tf_writemask |= then_tessfactor_writemask |
1162
else_tessfactor_writemask;
1167
tgsi_scan_tess_ctrl(const struct tgsi_token *tokens,
1168
const struct tgsi_shader_info *info,
1169
struct tgsi_tessctrl_info *out)
1171
memset(out, 0, sizeof(*out));
1173
if (info->processor != PIPE_SHADER_TESS_CTRL)
1176
struct tgsi_parse_context parse;
1177
if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
1178
debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n");
1182
/* The pass works as follows:
1183
* If all codepaths write tess factors, we can say that all invocations
1184
* define tess factors.
1186
* Each tess factor channel is tracked separately.
1188
unsigned main_block_tf_writemask = 0; /* if main block writes tess factors */
1189
unsigned cond_block_tf_writemask = 0; /* if cond block writes tess factors */
1191
/* Initial value = true. Here the pass will accumulate results from multiple
1192
* segments surrounded by barriers. If tess factors aren't written at all,
1193
* it's a shader bug and we don't care if this will be true.
1195
out->tessfactors_are_def_in_all_invocs = true;
1197
while (!tgsi_parse_end_of_tokens(&parse)) {
1198
tgsi_parse_token(&parse);
1200
if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION)
1203
struct tgsi_full_instruction *inst = &parse.FullToken.FullInstruction;
1204
check_no_subroutines(inst);
1206
/* Process nested blocks. */
1207
switch (inst->Instruction.Opcode) {
1208
case TGSI_OPCODE_IF:
1209
case TGSI_OPCODE_UIF:
1210
get_if_block_tessfactor_writemask(info, &parse,
1211
&main_block_tf_writemask,
1212
&cond_block_tf_writemask);
1215
case TGSI_OPCODE_BGNLOOP:
1216
cond_block_tf_writemask |=
1217
get_block_tessfactor_writemask(info, &parse, TGSI_OPCODE_ENDLOOP);
1220
case TGSI_OPCODE_BARRIER:
1221
/* The following case must be prevented:
1222
* gl_TessLevelInner = ...;
1224
* if (gl_InvocationID == 1)
1225
* gl_TessLevelInner = ...;
1227
* If you consider disjoint code segments separated by barriers, each
1228
* such segment that writes tess factor channels should write the same
1229
* channels in all codepaths within that segment.
1231
if (main_block_tf_writemask || cond_block_tf_writemask) {
1232
/* Accumulate the result: */
1233
out->tessfactors_are_def_in_all_invocs &=
1234
!(cond_block_tf_writemask & ~main_block_tf_writemask);
1236
/* Analyze the next code segment from scratch. */
1237
main_block_tf_writemask = 0;
1238
cond_block_tf_writemask = 0;
1243
main_block_tf_writemask |= get_inst_tessfactor_writemask(info, inst);
1246
/* Accumulate the result for the last code segment separated by a barrier. */
1247
if (main_block_tf_writemask || cond_block_tf_writemask) {
1248
out->tessfactors_are_def_in_all_invocs &=
1249
!(cond_block_tf_writemask & ~main_block_tf_writemask);
1252
tgsi_parse_free(&parse);