summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-03-14 02:23:37 -0300
committerGravatar ReinUsesLisp2019-04-10 14:20:25 -0300
commit13aa664f3f0e778b8b4d4b01c28eee07677431e4 (patch)
tree4cee6ad06edec4524dca9a2803945bdf81bfa998 /src
parentvk_shader_decompiler: Declare and stub interface for a SPIR-V decompiler (diff)
downloadyuzu-13aa664f3f0e778b8b4d4b01c28eee07677431e4.tar.gz
yuzu-13aa664f3f0e778b8b4d4b01c28eee07677431e4.tar.xz
yuzu-13aa664f3f0e778b8b4d4b01c28eee07677431e4.zip
vk_shader_decompiler: Implement declarations
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp460
1 files changed, 457 insertions, 3 deletions
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 3b8793840..563b3eb51 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -2,38 +2,492 @@
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 <functional>
6#include <map>
7#include <set>
8
9#include <fmt/format.h>
10
5#include <sirit/sirit.h> 11#include <sirit/sirit.h>
6 12
13#include "common/alignment.h"
7#include "common/assert.h" 14#include "common/assert.h"
15#include "common/common_types.h"
16#include "common/logging/log.h"
8#include "video_core/engines/maxwell_3d.h" 17#include "video_core/engines/maxwell_3d.h"
18#include "video_core/engines/shader_bytecode.h"
9#include "video_core/engines/shader_header.h" 19#include "video_core/engines/shader_header.h"
10#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 20#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
11#include "video_core/shader/shader_ir.h" 21#include "video_core/shader/shader_ir.h"
12 22
13namespace Vulkan::VKShader { 23namespace Vulkan::VKShader {
14 24
25using Sirit::Id;
26using Tegra::Shader::Attribute;
27using Tegra::Shader::AttributeUse;
28using Tegra::Shader::Register;
15using namespace VideoCommon::Shader; 29using namespace VideoCommon::Shader;
16 30
31using Maxwell = Tegra::Engines::Maxwell3D::Regs;
17using ShaderStage = Tegra::Engines::Maxwell3D::Regs::ShaderStage; 32using ShaderStage = Tegra::Engines::Maxwell3D::Regs::ShaderStage;
18 33
34// TODO(Rodrigo): Use rasterizer's value
35constexpr u32 MAX_CONSTBUFFER_ELEMENTS = 0x1000;
36constexpr u32 STAGE_BINDING_STRIDE = 0x100;
37
38enum class Type { Bool, Bool2, Float, Int, Uint, HalfFloat };
39
40struct SamplerImage {
41 Id image_type;
42 Id sampled_image_type;
43 Id sampler;
44};
45
46namespace {
47
48spv::Dim GetSamplerDim(const Sampler& sampler) {
49 switch (sampler.GetType()) {
50 case Tegra::Shader::TextureType::Texture1D:
51 return spv::Dim::Dim1D;
52 case Tegra::Shader::TextureType::Texture2D:
53 return spv::Dim::Dim2D;
54 case Tegra::Shader::TextureType::Texture3D:
55 return spv::Dim::Dim3D;
56 case Tegra::Shader::TextureType::TextureCube:
57 return spv::Dim::Cube;
58 default:
59 UNIMPLEMENTED_MSG("Unimplemented sampler type={}", static_cast<u32>(sampler.GetType()));
60 return spv::Dim::Dim2D;
61 }
62}
63
64/// Returns true if an attribute index is one of the 32 generic attributes
65constexpr bool IsGenericAttribute(Attribute::Index attribute) {
66 return attribute >= Attribute::Index::Attribute_0 &&
67 attribute <= Attribute::Index::Attribute_31;
68}
69
70/// Returns the location of a generic attribute
71constexpr u32 GetGenericAttributeLocation(Attribute::Index attribute) {
72 ASSERT(IsGenericAttribute(attribute));
73 return static_cast<u32>(attribute) - static_cast<u32>(Attribute::Index::Attribute_0);
74}
75
76} // namespace
77
19class SPIRVDecompiler : public Sirit::Module { 78class SPIRVDecompiler : public Sirit::Module {
20public: 79public:
21 explicit SPIRVDecompiler(const ShaderIR& ir, ShaderStage stage) 80 explicit SPIRVDecompiler(const ShaderIR& ir, ShaderStage stage)
22 : Module(0x00010300), ir{ir}, stage{stage}, header{ir.GetHeader()} {} 81 : Module(0x00010300), ir{ir}, stage{stage}, header{ir.GetHeader()} {
82 AddCapability(spv::Capability::Shader);
83 AddExtension("SPV_KHR_storage_buffer_storage_class");
84 AddExtension("SPV_KHR_variable_pointers");
85 }
23 86
24 void Decompile() { 87 void Decompile() {
88 AllocateBindings();
89
90 DeclareVertex();
91 DeclareGeometry();
92 DeclareFragment();
93 DeclareRegisters();
94 DeclarePredicates();
95 DeclareLocalMemory();
96 DeclareInternalFlags();
97 DeclareInputAttributes();
98 DeclareOutputAttributes();
99 DeclareConstantBuffers();
100 DeclareGlobalBuffers();
101 DeclareSamplers();
102
25 UNIMPLEMENTED(); 103 UNIMPLEMENTED();
26 } 104 }
27 105
28 ShaderEntries GetShaderEntries() const { 106 ShaderEntries GetShaderEntries() const {
29 UNIMPLEMENTED(); 107 ShaderEntries entries;
30 return {}; 108 entries.const_buffers_base_binding = const_buffers_base_binding;
109 entries.global_buffers_base_binding = global_buffers_base_binding;
110 entries.samplers_base_binding = samplers_base_binding;
111 for (const auto& cbuf : ir.GetConstantBuffers()) {
112 entries.const_buffers.emplace_back(cbuf.second, cbuf.first);
113 }
114 for (const auto& gmem : ir.GetGlobalMemoryBases()) {
115 entries.global_buffers.emplace_back(gmem.cbuf_index, gmem.cbuf_offset);
116 }
117 for (const auto& sampler : ir.GetSamplers()) {
118 entries.samplers.emplace_back(sampler);
119 }
120 for (const auto& attr : ir.GetInputAttributes()) {
121 entries.attributes.insert(GetGenericAttributeLocation(attr.first));
122 }
123 entries.clip_distances = ir.GetClipDistances();
124 entries.shader_length = ir.GetLength();
125 entries.entry_function = execute_function;
126 entries.interfaces = interfaces;
127 return entries;
31 } 128 }
32 129
33private: 130private:
131 static constexpr auto INTERNAL_FLAGS_COUNT = static_cast<std::size_t>(InternalFlag::Amount);
132 static constexpr u32 CBUF_STRIDE = 16;
133
134 void AllocateBindings() {
135 const u32 binding_base = static_cast<u32>(stage) * STAGE_BINDING_STRIDE;
136 u32 binding_iterator = binding_base;
137
138 const auto Allocate = [&binding_iterator](std::size_t count) {
139 const u32 current_binding = binding_iterator;
140 binding_iterator += static_cast<u32>(count);
141 return current_binding;
142 };
143 const_buffers_base_binding = Allocate(ir.GetConstantBuffers().size());
144 global_buffers_base_binding = Allocate(ir.GetGlobalMemoryBases().size());
145 samplers_base_binding = Allocate(ir.GetSamplers().size());
146
147 ASSERT_MSG(binding_iterator - binding_base < STAGE_BINDING_STRIDE,
148 "Stage binding stride is too small");
149 }
150
151 void DeclareVertex() {
152 if (stage != ShaderStage::Vertex)
153 return;
154
155 DeclareVertexRedeclarations();
156 }
157
158 void DeclareGeometry() {
159 if (stage != ShaderStage::Geometry)
160 return;
161
162 UNIMPLEMENTED();
163 }
164
165 void DeclareFragment() {
166 if (stage != ShaderStage::Fragment)
167 return;
168
169 for (u32 rt = 0; rt < static_cast<u32>(frag_colors.size()); ++rt) {
170 if (!IsRenderTargetUsed(rt)) {
171 continue;
172 }
173
174 const Id id = AddGlobalVariable(OpVariable(t_out_float4, spv::StorageClass::Output));
175 Name(id, fmt::format("frag_color{}", rt));
176 Decorate(id, spv::Decoration::Location, rt);
177
178 frag_colors[rt] = id;
179 interfaces.push_back(id);
180 }
181
182 if (header.ps.omap.depth) {
183 frag_depth = AddGlobalVariable(OpVariable(t_out_float, spv::StorageClass::Output));
184 Name(frag_depth, "frag_depth");
185 Decorate(frag_depth, spv::Decoration::BuiltIn,
186 static_cast<u32>(spv::BuiltIn::FragDepth));
187
188 interfaces.push_back(frag_depth);
189 }
190
191 frag_coord = DeclareBuiltIn(spv::BuiltIn::FragCoord, spv::StorageClass::Input, t_in_float4,
192 "frag_coord");
193 front_facing = DeclareBuiltIn(spv::BuiltIn::FrontFacing, spv::StorageClass::Input,
194 t_in_bool, "front_facing");
195 }
196
197 void DeclareRegisters() {
198 for (const u32 gpr : ir.GetRegisters()) {
199 const Id id = OpVariable(t_prv_float, spv::StorageClass::Private, v_float_zero);
200 Name(id, fmt::format("gpr_{}", gpr));
201 registers.emplace(gpr, AddGlobalVariable(id));
202 }
203 }
204
205 void DeclarePredicates() {
206 for (const auto pred : ir.GetPredicates()) {
207 const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
208 Name(id, fmt::format("pred_{}", static_cast<u32>(pred)));
209 predicates.emplace(pred, AddGlobalVariable(id));
210 }
211 }
212
213 void DeclareLocalMemory() {
214 if (const u64 local_memory_size = header.GetLocalMemorySize(); local_memory_size > 0) {
215 const auto element_count = static_cast<u32>(Common::AlignUp(local_memory_size, 4) / 4);
216 const Id type_array = TypeArray(t_float, Constant(t_uint, element_count));
217 const Id type_pointer = TypePointer(spv::StorageClass::Private, type_array);
218 Name(type_pointer, "LocalMemory");
219
220 local_memory =
221 OpVariable(type_pointer, spv::StorageClass::Private, ConstantNull(type_array));
222 AddGlobalVariable(Name(local_memory, "local_memory"));
223 }
224 }
225
226 void DeclareInternalFlags() {
227 constexpr std::array<const char*, INTERNAL_FLAGS_COUNT> names = {"zero", "sign", "carry",
228 "overflow"};
229 for (std::size_t flag = 0; flag < INTERNAL_FLAGS_COUNT; ++flag) {
230 const auto flag_code = static_cast<InternalFlag>(flag);
231 const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
232 internal_flags[flag] = AddGlobalVariable(Name(id, names[flag]));
233 }
234 }
235
236 void DeclareInputAttributes() {
237 for (const auto element : ir.GetInputAttributes()) {
238 const Attribute::Index index = element.first;
239 if (!IsGenericAttribute(index)) {
240 continue;
241 }
242
243 UNIMPLEMENTED_IF(stage == ShaderStage::Geometry);
244
245 const u32 location = GetGenericAttributeLocation(index);
246 const Id id = OpVariable(t_in_float4, spv::StorageClass::Input);
247 Name(AddGlobalVariable(id), fmt::format("in_attr{}", location));
248 input_attributes.emplace(index, id);
249 interfaces.push_back(id);
250
251 Decorate(id, spv::Decoration::Location, location);
252
253 if (stage != ShaderStage::Fragment) {
254 continue;
255 }
256 switch (header.ps.GetAttributeUse(location)) {
257 case AttributeUse::Constant:
258 Decorate(id, spv::Decoration::Flat);
259 break;
260 case AttributeUse::ScreenLinear:
261 Decorate(id, spv::Decoration::NoPerspective);
262 break;
263 case AttributeUse::Perspective:
264 // Default
265 break;
266 default:
267 UNREACHABLE_MSG("Unused attribute being fetched");
268 }
269 }
270 }
271
272 void DeclareOutputAttributes() {
273 for (const auto index : ir.GetOutputAttributes()) {
274 if (!IsGenericAttribute(index)) {
275 continue;
276 }
277 const auto location = GetGenericAttributeLocation(index);
278 const Id id = OpVariable(t_out_float4, spv::StorageClass::Output);
279 Name(AddGlobalVariable(id), fmt::format("out_attr{}", location));
280 output_attributes.emplace(index, id);
281 interfaces.push_back(id);
282
283 Decorate(id, spv::Decoration::Location, location);
284 }
285 }
286
287 void DeclareConstantBuffers() {
288 u32 binding = const_buffers_base_binding;
289 for (const auto& entry : ir.GetConstantBuffers()) {
290 const auto [index, size] = entry;
291 const Id id = OpVariable(t_cbuf_ubo, spv::StorageClass::Uniform);
292 AddGlobalVariable(Name(id, fmt::format("cbuf_{}", index)));
293
294 Decorate(id, spv::Decoration::Binding, binding++);
295 Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET);
296 constant_buffers.emplace(index, id);
297 }
298 }
299
300 void DeclareGlobalBuffers() {
301 u32 binding = global_buffers_base_binding;
302 for (const auto& entry : ir.GetGlobalMemoryBases()) {
303 const Id id = OpVariable(t_gmem_ssbo, spv::StorageClass::StorageBuffer);
304 AddGlobalVariable(
305 Name(id, fmt::format("gmem_{}_{}", entry.cbuf_index, entry.cbuf_offset)));
306
307 Decorate(id, spv::Decoration::Binding, binding++);
308 Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET);
309 global_buffers.emplace(entry, id);
310 }
311 }
312
313 void DeclareSamplers() {
314 u32 binding = samplers_base_binding;
315 for (const auto& sampler : ir.GetSamplers()) {
316 const auto dim = GetSamplerDim(sampler);
317 const int depth = sampler.IsShadow() ? 1 : 0;
318 const int arrayed = sampler.IsArray() ? 1 : 0;
319 // TODO(Rodrigo): Sampled 1 indicates that the image will be used with a sampler. When
320 // SULD and SUST instructions are implemented, replace this value.
321 const int sampled = 1;
322 const Id image_type =
323 TypeImage(t_float, dim, depth, arrayed, false, sampled, spv::ImageFormat::Unknown);
324 const Id sampled_image_type = TypeSampledImage(image_type);
325 const Id pointer_type =
326 TypePointer(spv::StorageClass::UniformConstant, sampled_image_type);
327 const Id id = OpVariable(pointer_type, spv::StorageClass::UniformConstant);
328 AddGlobalVariable(Name(id, fmt::format("sampler_{}", sampler.GetIndex())));
329
330 sampler_images.insert(
331 {static_cast<u32>(sampler.GetIndex()), {image_type, sampled_image_type, id}});
332
333 Decorate(id, spv::Decoration::Binding, binding++);
334 Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET);
335 }
336 }
337
338 void DeclareVertexRedeclarations() {
339 vertex_index = DeclareBuiltIn(spv::BuiltIn::VertexIndex, spv::StorageClass::Input,
340 t_in_uint, "vertex_index");
341 instance_index = DeclareBuiltIn(spv::BuiltIn::InstanceIndex, spv::StorageClass::Input,
342 t_in_uint, "instance_index");
343
344 bool is_point_size_declared = false;
345 bool is_clip_distances_declared = false;
346 for (const auto index : ir.GetOutputAttributes()) {
347 if (index == Attribute::Index::PointSize) {
348 is_point_size_declared = true;
349 } else if (index == Attribute::Index::ClipDistances0123 ||
350 index == Attribute::Index::ClipDistances4567) {
351 is_clip_distances_declared = true;
352 }
353 }
354
355 std::vector<Id> members;
356 members.push_back(t_float4);
357 if (is_point_size_declared) {
358 members.push_back(t_float);
359 }
360 if (is_clip_distances_declared) {
361 members.push_back(TypeArray(t_float, Constant(t_uint, 8)));
362 }
363
364 const Id gl_per_vertex_struct = Name(TypeStruct(members), "PerVertex");
365 Decorate(gl_per_vertex_struct, spv::Decoration::Block);
366
367 u32 declaration_index = 0;
368 const auto MemberDecorateBuiltIn = [&](spv::BuiltIn builtin, std::string name,
369 bool condition) {
370 if (!condition)
371 return u32{};
372 MemberName(gl_per_vertex_struct, declaration_index, name);
373 MemberDecorate(gl_per_vertex_struct, declaration_index, spv::Decoration::BuiltIn,
374 static_cast<u32>(builtin));
375 return declaration_index++;
376 };
377
378 position_index = MemberDecorateBuiltIn(spv::BuiltIn::Position, "position", true);
379 point_size_index =
380 MemberDecorateBuiltIn(spv::BuiltIn::PointSize, "point_size", is_point_size_declared);
381 clip_distances_index = MemberDecorateBuiltIn(spv::BuiltIn::ClipDistance, "clip_distances",
382 is_clip_distances_declared);
383
384 const Id type_pointer = TypePointer(spv::StorageClass::Output, gl_per_vertex_struct);
385 per_vertex = OpVariable(type_pointer, spv::StorageClass::Output);
386 AddGlobalVariable(Name(per_vertex, "per_vertex"));
387 interfaces.push_back(per_vertex);
388 }
389
390 Id DeclareBuiltIn(spv::BuiltIn builtin, spv::StorageClass storage, Id type,
391 const std::string& name) {
392 const Id id = OpVariable(type, storage);
393 Decorate(id, spv::Decoration::BuiltIn, static_cast<u32>(builtin));
394 AddGlobalVariable(Name(id, name));
395 interfaces.push_back(id);
396 return id;
397 }
398
399 bool IsRenderTargetUsed(u32 rt) const {
400 for (u32 component = 0; component < 4; ++component) {
401 if (header.ps.IsColorComponentOutputEnabled(rt, component)) {
402 return true;
403 }
404 }
405 return false;
406 }
407
34 const ShaderIR& ir; 408 const ShaderIR& ir;
35 const ShaderStage stage; 409 const ShaderStage stage;
36 const Tegra::Shader::Header header; 410 const Tegra::Shader::Header header;
411
412 const Id t_void = Name(TypeVoid(), "void");
413
414 const Id t_bool = Name(TypeBool(), "bool");
415 const Id t_bool2 = Name(TypeVector(t_bool, 2), "bool2");
416
417 const Id t_int = Name(TypeInt(32, true), "int");
418 const Id t_int2 = Name(TypeVector(t_int, 2), "int2");
419 const Id t_int3 = Name(TypeVector(t_int, 3), "int3");
420 const Id t_int4 = Name(TypeVector(t_int, 4), "int4");
421
422 const Id t_uint = Name(TypeInt(32, false), "uint");
423 const Id t_uint2 = Name(TypeVector(t_uint, 2), "uint2");
424 const Id t_uint3 = Name(TypeVector(t_uint, 3), "uint3");
425 const Id t_uint4 = Name(TypeVector(t_uint, 4), "uint4");
426
427 const Id t_float = Name(TypeFloat(32), "float");
428 const Id t_float2 = Name(TypeVector(t_float, 2), "float2");
429 const Id t_float3 = Name(TypeVector(t_float, 3), "float3");
430 const Id t_float4 = Name(TypeVector(t_float, 4), "float4");
431
432 const Id t_prv_bool = Name(TypePointer(spv::StorageClass::Private, t_bool), "prv_bool");
433 const Id t_prv_float = Name(TypePointer(spv::StorageClass::Private, t_float), "prv_float");
434
435 const Id t_in_bool = Name(TypePointer(spv::StorageClass::Input, t_bool), "in_bool");
436 const Id t_in_uint = Name(TypePointer(spv::StorageClass::Input, t_uint), "in_uint");
437 const Id t_in_float = Name(TypePointer(spv::StorageClass::Input, t_float), "in_float");
438 const Id t_in_float4 = Name(TypePointer(spv::StorageClass::Input, t_float4), "in_float4");
439
440 const Id t_out_float = Name(TypePointer(spv::StorageClass::Output, t_float), "out_float");
441 const Id t_out_float4 = Name(TypePointer(spv::StorageClass::Output, t_float4), "out_float4");
442
443 const Id t_cbuf_float = TypePointer(spv::StorageClass::Uniform, t_float);
444 const Id t_cbuf_array =
445 Decorate(Name(TypeArray(t_float4, Constant(t_uint, MAX_CONSTBUFFER_ELEMENTS)), "CbufArray"),
446 spv::Decoration::ArrayStride, CBUF_STRIDE);
447 const Id t_cbuf_struct = MemberDecorate(
448 Decorate(TypeStruct(t_cbuf_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0);
449 const Id t_cbuf_ubo = TypePointer(spv::StorageClass::Uniform, t_cbuf_struct);
450
451 const Id t_gmem_float = TypePointer(spv::StorageClass::StorageBuffer, t_float);
452 const Id t_gmem_array =
453 Name(Decorate(TypeRuntimeArray(t_float), spv::Decoration::ArrayStride, 4u), "GmemArray");
454 const Id t_gmem_struct = MemberDecorate(
455 Decorate(TypeStruct(t_gmem_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0);
456 const Id t_gmem_ssbo = TypePointer(spv::StorageClass::StorageBuffer, t_gmem_struct);
457
458 const Id v_float_zero = Constant(t_float, 0.0f);
459 const Id v_true = ConstantTrue(t_bool);
460 const Id v_false = ConstantFalse(t_bool);
461
462 Id per_vertex{};
463 std::map<u32, Id> registers;
464 std::map<Tegra::Shader::Pred, Id> predicates;
465 Id local_memory{};
466 std::array<Id, INTERNAL_FLAGS_COUNT> internal_flags{};
467 std::map<Attribute::Index, Id> input_attributes;
468 std::map<Attribute::Index, Id> output_attributes;
469 std::map<u32, Id> constant_buffers;
470 std::map<GlobalMemoryBase, Id> global_buffers;
471 std::map<u32, SamplerImage> sampler_images;
472
473 Id instance_index{};
474 Id vertex_index{};
475 std::array<Id, Maxwell::NumRenderTargets> frag_colors{};
476 Id frag_depth{};
477 Id frag_coord{};
478 Id front_facing{};
479
480 u32 position_index{};
481 u32 point_size_index{};
482 u32 clip_distances_index{};
483
484 std::vector<Id> interfaces;
485
486 u32 const_buffers_base_binding{};
487 u32 global_buffers_base_binding{};
488 u32 samplers_base_binding{};
489
490 Id execute_function{};
37}; 491};
38 492
39DecompilerResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage) { 493DecompilerResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage) {