diff options
| author | 2019-03-14 02:23:37 -0300 | |
|---|---|---|
| committer | 2019-04-10 14:20:25 -0300 | |
| commit | 13aa664f3f0e778b8b4d4b01c28eee07677431e4 (patch) | |
| tree | 4cee6ad06edec4524dca9a2803945bdf81bfa998 /src | |
| parent | vk_shader_decompiler: Declare and stub interface for a SPIR-V decompiler (diff) | |
| download | yuzu-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.cpp | 460 |
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 | ||
| 13 | namespace Vulkan::VKShader { | 23 | namespace Vulkan::VKShader { |
| 14 | 24 | ||
| 25 | using Sirit::Id; | ||
| 26 | using Tegra::Shader::Attribute; | ||
| 27 | using Tegra::Shader::AttributeUse; | ||
| 28 | using Tegra::Shader::Register; | ||
| 15 | using namespace VideoCommon::Shader; | 29 | using namespace VideoCommon::Shader; |
| 16 | 30 | ||
| 31 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||
| 17 | using ShaderStage = Tegra::Engines::Maxwell3D::Regs::ShaderStage; | 32 | using ShaderStage = Tegra::Engines::Maxwell3D::Regs::ShaderStage; |
| 18 | 33 | ||
| 34 | // TODO(Rodrigo): Use rasterizer's value | ||
| 35 | constexpr u32 MAX_CONSTBUFFER_ELEMENTS = 0x1000; | ||
| 36 | constexpr u32 STAGE_BINDING_STRIDE = 0x100; | ||
| 37 | |||
| 38 | enum class Type { Bool, Bool2, Float, Int, Uint, HalfFloat }; | ||
| 39 | |||
| 40 | struct SamplerImage { | ||
| 41 | Id image_type; | ||
| 42 | Id sampled_image_type; | ||
| 43 | Id sampler; | ||
| 44 | }; | ||
| 45 | |||
| 46 | namespace { | ||
| 47 | |||
| 48 | spv::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 | ||
| 65 | constexpr 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 | ||
| 71 | constexpr 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 | |||
| 19 | class SPIRVDecompiler : public Sirit::Module { | 78 | class SPIRVDecompiler : public Sirit::Module { |
| 20 | public: | 79 | public: |
| 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 | ||
| 33 | private: | 130 | private: |
| 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 | ||
| 39 | DecompilerResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage) { | 493 | DecompilerResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage) { |