summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/maxwell/translate_program.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-06-16 01:49:19 -0300
committerGravatar ameerj2021-07-22 21:51:38 -0400
commit376aa94819b7da976adb120136d83980a757d044 (patch)
tree9e7917c30612ee74d37f92ee4773e907e75dddb4 /src/shader_recompiler/frontend/maxwell/translate_program.cpp
parentvulkan_device: Blacklist VK_EXT_vertex_input_dynamic_state on Intel (diff)
downloadyuzu-376aa94819b7da976adb120136d83980a757d044.tar.gz
yuzu-376aa94819b7da976adb120136d83980a757d044.tar.xz
yuzu-376aa94819b7da976adb120136d83980a757d044.zip
shader: Rename maxwell/program.h to translate_program.h
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/translate_program.cpp')
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate_program.cpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp
new file mode 100644
index 000000000..e52170e3e
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp
@@ -0,0 +1,203 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <memory>
7#include <ranges>
8#include <vector>
9
10#include "shader_recompiler/exception.h"
11#include "shader_recompiler/frontend/ir/basic_block.h"
12#include "shader_recompiler/frontend/ir/post_order.h"
13#include "shader_recompiler/frontend/maxwell/structured_control_flow.h"
14#include "shader_recompiler/frontend/maxwell/translate/translate.h"
15#include "shader_recompiler/frontend/maxwell/translate_program.h"
16#include "shader_recompiler/ir_opt/passes.h"
17
18namespace Shader::Maxwell {
19namespace {
20IR::BlockList GenerateBlocks(const IR::AbstractSyntaxList& syntax_list) {
21 auto syntax_blocks{syntax_list | std::views::filter([](const auto& node) {
22 return node.type == IR::AbstractSyntaxNode::Type::Block;
23 })};
24 IR::BlockList blocks(std::ranges::distance(syntax_blocks));
25 std::ranges::transform(syntax_blocks, blocks.begin(),
26 [](const IR::AbstractSyntaxNode& node) { return node.data.block; });
27 return blocks;
28}
29
30void RemoveUnreachableBlocks(IR::Program& program) {
31 // Some blocks might be unreachable if a function call exists unconditionally
32 // If this happens the number of blocks and post order blocks will mismatch
33 if (program.blocks.size() == program.post_order_blocks.size()) {
34 return;
35 }
36 const auto begin{program.blocks.begin() + 1};
37 const auto end{program.blocks.end()};
38 const auto pred{[](IR::Block* block) { return block->ImmPredecessors().empty(); }};
39 program.blocks.erase(std::remove_if(begin, end, pred), end);
40}
41
42void CollectInterpolationInfo(Environment& env, IR::Program& program) {
43 if (program.stage != Stage::Fragment) {
44 return;
45 }
46 const ProgramHeader& sph{env.SPH()};
47 for (size_t index = 0; index < program.info.input_generics.size(); ++index) {
48 std::optional<PixelImap> imap;
49 for (const PixelImap value : sph.ps.GenericInputMap(static_cast<u32>(index))) {
50 if (value == PixelImap::Unused) {
51 continue;
52 }
53 if (imap && imap != value) {
54 throw NotImplementedException("Per component interpolation");
55 }
56 imap = value;
57 }
58 if (!imap) {
59 continue;
60 }
61 program.info.input_generics[index].interpolation = [&] {
62 switch (*imap) {
63 case PixelImap::Unused:
64 case PixelImap::Perspective:
65 return Interpolation::Smooth;
66 case PixelImap::Constant:
67 return Interpolation::Flat;
68 case PixelImap::ScreenLinear:
69 return Interpolation::NoPerspective;
70 }
71 throw NotImplementedException("Unknown interpolation {}", *imap);
72 }();
73 }
74}
75
76void AddNVNStorageBuffers(IR::Program& program) {
77 if (!program.info.uses_global_memory) {
78 return;
79 }
80 const u32 driver_cbuf{0};
81 const u32 descriptor_size{0x10};
82 const u32 num_buffers{16};
83 const u32 base{[&] {
84 switch (program.stage) {
85 case Stage::VertexA:
86 case Stage::VertexB:
87 return 0x110u;
88 case Stage::TessellationControl:
89 return 0x210u;
90 case Stage::TessellationEval:
91 return 0x310u;
92 case Stage::Geometry:
93 return 0x410u;
94 case Stage::Fragment:
95 return 0x510u;
96 case Stage::Compute:
97 return 0x310u;
98 }
99 throw InvalidArgument("Invalid stage {}", program.stage);
100 }()};
101 auto& descs{program.info.storage_buffers_descriptors};
102 for (u32 index = 0; index < num_buffers; ++index) {
103 if (!program.info.nvn_buffer_used[index]) {
104 continue;
105 }
106 const u32 offset{base + index * descriptor_size};
107 const auto it{std::ranges::find(descs, offset, &StorageBufferDescriptor::cbuf_offset)};
108 if (it != descs.end()) {
109 it->is_written |= program.info.stores_global_memory;
110 continue;
111 }
112 descs.push_back({
113 .cbuf_index = driver_cbuf,
114 .cbuf_offset = offset,
115 .count = 1,
116 .is_written = program.info.stores_global_memory,
117 });
118 }
119}
120} // Anonymous namespace
121
122IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool,
123 Environment& env, Flow::CFG& cfg) {
124 IR::Program program;
125 program.syntax_list = BuildASL(inst_pool, block_pool, env, cfg);
126 program.blocks = GenerateBlocks(program.syntax_list);
127 program.post_order_blocks = PostOrder(program.syntax_list.front());
128 program.stage = env.ShaderStage();
129 program.local_memory_size = env.LocalMemorySize();
130 switch (program.stage) {
131 case Stage::TessellationControl: {
132 const ProgramHeader& sph{env.SPH()};
133 program.invocations = sph.common2.threads_per_input_primitive;
134 break;
135 }
136 case Stage::Geometry: {
137 const ProgramHeader& sph{env.SPH()};
138 program.output_topology = sph.common3.output_topology;
139 program.output_vertices = sph.common4.max_output_vertices;
140 program.invocations = sph.common2.threads_per_input_primitive;
141 break;
142 }
143 case Stage::Compute:
144 program.workgroup_size = env.WorkgroupSize();
145 program.shared_memory_size = env.SharedMemorySize();
146 break;
147 default:
148 break;
149 }
150 RemoveUnreachableBlocks(program);
151
152 // Replace instructions before the SSA rewrite
153 Optimization::LowerFp16ToFp32(program);
154
155 Optimization::SsaRewritePass(program);
156
157 Optimization::GlobalMemoryToStorageBufferPass(program);
158 Optimization::TexturePass(env, program);
159
160 Optimization::ConstantPropagationPass(program);
161 Optimization::DeadCodeEliminationPass(program);
162 Optimization::VerificationPass(program);
163 Optimization::CollectShaderInfoPass(env, program);
164 CollectInterpolationInfo(env, program);
165 AddNVNStorageBuffers(program);
166 return program;
167}
168
169IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b,
170 Environment& env_vertex_b) {
171 IR::Program result{};
172 Optimization::VertexATransformPass(vertex_a);
173 Optimization::VertexBTransformPass(vertex_b);
174 for (const auto& term : vertex_a.syntax_list) {
175 if (term.type == IR::AbstractSyntaxNode::Type::Return) {
176 continue;
177 }
178 result.syntax_list.push_back(term);
179 }
180 for (const auto& term : vertex_b.syntax_list) {
181 result.syntax_list.push_back(term);
182 }
183 result.blocks = GenerateBlocks(result.syntax_list);
184 result.post_order_blocks = vertex_b.post_order_blocks;
185 for (const auto& block : vertex_a.post_order_blocks) {
186 result.post_order_blocks.push_back(block);
187 }
188 result.stage = Stage::VertexB;
189 result.info = vertex_a.info;
190 result.local_memory_size = std::max(vertex_a.local_memory_size, vertex_b.local_memory_size);
191 for (size_t index = 0; index < 32; ++index) {
192 result.info.input_generics[index].used |= vertex_b.info.input_generics[index].used;
193 result.info.stores_generics[index] |= vertex_b.info.stores_generics[index];
194 }
195 Optimization::JoinTextureInfo(result.info, vertex_b.info);
196 Optimization::JoinStorageInfo(result.info, vertex_b.info);
197 Optimization::DeadCodeEliminationPass(result);
198 Optimization::VerificationPass(result);
199 Optimization::CollectShaderInfoPass(env_vertex_b, result);
200 return result;
201}
202
203} // namespace Shader::Maxwell