|
|
|
@ -2,38 +2,492 @@ |
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
#include <map>
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
#include <fmt/format.h>
|
|
|
|
|
|
|
|
#include <sirit/sirit.h>
|
|
|
|
|
|
|
|
#include "common/alignment.h"
|
|
|
|
#include "common/assert.h"
|
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "common/logging/log.h"
|
|
|
|
#include "video_core/engines/maxwell_3d.h"
|
|
|
|
#include "video_core/engines/shader_bytecode.h"
|
|
|
|
#include "video_core/engines/shader_header.h"
|
|
|
|
#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
|
|
|
|
#include "video_core/shader/shader_ir.h"
|
|
|
|
|
|
|
|
namespace Vulkan::VKShader { |
|
|
|
|
|
|
|
using Sirit::Id; |
|
|
|
using Tegra::Shader::Attribute; |
|
|
|
using Tegra::Shader::AttributeUse; |
|
|
|
using Tegra::Shader::Register; |
|
|
|
using namespace VideoCommon::Shader; |
|
|
|
|
|
|
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
|
|
|
using ShaderStage = Tegra::Engines::Maxwell3D::Regs::ShaderStage; |
|
|
|
|
|
|
|
// TODO(Rodrigo): Use rasterizer's value
|
|
|
|
constexpr u32 MAX_CONSTBUFFER_ELEMENTS = 0x1000; |
|
|
|
constexpr u32 STAGE_BINDING_STRIDE = 0x100; |
|
|
|
|
|
|
|
enum class Type { Bool, Bool2, Float, Int, Uint, HalfFloat }; |
|
|
|
|
|
|
|
struct SamplerImage { |
|
|
|
Id image_type; |
|
|
|
Id sampled_image_type; |
|
|
|
Id sampler; |
|
|
|
}; |
|
|
|
|
|
|
|
namespace { |
|
|
|
|
|
|
|
spv::Dim GetSamplerDim(const Sampler& sampler) { |
|
|
|
switch (sampler.GetType()) { |
|
|
|
case Tegra::Shader::TextureType::Texture1D: |
|
|
|
return spv::Dim::Dim1D; |
|
|
|
case Tegra::Shader::TextureType::Texture2D: |
|
|
|
return spv::Dim::Dim2D; |
|
|
|
case Tegra::Shader::TextureType::Texture3D: |
|
|
|
return spv::Dim::Dim3D; |
|
|
|
case Tegra::Shader::TextureType::TextureCube: |
|
|
|
return spv::Dim::Cube; |
|
|
|
default: |
|
|
|
UNIMPLEMENTED_MSG("Unimplemented sampler type={}", static_cast<u32>(sampler.GetType())); |
|
|
|
return spv::Dim::Dim2D; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// Returns true if an attribute index is one of the 32 generic attributes
|
|
|
|
constexpr bool IsGenericAttribute(Attribute::Index attribute) { |
|
|
|
return attribute >= Attribute::Index::Attribute_0 && |
|
|
|
attribute <= Attribute::Index::Attribute_31; |
|
|
|
} |
|
|
|
|
|
|
|
/// Returns the location of a generic attribute
|
|
|
|
constexpr u32 GetGenericAttributeLocation(Attribute::Index attribute) { |
|
|
|
ASSERT(IsGenericAttribute(attribute)); |
|
|
|
return static_cast<u32>(attribute) - static_cast<u32>(Attribute::Index::Attribute_0); |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
class SPIRVDecompiler : public Sirit::Module { |
|
|
|
public: |
|
|
|
explicit SPIRVDecompiler(const ShaderIR& ir, ShaderStage stage) |
|
|
|
: Module(0x00010300), ir{ir}, stage{stage}, header{ir.GetHeader()} {} |
|
|
|
: Module(0x00010300), ir{ir}, stage{stage}, header{ir.GetHeader()} { |
|
|
|
AddCapability(spv::Capability::Shader); |
|
|
|
AddExtension("SPV_KHR_storage_buffer_storage_class"); |
|
|
|
AddExtension("SPV_KHR_variable_pointers"); |
|
|
|
} |
|
|
|
|
|
|
|
void Decompile() { |
|
|
|
AllocateBindings(); |
|
|
|
|
|
|
|
DeclareVertex(); |
|
|
|
DeclareGeometry(); |
|
|
|
DeclareFragment(); |
|
|
|
DeclareRegisters(); |
|
|
|
DeclarePredicates(); |
|
|
|
DeclareLocalMemory(); |
|
|
|
DeclareInternalFlags(); |
|
|
|
DeclareInputAttributes(); |
|
|
|
DeclareOutputAttributes(); |
|
|
|
DeclareConstantBuffers(); |
|
|
|
DeclareGlobalBuffers(); |
|
|
|
DeclareSamplers(); |
|
|
|
|
|
|
|
UNIMPLEMENTED(); |
|
|
|
} |
|
|
|
|
|
|
|
ShaderEntries GetShaderEntries() const { |
|
|
|
UNIMPLEMENTED(); |
|
|
|
return {}; |
|
|
|
ShaderEntries entries; |
|
|
|
entries.const_buffers_base_binding = const_buffers_base_binding; |
|
|
|
entries.global_buffers_base_binding = global_buffers_base_binding; |
|
|
|
entries.samplers_base_binding = samplers_base_binding; |
|
|
|
for (const auto& cbuf : ir.GetConstantBuffers()) { |
|
|
|
entries.const_buffers.emplace_back(cbuf.second, cbuf.first); |
|
|
|
} |
|
|
|
for (const auto& gmem : ir.GetGlobalMemoryBases()) { |
|
|
|
entries.global_buffers.emplace_back(gmem.cbuf_index, gmem.cbuf_offset); |
|
|
|
} |
|
|
|
for (const auto& sampler : ir.GetSamplers()) { |
|
|
|
entries.samplers.emplace_back(sampler); |
|
|
|
} |
|
|
|
for (const auto& attr : ir.GetInputAttributes()) { |
|
|
|
entries.attributes.insert(GetGenericAttributeLocation(attr.first)); |
|
|
|
} |
|
|
|
entries.clip_distances = ir.GetClipDistances(); |
|
|
|
entries.shader_length = ir.GetLength(); |
|
|
|
entries.entry_function = execute_function; |
|
|
|
entries.interfaces = interfaces; |
|
|
|
return entries; |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
static constexpr auto INTERNAL_FLAGS_COUNT = static_cast<std::size_t>(InternalFlag::Amount); |
|
|
|
static constexpr u32 CBUF_STRIDE = 16; |
|
|
|
|
|
|
|
void AllocateBindings() { |
|
|
|
const u32 binding_base = static_cast<u32>(stage) * STAGE_BINDING_STRIDE; |
|
|
|
u32 binding_iterator = binding_base; |
|
|
|
|
|
|
|
const auto Allocate = [&binding_iterator](std::size_t count) { |
|
|
|
const u32 current_binding = binding_iterator; |
|
|
|
binding_iterator += static_cast<u32>(count); |
|
|
|
return current_binding; |
|
|
|
}; |
|
|
|
const_buffers_base_binding = Allocate(ir.GetConstantBuffers().size()); |
|
|
|
global_buffers_base_binding = Allocate(ir.GetGlobalMemoryBases().size()); |
|
|
|
samplers_base_binding = Allocate(ir.GetSamplers().size()); |
|
|
|
|
|
|
|
ASSERT_MSG(binding_iterator - binding_base < STAGE_BINDING_STRIDE, |
|
|
|
"Stage binding stride is too small"); |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareVertex() { |
|
|
|
if (stage != ShaderStage::Vertex) |
|
|
|
return; |
|
|
|
|
|
|
|
DeclareVertexRedeclarations(); |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareGeometry() { |
|
|
|
if (stage != ShaderStage::Geometry) |
|
|
|
return; |
|
|
|
|
|
|
|
UNIMPLEMENTED(); |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareFragment() { |
|
|
|
if (stage != ShaderStage::Fragment) |
|
|
|
return; |
|
|
|
|
|
|
|
for (u32 rt = 0; rt < static_cast<u32>(frag_colors.size()); ++rt) { |
|
|
|
if (!IsRenderTargetUsed(rt)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
const Id id = AddGlobalVariable(OpVariable(t_out_float4, spv::StorageClass::Output)); |
|
|
|
Name(id, fmt::format("frag_color{}", rt)); |
|
|
|
Decorate(id, spv::Decoration::Location, rt); |
|
|
|
|
|
|
|
frag_colors[rt] = id; |
|
|
|
interfaces.push_back(id); |
|
|
|
} |
|
|
|
|
|
|
|
if (header.ps.omap.depth) { |
|
|
|
frag_depth = AddGlobalVariable(OpVariable(t_out_float, spv::StorageClass::Output)); |
|
|
|
Name(frag_depth, "frag_depth"); |
|
|
|
Decorate(frag_depth, spv::Decoration::BuiltIn, |
|
|
|
static_cast<u32>(spv::BuiltIn::FragDepth)); |
|
|
|
|
|
|
|
interfaces.push_back(frag_depth); |
|
|
|
} |
|
|
|
|
|
|
|
frag_coord = DeclareBuiltIn(spv::BuiltIn::FragCoord, spv::StorageClass::Input, t_in_float4, |
|
|
|
"frag_coord"); |
|
|
|
front_facing = DeclareBuiltIn(spv::BuiltIn::FrontFacing, spv::StorageClass::Input, |
|
|
|
t_in_bool, "front_facing"); |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareRegisters() { |
|
|
|
for (const u32 gpr : ir.GetRegisters()) { |
|
|
|
const Id id = OpVariable(t_prv_float, spv::StorageClass::Private, v_float_zero); |
|
|
|
Name(id, fmt::format("gpr_{}", gpr)); |
|
|
|
registers.emplace(gpr, AddGlobalVariable(id)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void DeclarePredicates() { |
|
|
|
for (const auto pred : ir.GetPredicates()) { |
|
|
|
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); |
|
|
|
Name(id, fmt::format("pred_{}", static_cast<u32>(pred))); |
|
|
|
predicates.emplace(pred, AddGlobalVariable(id)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareLocalMemory() { |
|
|
|
if (const u64 local_memory_size = header.GetLocalMemorySize(); local_memory_size > 0) { |
|
|
|
const auto element_count = static_cast<u32>(Common::AlignUp(local_memory_size, 4) / 4); |
|
|
|
const Id type_array = TypeArray(t_float, Constant(t_uint, element_count)); |
|
|
|
const Id type_pointer = TypePointer(spv::StorageClass::Private, type_array); |
|
|
|
Name(type_pointer, "LocalMemory"); |
|
|
|
|
|
|
|
local_memory = |
|
|
|
OpVariable(type_pointer, spv::StorageClass::Private, ConstantNull(type_array)); |
|
|
|
AddGlobalVariable(Name(local_memory, "local_memory")); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareInternalFlags() { |
|
|
|
constexpr std::array<const char*, INTERNAL_FLAGS_COUNT> names = {"zero", "sign", "carry", |
|
|
|
"overflow"}; |
|
|
|
for (std::size_t flag = 0; flag < INTERNAL_FLAGS_COUNT; ++flag) { |
|
|
|
const auto flag_code = static_cast<InternalFlag>(flag); |
|
|
|
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); |
|
|
|
internal_flags[flag] = AddGlobalVariable(Name(id, names[flag])); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareInputAttributes() { |
|
|
|
for (const auto element : ir.GetInputAttributes()) { |
|
|
|
const Attribute::Index index = element.first; |
|
|
|
if (!IsGenericAttribute(index)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
UNIMPLEMENTED_IF(stage == ShaderStage::Geometry); |
|
|
|
|
|
|
|
const u32 location = GetGenericAttributeLocation(index); |
|
|
|
const Id id = OpVariable(t_in_float4, spv::StorageClass::Input); |
|
|
|
Name(AddGlobalVariable(id), fmt::format("in_attr{}", location)); |
|
|
|
input_attributes.emplace(index, id); |
|
|
|
interfaces.push_back(id); |
|
|
|
|
|
|
|
Decorate(id, spv::Decoration::Location, location); |
|
|
|
|
|
|
|
if (stage != ShaderStage::Fragment) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
switch (header.ps.GetAttributeUse(location)) { |
|
|
|
case AttributeUse::Constant: |
|
|
|
Decorate(id, spv::Decoration::Flat); |
|
|
|
break; |
|
|
|
case AttributeUse::ScreenLinear: |
|
|
|
Decorate(id, spv::Decoration::NoPerspective); |
|
|
|
break; |
|
|
|
case AttributeUse::Perspective: |
|
|
|
// Default
|
|
|
|
break; |
|
|
|
default: |
|
|
|
UNREACHABLE_MSG("Unused attribute being fetched"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareOutputAttributes() { |
|
|
|
for (const auto index : ir.GetOutputAttributes()) { |
|
|
|
if (!IsGenericAttribute(index)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
const auto location = GetGenericAttributeLocation(index); |
|
|
|
const Id id = OpVariable(t_out_float4, spv::StorageClass::Output); |
|
|
|
Name(AddGlobalVariable(id), fmt::format("out_attr{}", location)); |
|
|
|
output_attributes.emplace(index, id); |
|
|
|
interfaces.push_back(id); |
|
|
|
|
|
|
|
Decorate(id, spv::Decoration::Location, location); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareConstantBuffers() { |
|
|
|
u32 binding = const_buffers_base_binding; |
|
|
|
for (const auto& entry : ir.GetConstantBuffers()) { |
|
|
|
const auto [index, size] = entry; |
|
|
|
const Id id = OpVariable(t_cbuf_ubo, spv::StorageClass::Uniform); |
|
|
|
AddGlobalVariable(Name(id, fmt::format("cbuf_{}", index))); |
|
|
|
|
|
|
|
Decorate(id, spv::Decoration::Binding, binding++); |
|
|
|
Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); |
|
|
|
constant_buffers.emplace(index, id); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareGlobalBuffers() { |
|
|
|
u32 binding = global_buffers_base_binding; |
|
|
|
for (const auto& entry : ir.GetGlobalMemoryBases()) { |
|
|
|
const Id id = OpVariable(t_gmem_ssbo, spv::StorageClass::StorageBuffer); |
|
|
|
AddGlobalVariable( |
|
|
|
Name(id, fmt::format("gmem_{}_{}", entry.cbuf_index, entry.cbuf_offset))); |
|
|
|
|
|
|
|
Decorate(id, spv::Decoration::Binding, binding++); |
|
|
|
Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); |
|
|
|
global_buffers.emplace(entry, id); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareSamplers() { |
|
|
|
u32 binding = samplers_base_binding; |
|
|
|
for (const auto& sampler : ir.GetSamplers()) { |
|
|
|
const auto dim = GetSamplerDim(sampler); |
|
|
|
const int depth = sampler.IsShadow() ? 1 : 0; |
|
|
|
const int arrayed = sampler.IsArray() ? 1 : 0; |
|
|
|
// TODO(Rodrigo): Sampled 1 indicates that the image will be used with a sampler. When
|
|
|
|
// SULD and SUST instructions are implemented, replace this value.
|
|
|
|
const int sampled = 1; |
|
|
|
const Id image_type = |
|
|
|
TypeImage(t_float, dim, depth, arrayed, false, sampled, spv::ImageFormat::Unknown); |
|
|
|
const Id sampled_image_type = TypeSampledImage(image_type); |
|
|
|
const Id pointer_type = |
|
|
|
TypePointer(spv::StorageClass::UniformConstant, sampled_image_type); |
|
|
|
const Id id = OpVariable(pointer_type, spv::StorageClass::UniformConstant); |
|
|
|
AddGlobalVariable(Name(id, fmt::format("sampler_{}", sampler.GetIndex()))); |
|
|
|
|
|
|
|
sampler_images.insert( |
|
|
|
{static_cast<u32>(sampler.GetIndex()), {image_type, sampled_image_type, id}}); |
|
|
|
|
|
|
|
Decorate(id, spv::Decoration::Binding, binding++); |
|
|
|
Decorate(id, spv::Decoration::DescriptorSet, DESCRIPTOR_SET); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void DeclareVertexRedeclarations() { |
|
|
|
vertex_index = DeclareBuiltIn(spv::BuiltIn::VertexIndex, spv::StorageClass::Input, |
|
|
|
t_in_uint, "vertex_index"); |
|
|
|
instance_index = DeclareBuiltIn(spv::BuiltIn::InstanceIndex, spv::StorageClass::Input, |
|
|
|
t_in_uint, "instance_index"); |
|
|
|
|
|
|
|
bool is_point_size_declared = false; |
|
|
|
bool is_clip_distances_declared = false; |
|
|
|
for (const auto index : ir.GetOutputAttributes()) { |
|
|
|
if (index == Attribute::Index::PointSize) { |
|
|
|
is_point_size_declared = true; |
|
|
|
} else if (index == Attribute::Index::ClipDistances0123 || |
|
|
|
index == Attribute::Index::ClipDistances4567) { |
|
|
|
is_clip_distances_declared = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<Id> members; |
|
|
|
members.push_back(t_float4); |
|
|
|
if (is_point_size_declared) { |
|
|
|
members.push_back(t_float); |
|
|
|
} |
|
|
|
if (is_clip_distances_declared) { |
|
|
|
members.push_back(TypeArray(t_float, Constant(t_uint, 8))); |
|
|
|
} |
|
|
|
|
|
|
|
const Id gl_per_vertex_struct = Name(TypeStruct(members), "PerVertex"); |
|
|
|
Decorate(gl_per_vertex_struct, spv::Decoration::Block); |
|
|
|
|
|
|
|
u32 declaration_index = 0; |
|
|
|
const auto MemberDecorateBuiltIn = [&](spv::BuiltIn builtin, std::string name, |
|
|
|
bool condition) { |
|
|
|
if (!condition) |
|
|
|
return u32{}; |
|
|
|
MemberName(gl_per_vertex_struct, declaration_index, name); |
|
|
|
MemberDecorate(gl_per_vertex_struct, declaration_index, spv::Decoration::BuiltIn, |
|
|
|
static_cast<u32>(builtin)); |
|
|
|
return declaration_index++; |
|
|
|
}; |
|
|
|
|
|
|
|
position_index = MemberDecorateBuiltIn(spv::BuiltIn::Position, "position", true); |
|
|
|
point_size_index = |
|
|
|
MemberDecorateBuiltIn(spv::BuiltIn::PointSize, "point_size", is_point_size_declared); |
|
|
|
clip_distances_index = MemberDecorateBuiltIn(spv::BuiltIn::ClipDistance, "clip_distances", |
|
|
|
is_clip_distances_declared); |
|
|
|
|
|
|
|
const Id type_pointer = TypePointer(spv::StorageClass::Output, gl_per_vertex_struct); |
|
|
|
per_vertex = OpVariable(type_pointer, spv::StorageClass::Output); |
|
|
|
AddGlobalVariable(Name(per_vertex, "per_vertex")); |
|
|
|
interfaces.push_back(per_vertex); |
|
|
|
} |
|
|
|
|
|
|
|
Id DeclareBuiltIn(spv::BuiltIn builtin, spv::StorageClass storage, Id type, |
|
|
|
const std::string& name) { |
|
|
|
const Id id = OpVariable(type, storage); |
|
|
|
Decorate(id, spv::Decoration::BuiltIn, static_cast<u32>(builtin)); |
|
|
|
AddGlobalVariable(Name(id, name)); |
|
|
|
interfaces.push_back(id); |
|
|
|
return id; |
|
|
|
} |
|
|
|
|
|
|
|
bool IsRenderTargetUsed(u32 rt) const { |
|
|
|
for (u32 component = 0; component < 4; ++component) { |
|
|
|
if (header.ps.IsColorComponentOutputEnabled(rt, component)) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
const ShaderIR& ir; |
|
|
|
const ShaderStage stage; |
|
|
|
const Tegra::Shader::Header header; |
|
|
|
|
|
|
|
const Id t_void = Name(TypeVoid(), "void"); |
|
|
|
|
|
|
|
const Id t_bool = Name(TypeBool(), "bool"); |
|
|
|
const Id t_bool2 = Name(TypeVector(t_bool, 2), "bool2"); |
|
|
|
|
|
|
|
const Id t_int = Name(TypeInt(32, true), "int"); |
|
|
|
const Id t_int2 = Name(TypeVector(t_int, 2), "int2"); |
|
|
|
const Id t_int3 = Name(TypeVector(t_int, 3), "int3"); |
|
|
|
const Id t_int4 = Name(TypeVector(t_int, 4), "int4"); |
|
|
|
|
|
|
|
const Id t_uint = Name(TypeInt(32, false), "uint"); |
|
|
|
const Id t_uint2 = Name(TypeVector(t_uint, 2), "uint2"); |
|
|
|
const Id t_uint3 = Name(TypeVector(t_uint, 3), "uint3"); |
|
|
|
const Id t_uint4 = Name(TypeVector(t_uint, 4), "uint4"); |
|
|
|
|
|
|
|
const Id t_float = Name(TypeFloat(32), "float"); |
|
|
|
const Id t_float2 = Name(TypeVector(t_float, 2), "float2"); |
|
|
|
const Id t_float3 = Name(TypeVector(t_float, 3), "float3"); |
|
|
|
const Id t_float4 = Name(TypeVector(t_float, 4), "float4"); |
|
|
|
|
|
|
|
const Id t_prv_bool = Name(TypePointer(spv::StorageClass::Private, t_bool), "prv_bool"); |
|
|
|
const Id t_prv_float = Name(TypePointer(spv::StorageClass::Private, t_float), "prv_float"); |
|
|
|
|
|
|
|
const Id t_in_bool = Name(TypePointer(spv::StorageClass::Input, t_bool), "in_bool"); |
|
|
|
const Id t_in_uint = Name(TypePointer(spv::StorageClass::Input, t_uint), "in_uint"); |
|
|
|
const Id t_in_float = Name(TypePointer(spv::StorageClass::Input, t_float), "in_float"); |
|
|
|
const Id t_in_float4 = Name(TypePointer(spv::StorageClass::Input, t_float4), "in_float4"); |
|
|
|
|
|
|
|
const Id t_out_float = Name(TypePointer(spv::StorageClass::Output, t_float), "out_float"); |
|
|
|
const Id t_out_float4 = Name(TypePointer(spv::StorageClass::Output, t_float4), "out_float4"); |
|
|
|
|
|
|
|
const Id t_cbuf_float = TypePointer(spv::StorageClass::Uniform, t_float); |
|
|
|
const Id t_cbuf_array = |
|
|
|
Decorate(Name(TypeArray(t_float4, Constant(t_uint, MAX_CONSTBUFFER_ELEMENTS)), "CbufArray"), |
|
|
|
spv::Decoration::ArrayStride, CBUF_STRIDE); |
|
|
|
const Id t_cbuf_struct = MemberDecorate( |
|
|
|
Decorate(TypeStruct(t_cbuf_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0); |
|
|
|
const Id t_cbuf_ubo = TypePointer(spv::StorageClass::Uniform, t_cbuf_struct); |
|
|
|
|
|
|
|
const Id t_gmem_float = TypePointer(spv::StorageClass::StorageBuffer, t_float); |
|
|
|
const Id t_gmem_array = |
|
|
|
Name(Decorate(TypeRuntimeArray(t_float), spv::Decoration::ArrayStride, 4u), "GmemArray"); |
|
|
|
const Id t_gmem_struct = MemberDecorate( |
|
|
|
Decorate(TypeStruct(t_gmem_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0); |
|
|
|
const Id t_gmem_ssbo = TypePointer(spv::StorageClass::StorageBuffer, t_gmem_struct); |
|
|
|
|
|
|
|
const Id v_float_zero = Constant(t_float, 0.0f); |
|
|
|
const Id v_true = ConstantTrue(t_bool); |
|
|
|
const Id v_false = ConstantFalse(t_bool); |
|
|
|
|
|
|
|
Id per_vertex{}; |
|
|
|
std::map<u32, Id> registers; |
|
|
|
std::map<Tegra::Shader::Pred, Id> predicates; |
|
|
|
Id local_memory{}; |
|
|
|
std::array<Id, INTERNAL_FLAGS_COUNT> internal_flags{}; |
|
|
|
std::map<Attribute::Index, Id> input_attributes; |
|
|
|
std::map<Attribute::Index, Id> output_attributes; |
|
|
|
std::map<u32, Id> constant_buffers; |
|
|
|
std::map<GlobalMemoryBase, Id> global_buffers; |
|
|
|
std::map<u32, SamplerImage> sampler_images; |
|
|
|
|
|
|
|
Id instance_index{}; |
|
|
|
Id vertex_index{}; |
|
|
|
std::array<Id, Maxwell::NumRenderTargets> frag_colors{}; |
|
|
|
Id frag_depth{}; |
|
|
|
Id frag_coord{}; |
|
|
|
Id front_facing{}; |
|
|
|
|
|
|
|
u32 position_index{}; |
|
|
|
u32 point_size_index{}; |
|
|
|
u32 clip_distances_index{}; |
|
|
|
|
|
|
|
std::vector<Id> interfaces; |
|
|
|
|
|
|
|
u32 const_buffers_base_binding{}; |
|
|
|
u32 global_buffers_base_binding{}; |
|
|
|
u32 samplers_base_binding{}; |
|
|
|
|
|
|
|
Id execute_function{}; |
|
|
|
}; |
|
|
|
|
|
|
|
DecompilerResult Decompile(const VideoCommon::Shader::ShaderIR& ir, Maxwell::ShaderStage stage) { |
|
|
|
|