summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp124
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp8
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp8
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h3
-rw-r--r--src/shader_recompiler/frontend/maxwell/program.cpp2
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp38
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp36
-rw-r--r--src/shader_recompiler/ir_opt/passes.h2
-rw-r--r--src/shader_recompiler/program_header.h83
-rw-r--r--src/shader_recompiler/shader_info.h2
12 files changed, 279 insertions, 35 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index 002b305dc..eadecb064 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -82,6 +82,28 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) {
82 } 82 }
83 throw InvalidArgument("Invalid attribute type {}", type); 83 throw InvalidArgument("Invalid attribute type {}", type);
84} 84}
85
86struct AttrInfo {
87 Id pointer;
88 Id id;
89 bool needs_cast;
90};
91
92std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) {
93 const AttributeType type{ctx.profile.generic_input_types.at(index)};
94 switch (type) {
95 case AttributeType::Float:
96 return AttrInfo{ctx.input_f32, ctx.F32[1], false};
97 case AttributeType::UnsignedInt:
98 return AttrInfo{ctx.input_u32, ctx.U32[1], true};
99 case AttributeType::SignedInt:
100 return AttrInfo{ctx.input_s32, ctx.TypeInt(32, true), true};
101 case AttributeType::Disabled:
102 return std::nullopt;
103 }
104 throw InvalidArgument("Invalid attribute type {}", type);
105}
106
85} // Anonymous namespace 107} // Anonymous namespace
86 108
87void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { 109void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) {
@@ -107,6 +129,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin
107 DefineConstantBuffers(program.info, binding); 129 DefineConstantBuffers(program.info, binding);
108 DefineStorageBuffers(program.info, binding); 130 DefineStorageBuffers(program.info, binding);
109 DefineTextures(program.info, binding); 131 DefineTextures(program.info, binding);
132 DefineAttributeMemAccess(program.info);
110 DefineLabels(program); 133 DefineLabels(program);
111} 134}
112 135
@@ -290,6 +313,107 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) {
290 } 313 }
291} 314}
292 315
316void EmitContext::DefineAttributeMemAccess(const Info& info) {
317 const auto make_load{[&]() {
318 const Id end_block{OpLabel()};
319 const Id default_label{OpLabel()};
320
321 const Id func_type_load{TypeFunction(F32[1], U32[1])};
322 const Id func{OpFunction(F32[1], spv::FunctionControlMask::MaskNone, func_type_load)};
323 const Id offset{OpFunctionParameter(U32[1])};
324 AddLabel();
325 const Id base_index{OpShiftRightLogical(U32[1], offset, Constant(U32[1], 2U))};
326 const Id masked_index{OpBitwiseAnd(U32[1], base_index, Constant(U32[1], 3U))};
327 const Id compare_index{OpShiftRightLogical(U32[1], base_index, Constant(U32[1], 2U))};
328 std::vector<Sirit::Literal> literals;
329 std::vector<Id> labels;
330 const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2;
331 for (u32 i = 0; i < info.input_generics.size(); i++) {
332 if (!info.input_generics[i].used) {
333 continue;
334 }
335 literals.push_back(base_attribute_value + i);
336 labels.push_back(OpLabel());
337 }
338 OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone);
339 OpSwitch(compare_index, default_label, literals, labels);
340 AddLabel(default_label);
341 OpReturnValue(Constant(F32[1], 0.0f));
342 size_t label_index = 0;
343 for (u32 i = 0; i < info.input_generics.size(); i++) {
344 if (!info.input_generics[i].used) {
345 continue;
346 }
347 AddLabel(labels[label_index]);
348 const auto type{AttrTypes(*this, i)};
349 if (!type) {
350 OpReturnValue(Constant(F32[1], 0.0f));
351 label_index++;
352 continue;
353 }
354 const Id generic_id{input_generics.at(i)};
355 const Id pointer{OpAccessChain(type->pointer, generic_id, masked_index)};
356 const Id value{OpLoad(type->id, pointer)};
357 const Id result{type->needs_cast ? OpBitcast(F32[1], value) : value};
358 OpReturnValue(result);
359 label_index++;
360 }
361 AddLabel(end_block);
362 OpUnreachable();
363 OpFunctionEnd();
364 return func;
365 }};
366 const auto make_store{[&]() {
367 const Id end_block{OpLabel()};
368 const Id default_label{OpLabel()};
369
370 const Id func_type_store{TypeFunction(void_id, U32[1], F32[1])};
371 const Id func{OpFunction(void_id, spv::FunctionControlMask::MaskNone, func_type_store)};
372 const Id offset{OpFunctionParameter(U32[1])};
373 const Id store_value{OpFunctionParameter(F32[1])};
374 AddLabel();
375 const Id base_index{OpShiftRightLogical(U32[1], offset, Constant(U32[1], 2U))};
376 const Id masked_index{OpBitwiseAnd(U32[1], base_index, Constant(U32[1], 3U))};
377 const Id compare_index{OpShiftRightLogical(U32[1], base_index, Constant(U32[1], 2U))};
378 std::vector<Sirit::Literal> literals;
379 std::vector<Id> labels;
380 const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2;
381 for (u32 i = 0; i < info.stores_generics.size(); i++) {
382 if (!info.stores_generics[i]) {
383 continue;
384 }
385 literals.push_back(base_attribute_value + i);
386 labels.push_back(OpLabel());
387 }
388 OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone);
389 OpSwitch(compare_index, default_label, literals, labels);
390 AddLabel(default_label);
391 OpReturn();
392 size_t label_index = 0;
393 for (u32 i = 0; i < info.stores_generics.size(); i++) {
394 if (!info.stores_generics[i]) {
395 continue;
396 }
397 AddLabel(labels[label_index]);
398 const Id generic_id{output_generics.at(i)};
399 const Id pointer{OpAccessChain(output_f32, generic_id, masked_index)};
400 OpStore(pointer, store_value);
401 OpReturn();
402 label_index++;
403 }
404 AddLabel(end_block);
405 OpUnreachable();
406 OpFunctionEnd();
407 return func;
408 }};
409 if (info.loads_indexed_attributes) {
410 indexed_load_func = make_load();
411 }
412 if (info.stores_indexed_attributes) {
413 indexed_store_func = make_store();
414 }
415}
416
293void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { 417void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
294 if (info.constant_buffer_descriptors.empty()) { 418 if (info.constant_buffer_descriptors.empty()) {
295 return; 419 return;
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index 03c5a6aba..7a2ac0511 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -116,6 +116,9 @@ public:
116 Id fswzadd_lut_a{}; 116 Id fswzadd_lut_a{};
117 Id fswzadd_lut_b{}; 117 Id fswzadd_lut_b{};
118 118
119 Id indexed_load_func{};
120 Id indexed_store_func{};
121
119 Id local_memory{}; 122 Id local_memory{};
120 123
121 Id shared_memory_u8{}; 124 Id shared_memory_u8{};
@@ -148,6 +151,7 @@ private:
148 void DefineConstantBuffers(const Info& info, u32& binding); 151 void DefineConstantBuffers(const Info& info, u32& binding);
149 void DefineStorageBuffers(const Info& info, u32& binding); 152 void DefineStorageBuffers(const Info& info, u32& binding);
150 void DefineTextures(const Info& info, u32& binding); 153 void DefineTextures(const Info& info, u32& binding);
154 void DefineAttributeMemAccess(const Info& info);
151 void DefineLabels(IR::Program& program); 155 void DefineLabels(IR::Program& program);
152 156
153 void DefineConstantBuffers(const Info& info, Id UniformDefinitions::*member_type, u32 binding, 157 void DefineConstantBuffers(const Info& info, Id UniformDefinitions::*member_type, u32 binding,
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index 712c5e61f..08460c94e 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -51,8 +51,8 @@ Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& o
51Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); 51Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset);
52Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr); 52Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr);
53void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value); 53void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value);
54void EmitGetAttributeIndexed(EmitContext& ctx); 54Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset);
55void EmitSetAttributeIndexed(EmitContext& ctx); 55void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value);
56void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value); 56void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value);
57void EmitSetFragDepth(EmitContext& ctx, Id value); 57void EmitSetFragDepth(EmitContext& ctx, Id value);
58void EmitGetZFlag(EmitContext& ctx); 58void EmitGetZFlag(EmitContext& ctx);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index 1bfc60294..a60eca815 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -216,12 +216,12 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value) {
216 ctx.OpStore(*output, value); 216 ctx.OpStore(*output, value);
217} 217}
218 218
219void EmitGetAttributeIndexed(EmitContext&) { 219Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset) {
220 throw NotImplementedException("SPIR-V Instruction"); 220 return ctx.OpFunctionCall(ctx.F32[1], ctx.indexed_load_func, offset);
221} 221}
222 222
223void EmitSetAttributeIndexed(EmitContext&) { 223void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value) {
224 throw NotImplementedException("SPIR-V Instruction"); 224 ctx.OpFunctionCall(ctx.void_id, ctx.indexed_store_func, offset, value);
225} 225}
226 226
227void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) { 227void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) {
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index ed1e0dd3b..e4e9b260c 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -307,6 +307,14 @@ void IREmitter::SetAttribute(IR::Attribute attribute, const F32& value) {
307 Inst(Opcode::SetAttribute, attribute, value); 307 Inst(Opcode::SetAttribute, attribute, value);
308} 308}
309 309
310F32 IREmitter::GetAttributeIndexed(IR::U32 phys_address) {
311 return Inst<F32>(Opcode::GetAttributeIndexed, phys_address);
312}
313
314void IREmitter::SetAttributeIndexed(IR::U32 phys_address, const F32& value) {
315 Inst(Opcode::SetAttributeIndexed, phys_address, value);
316}
317
310void IREmitter::SetFragColor(u32 index, u32 component, const F32& value) { 318void IREmitter::SetFragColor(u32 index, u32 component, const F32& value) {
311 Inst(Opcode::SetFragColor, Imm32(index), Imm32(component), value); 319 Inst(Opcode::SetFragColor, Imm32(index), Imm32(component), value);
312} 320}
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 42756af43..afa8bd924 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -76,6 +76,9 @@ public:
76 [[nodiscard]] F32 GetAttribute(IR::Attribute attribute); 76 [[nodiscard]] F32 GetAttribute(IR::Attribute attribute);
77 void SetAttribute(IR::Attribute attribute, const F32& value); 77 void SetAttribute(IR::Attribute attribute, const F32& value);
78 78
79 [[nodiscard]] F32 GetAttributeIndexed(IR::U32 phys_address);
80 void SetAttributeIndexed(IR::U32 phys_address, const F32& value);
81
79 void SetFragColor(u32 index, u32 component, const F32& value); 82 void SetFragColor(u32 index, u32 component, const F32& value);
80 void SetFragDepth(const F32& value); 83 void SetFragDepth(const F32& value);
81 84
diff --git a/src/shader_recompiler/frontend/maxwell/program.cpp b/src/shader_recompiler/frontend/maxwell/program.cpp
index 58caa35a1..aaf2a74a7 100644
--- a/src/shader_recompiler/frontend/maxwell/program.cpp
+++ b/src/shader_recompiler/frontend/maxwell/program.cpp
@@ -87,7 +87,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
87 Optimization::DeadCodeEliminationPass(program); 87 Optimization::DeadCodeEliminationPass(program);
88 Optimization::IdentityRemovalPass(program); 88 Optimization::IdentityRemovalPass(program);
89 Optimization::VerificationPass(program); 89 Optimization::VerificationPass(program);
90 Optimization::CollectShaderInfoPass(program); 90 Optimization::CollectShaderInfoPass(env, program);
91 CollectInterpolationInfo(env, program); 91 CollectInterpolationInfo(env, program);
92 return program; 92 return program;
93} 93}
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
index 54bc1e34c..0d248c020 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
@@ -31,7 +31,7 @@ enum class SampleMode : u64 {
31 Offset, 31 Offset,
32}; 32};
33 33
34int NumElements(Size size) { 34u32 NumElements(Size size) {
35 switch (size) { 35 switch (size) {
36 case Size::B32: 36 case Size::B32:
37 return 1; 37 return 1;
@@ -65,15 +65,21 @@ void TranslatorVisitor::ALD(u64 insn) {
65 if (ald.patch != 0) { 65 if (ald.patch != 0) {
66 throw NotImplementedException("P"); 66 throw NotImplementedException("P");
67 } 67 }
68 if (ald.index_reg != IR::Reg::RZ) {
69 throw NotImplementedException("Indexed");
70 }
71 const u64 offset{ald.absolute_offset.Value()}; 68 const u64 offset{ald.absolute_offset.Value()};
72 if (offset % 4 != 0) { 69 if (offset % 4 != 0) {
73 throw NotImplementedException("Unaligned absolute offset {}", offset); 70 throw NotImplementedException("Unaligned absolute offset {}", offset);
74 } 71 }
75 const int num_elements{NumElements(ald.size)}; 72 const u32 num_elements{NumElements(ald.size)};
76 for (int element = 0; element < num_elements; ++element) { 73 if (ald.index_reg != IR::Reg::RZ) {
74 const IR::U32 index_value = X(ald.index_reg);
75 for (u32 element = 0; element < num_elements; ++element) {
76 const IR::U32 final_offset =
77 element == 0 ? index_value : IR::U32{ir.IAdd(index_value, ir.Imm32(element * 4U))};
78 F(ald.dest_reg + element, ir.GetAttributeIndexed(final_offset));
79 }
80 return;
81 }
82 for (u32 element = 0; element < num_elements; ++element) {
77 F(ald.dest_reg + element, ir.GetAttribute(IR::Attribute{offset / 4 + element})); 83 F(ald.dest_reg + element, ir.GetAttribute(IR::Attribute{offset / 4 + element}));
78 } 84 }
79} 85}
@@ -103,8 +109,17 @@ void TranslatorVisitor::AST(u64 insn) {
103 if (offset % 4 != 0) { 109 if (offset % 4 != 0) {
104 throw NotImplementedException("Unaligned absolute offset {}", offset); 110 throw NotImplementedException("Unaligned absolute offset {}", offset);
105 } 111 }
106 const int num_elements{NumElements(ast.size)}; 112 const u32 num_elements{NumElements(ast.size)};
107 for (int element = 0; element < num_elements; ++element) { 113 if (ast.index_reg != IR::Reg::RZ) {
114 const IR::U32 index_value = X(ast.index_reg);
115 for (u32 element = 0; element < num_elements; ++element) {
116 const IR::U32 final_offset =
117 element == 0 ? index_value : IR::U32{ir.IAdd(index_value, ir.Imm32(element * 4U))};
118 ir.SetAttributeIndexed(final_offset, F(ast.src_reg + element));
119 }
120 return;
121 }
122 for (u32 element = 0; element < num_elements; ++element) {
108 ir.SetAttribute(IR::Attribute{offset / 4 + element}, F(ast.src_reg + element)); 123 ir.SetAttribute(IR::Attribute{offset / 4 + element}, F(ast.src_reg + element));
109 } 124 }
110} 125}
@@ -134,12 +149,9 @@ void TranslatorVisitor::IPA(u64 insn) {
134 // gl_FragColor = colors[idx]; 149 // gl_FragColor = colors[idx];
135 // } 150 // }
136 const bool is_indexed{ipa.idx != 0 && ipa.index_reg != IR::Reg::RZ}; 151 const bool is_indexed{ipa.idx != 0 && ipa.index_reg != IR::Reg::RZ};
137 if (is_indexed) {
138 throw NotImplementedException("IDX");
139 }
140
141 const IR::Attribute attribute{ipa.attribute}; 152 const IR::Attribute attribute{ipa.attribute};
142 IR::F32 value{ir.GetAttribute(attribute)}; 153 IR::F32 value{is_indexed ? ir.GetAttributeIndexed(X(ipa.index_reg))
154 : ir.GetAttribute(attribute)};
143 if (IR::IsGeneric(attribute)) { 155 if (IR::IsGeneric(attribute)) {
144 const ProgramHeader& sph{env.SPH()}; 156 const ProgramHeader& sph{env.SPH()};
145 const u32 attr_index{IR::GenericAttributeIndex(attribute)}; 157 const u32 attr_index{IR::GenericAttributeIndex(attribute)};
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
index 0f870535b..dbe9f1f40 100644
--- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
+++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "shader_recompiler/environment.h"
5#include "shader_recompiler/frontend/ir/microinstruction.h" 6#include "shader_recompiler/frontend/ir/microinstruction.h"
6#include "shader_recompiler/frontend/ir/modifiers.h" 7#include "shader_recompiler/frontend/ir/modifiers.h"
7#include "shader_recompiler/frontend/ir/program.h" 8#include "shader_recompiler/frontend/ir/program.h"
@@ -323,6 +324,12 @@ void VisitUsages(Info& info, IR::Inst& inst) {
323 case IR::Opcode::SetAttribute: 324 case IR::Opcode::SetAttribute:
324 SetAttribute(info, inst.Arg(0).Attribute()); 325 SetAttribute(info, inst.Arg(0).Attribute());
325 break; 326 break;
327 case IR::Opcode::GetAttributeIndexed:
328 info.loads_indexed_attributes = true;
329 break;
330 case IR::Opcode::SetAttributeIndexed:
331 info.stores_indexed_attributes = true;
332 break;
326 case IR::Opcode::SetFragColor: 333 case IR::Opcode::SetFragColor:
327 info.stores_frag_color[inst.Arg(0).U32()] = true; 334 info.stores_frag_color[inst.Arg(0).U32()] = true;
328 break; 335 break;
@@ -502,15 +509,42 @@ void Visit(Info& info, IR::Inst& inst) {
502 VisitUsages(info, inst); 509 VisitUsages(info, inst);
503 VisitFpModifiers(info, inst); 510 VisitFpModifiers(info, inst);
504} 511}
512
513void GatherInfoFromHeader(Environment& env, Info& info) {
514 auto stage = env.ShaderStage();
515 if (stage == Stage::Compute) {
516 return;
517 }
518 const auto& header = env.SPH();
519 if (stage == Stage::Fragment) {
520 for (size_t i = 0; i < info.input_generics.size(); i++) {
521 info.input_generics[i].used =
522 info.input_generics[i].used || header.ps.IsGenericVectorActive(i);
523 }
524 return;
525 }
526 for (size_t i = 0; i < info.input_generics.size(); i++) {
527 info.input_generics[i].used =
528 info.input_generics[i].used || header.vtg.IsInputGenericVectorActive(i);
529 }
530 for (size_t i = 0; i < info.stores_generics.size(); i++) {
531 info.stores_generics[i] =
532 info.stores_generics[i] || header.vtg.IsOutputGenericVectorActive(i);
533 }
534 info.stores_clip_distance =
535 info.stores_clip_distance || header.vtg.omap_systemc.clip_distances != 0;
536}
537
505} // Anonymous namespace 538} // Anonymous namespace
506 539
507void CollectShaderInfoPass(IR::Program& program) { 540void CollectShaderInfoPass(Environment& env, IR::Program& program) {
508 Info& info{program.info}; 541 Info& info{program.info};
509 for (IR::Block* const block : program.post_order_blocks) { 542 for (IR::Block* const block : program.post_order_blocks) {
510 for (IR::Inst& inst : block->Instructions()) { 543 for (IR::Inst& inst : block->Instructions()) {
511 Visit(info, inst); 544 Visit(info, inst);
512 } 545 }
513 } 546 }
547 GatherInfoFromHeader(env, info);
514} 548}
515 549
516} // namespace Shader::Optimization 550} // namespace Shader::Optimization
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h
index 5c1fc166c..186104713 100644
--- a/src/shader_recompiler/ir_opt/passes.h
+++ b/src/shader_recompiler/ir_opt/passes.h
@@ -12,7 +12,7 @@
12 12
13namespace Shader::Optimization { 13namespace Shader::Optimization {
14 14
15void CollectShaderInfoPass(IR::Program& program); 15void CollectShaderInfoPass(Environment& env, IR::Program& program);
16void ConstantPropagationPass(IR::Program& program); 16void ConstantPropagationPass(IR::Program& program);
17void DeadCodeEliminationPass(IR::Program& program); 17void DeadCodeEliminationPass(IR::Program& program);
18void GlobalMemoryToStorageBufferPass(IR::Program& program); 18void GlobalMemoryToStorageBufferPass(IR::Program& program);
diff --git a/src/shader_recompiler/program_header.h b/src/shader_recompiler/program_header.h
index 1544bfa42..ce65fc1a4 100644
--- a/src/shader_recompiler/program_header.h
+++ b/src/shader_recompiler/program_header.h
@@ -68,10 +68,24 @@ struct ProgramHeader {
68 68
69 union { 69 union {
70 struct { 70 struct {
71 INSERT_PADDING_BYTES_NOINIT(3); // ImapSystemValuesA 71 INSERT_PADDING_BYTES_NOINIT(3); // ImapSystemValuesA
72 INSERT_PADDING_BYTES_NOINIT(1); // ImapSystemValuesB 72 INSERT_PADDING_BYTES_NOINIT(1); // ImapSystemValuesB
73 INSERT_PADDING_BYTES_NOINIT(16); // ImapGenericVector[32] 73
74 INSERT_PADDING_BYTES_NOINIT(2); // ImapColor 74 union {
75 BitField<0, 1, u8> x;
76 BitField<1, 1, u8> y;
77 BitField<2, 1, u8> z;
78 BitField<3, 1, u8> w;
79 BitField<4, 1, u8> x2;
80 BitField<5, 1, u8> y2;
81 BitField<6, 1, u8> z2;
82 BitField<7, 1, u8> w2;
83 BitField<0, 4, u8> first;
84 BitField<4, 4, u8> second;
85 u8 raw;
86 } imap_generic_vector[16];
87
88 INSERT_PADDING_BYTES_NOINIT(2); // ImapColor
75 union { 89 union {
76 BitField<0, 8, u16> clip_distances; 90 BitField<0, 8, u16> clip_distances;
77 BitField<8, 1, u16> point_sprite_s; 91 BitField<8, 1, u16> point_sprite_s;
@@ -82,15 +96,54 @@ struct ProgramHeader {
82 BitField<14, 1, u16> instance_id; 96 BitField<14, 1, u16> instance_id;
83 BitField<15, 1, u16> vertex_id; 97 BitField<15, 1, u16> vertex_id;
84 }; 98 };
85 INSERT_PADDING_BYTES_NOINIT(5); // ImapFixedFncTexture[10] 99 INSERT_PADDING_BYTES_NOINIT(5); // ImapFixedFncTexture[10]
86 INSERT_PADDING_BYTES_NOINIT(1); // ImapReserved 100 INSERT_PADDING_BYTES_NOINIT(1); // ImapReserved
87 INSERT_PADDING_BYTES_NOINIT(3); // OmapSystemValuesA 101 INSERT_PADDING_BYTES_NOINIT(3); // OmapSystemValuesA
88 INSERT_PADDING_BYTES_NOINIT(1); // OmapSystemValuesB 102 INSERT_PADDING_BYTES_NOINIT(1); // OmapSystemValuesB
89 INSERT_PADDING_BYTES_NOINIT(16); // OmapGenericVector[32] 103
90 INSERT_PADDING_BYTES_NOINIT(2); // OmapColor 104 union {
91 INSERT_PADDING_BYTES_NOINIT(2); // OmapSystemValuesC 105 BitField<0, 1, u8> x;
92 INSERT_PADDING_BYTES_NOINIT(5); // OmapFixedFncTexture[10] 106 BitField<1, 1, u8> y;
93 INSERT_PADDING_BYTES_NOINIT(1); // OmapReserved 107 BitField<2, 1, u8> z;
108 BitField<3, 1, u8> w;
109 BitField<4, 1, u8> x2;
110 BitField<5, 1, u8> y2;
111 BitField<6, 1, u8> z2;
112 BitField<7, 1, u8> w2;
113 BitField<0, 4, u8> first;
114 BitField<4, 4, u8> second;
115 u8 raw;
116 } omap_generic_vector[16];
117
118 INSERT_PADDING_BYTES_NOINIT(2); // OmapColor
119
120 union {
121 BitField<0, 8, u16> clip_distances;
122 BitField<8, 1, u16> point_sprite_s;
123 BitField<9, 1, u16> point_sprite_t;
124 BitField<10, 1, u16> fog_coordinate;
125 BitField<12, 1, u16> tessellation_eval_point_u;
126 BitField<13, 1, u16> tessellation_eval_point_v;
127 BitField<14, 1, u16> instance_id;
128 BitField<15, 1, u16> vertex_id;
129 } omap_systemc;
130
131 INSERT_PADDING_BYTES_NOINIT(5); // OmapFixedFncTexture[10]
132 INSERT_PADDING_BYTES_NOINIT(1); // OmapReserved
133
134 [[nodiscard]] bool IsInputGenericVectorActive(size_t index) const {
135 if ((index & 1) == 0) {
136 return imap_generic_vector[index >> 1].first != 0;
137 }
138 return imap_generic_vector[index >> 1].second != 0;
139 }
140
141 [[nodiscard]] bool IsOutputGenericVectorActive(size_t index) const {
142 if ((index & 1) == 0) {
143 return omap_generic_vector[index >> 1].first != 0;
144 }
145 return omap_generic_vector[index >> 1].second != 0;
146 }
94 } vtg; 147 } vtg;
95 148
96 struct { 149 struct {
@@ -128,6 +181,10 @@ struct ProgramHeader {
128 const auto& vector{imap_generic_vector[attribute]}; 181 const auto& vector{imap_generic_vector[attribute]};
129 return {vector.x, vector.y, vector.z, vector.w}; 182 return {vector.x, vector.y, vector.z, vector.w};
130 } 183 }
184
185 [[nodiscard]] bool IsGenericVectorActive(size_t index) const {
186 return imap_generic_vector[index].raw != 0;
187 }
131 } ps; 188 } ps;
132 189
133 std::array<u32, 0xf> raw; 190 std::array<u32, 0xf> raw;
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h
index 9551a124f..41bb5b9a1 100644
--- a/src/shader_recompiler/shader_info.h
+++ b/src/shader_recompiler/shader_info.h
@@ -76,6 +76,7 @@ struct Info {
76 bool loads_vertex_id{}; 76 bool loads_vertex_id{};
77 bool loads_front_face{}; 77 bool loads_front_face{};
78 bool loads_point_coord{}; 78 bool loads_point_coord{};
79 bool loads_indexed_attributes{};
79 80
80 std::array<bool, 8> stores_frag_color{}; 81 std::array<bool, 8> stores_frag_color{};
81 bool stores_frag_depth{}; 82 bool stores_frag_depth{};
@@ -84,6 +85,7 @@ struct Info {
84 bool stores_point_size{}; 85 bool stores_point_size{};
85 bool stores_clip_distance{}; 86 bool stores_clip_distance{};
86 bool stores_viewport_index{}; 87 bool stores_viewport_index{};
88 bool stores_indexed_attributes{};
87 89
88 bool uses_fp16{}; 90 bool uses_fp16{};
89 bool uses_fp64{}; 91 bool uses_fp64{};