diff options
Diffstat (limited to 'src/shader_recompiler')
17 files changed, 217 insertions, 24 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 545d69c7e..525b2363c 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt @@ -221,6 +221,7 @@ add_library(shader_recompiler STATIC ir_opt/dual_vertex_pass.cpp ir_opt/global_memory_to_storage_buffer_pass.cpp ir_opt/identity_removal_pass.cpp + ir_opt/layer_pass.cpp ir_opt/lower_fp16_to_fp32.cpp ir_opt/lower_int64_to_int32.cpp ir_opt/passes.h @@ -230,6 +231,7 @@ add_library(shader_recompiler STATIC ir_opt/texture_pass.cpp ir_opt/verification_pass.cpp object_pool.h + precompiled_headers.h profile.h program_header.h runtime_info.h @@ -254,7 +256,12 @@ else() # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6. # And this in turns limits the size of a std::array. $<$<CXX_COMPILER_ID:Clang>:-fbracket-depth=1024> + $<$<CXX_COMPILER_ID:AppleClang>:-fbracket-depth=1024> ) endif() create_target_directory_groups(shader_recompiler) + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(shader_recompiler PRIVATE precompiled_headers.h) +endif() diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 265ac9c85..0f86a8004 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -402,8 +402,10 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct ctx.AddCapability(spv::Capability::SparseResidency); } if (info.uses_demote_to_helper_invocation && profile.support_demote_to_helper_invocation) { - ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); - ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT); + if (profile.supported_spirv < 0x00010600) { + ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); + } + ctx.AddCapability(spv::Capability::DemoteToHelperInvocation); } if (info.stores[IR::Attribute::ViewportIndex]) { ctx.AddCapability(spv::Capability::MultiViewport); @@ -426,12 +428,11 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles) && profile.support_vote) { - ctx.AddExtension("SPV_KHR_shader_ballot"); - ctx.AddCapability(spv::Capability::SubgroupBallotKHR); + ctx.AddCapability(spv::Capability::GroupNonUniformBallot); + ctx.AddCapability(spv::Capability::GroupNonUniformShuffle); if (!profile.warp_size_potentially_larger_than_guest) { // vote ops are only used when not taking the long path - ctx.AddExtension("SPV_KHR_subgroup_vote"); - ctx.AddCapability(spv::Capability::SubgroupVoteKHR); + ctx.AddCapability(spv::Capability::GroupNonUniformVote); } } if (info.uses_int64_bit_atomics && profile.support_int64_atomics) { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp index 7ad0b08ac..fb2c792c1 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp @@ -12,7 +12,7 @@ void EmitJoin(EmitContext&) { void EmitDemoteToHelperInvocation(EmitContext& ctx) { if (ctx.profile.support_demote_to_helper_invocation) { - ctx.OpDemoteToHelperInvocationEXT(); + ctx.OpDemoteToHelperInvocation(); } else { const Id kill_label{ctx.OpLabel()}; const Id impossible_label{ctx.OpLabel()}; diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp index 7cbbbfaa6..2c90f2368 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp @@ -6,6 +6,10 @@ namespace Shader::Backend::SPIRV { namespace { +Id SubgroupScope(EmitContext& ctx) { + return ctx.Const(static_cast<u32>(spv::Scope::Subgroup)); +} + Id GetThreadId(EmitContext& ctx) { return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id); } @@ -49,8 +53,9 @@ Id GetMaxThreadId(EmitContext& ctx, Id thread_id, Id clamp, Id segmentation_mask } Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) { - return ctx.OpSelect(ctx.U32[1], in_range, - ctx.OpSubgroupReadInvocationKHR(ctx.U32[1], value, src_thread_id), value); + return ctx.OpSelect( + ctx.U32[1], in_range, + ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value); } Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) { @@ -71,40 +76,46 @@ Id EmitLaneId(EmitContext& ctx) { Id EmitVoteAll(EmitContext& ctx, Id pred) { if (!ctx.profile.warp_size_potentially_larger_than_guest) { - return ctx.OpSubgroupAllKHR(ctx.U1, pred); + return ctx.OpGroupNonUniformAll(ctx.U1, SubgroupScope(ctx), pred); } - const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; + const Id mask_ballot{ + ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; const Id active_mask{WarpExtract(ctx, mask_ballot)}; - const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; + const Id ballot{ + WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; return ctx.OpIEqual(ctx.U1, lhs, active_mask); } Id EmitVoteAny(EmitContext& ctx, Id pred) { if (!ctx.profile.warp_size_potentially_larger_than_guest) { - return ctx.OpSubgroupAnyKHR(ctx.U1, pred); + return ctx.OpGroupNonUniformAny(ctx.U1, SubgroupScope(ctx), pred); } - const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; + const Id mask_ballot{ + ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; const Id active_mask{WarpExtract(ctx, mask_ballot)}; - const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; + const Id ballot{ + WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)}; return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value); } Id EmitVoteEqual(EmitContext& ctx, Id pred) { if (!ctx.profile.warp_size_potentially_larger_than_guest) { - return ctx.OpSubgroupAllEqualKHR(ctx.U1, pred); + return ctx.OpGroupNonUniformAllEqual(ctx.U1, SubgroupScope(ctx), pred); } - const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; + const Id mask_ballot{ + ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)}; const Id active_mask{WarpExtract(ctx, mask_ballot)}; - const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; + const Id ballot{ + WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))}; const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)}; return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value), ctx.OpIEqual(ctx.U1, lhs, active_mask)); } Id EmitSubgroupBallot(EmitContext& ctx, Id pred) { - const Id ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], pred)}; + const Id ballot{ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred)}; if (!ctx.profile.warp_size_potentially_larger_than_guest) { return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U); } diff --git a/src/shader_recompiler/frontend/ir/opcodes.h b/src/shader_recompiler/frontend/ir/opcodes.h index e70d7745c..d155afd0f 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.h +++ b/src/shader_recompiler/frontend/ir/opcodes.h @@ -8,6 +8,7 @@ #include <fmt/format.h> +#include "common/polyfill_ranges.h" #include "shader_recompiler/frontend/ir/type.h" namespace Shader::IR { diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index e8bbb93a5..8b34356fd 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h @@ -23,7 +23,6 @@ #include "shader_recompiler/frontend/ir/pred.h" #include "shader_recompiler/frontend/ir/reg.h" #include "shader_recompiler/frontend/ir/type.h" -#include "shader_recompiler/frontend/ir/value.h" namespace Shader::IR { diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.cpp b/src/shader_recompiler/frontend/maxwell/control_flow.cpp index 6939692cd..dce414cb4 100644 --- a/src/shader_recompiler/frontend/maxwell/control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/control_flow.cpp @@ -9,6 +9,7 @@ #include <fmt/format.h> +#include "common/polyfill_ranges.h" #include "shader_recompiler/exception.h" #include "shader_recompiler/frontend/maxwell/control_flow.h" #include "shader_recompiler/frontend/maxwell/decode.h" diff --git a/src/shader_recompiler/frontend/maxwell/decode.cpp b/src/shader_recompiler/frontend/maxwell/decode.cpp index 455c91470..774f65bc5 100644 --- a/src/shader_recompiler/frontend/maxwell/decode.cpp +++ b/src/shader_recompiler/frontend/maxwell/decode.cpp @@ -7,6 +7,7 @@ #include <memory> #include "common/common_types.h" +#include "common/polyfill_ranges.h" #include "shader_recompiler/exception.h" #include "shader_recompiler/frontend/maxwell/decode.h" #include "shader_recompiler/frontend/maxwell/opcodes.h" diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp index ce42475d4..80c90fe6a 100644 --- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp @@ -12,6 +12,7 @@ #include <boost/intrusive/list.hpp> +#include "common/polyfill_ranges.h" #include "shader_recompiler/environment.h" #include "shader_recompiler/frontend/ir/basic_block.h" #include "shader_recompiler/frontend/ir/ir_emitter.h" diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp index 4942878b9..85c18d942 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp @@ -176,12 +176,13 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) { (f2i.src_format == SrcFormat::F64) != (f2i.dest_format == DestFormat::I64); if (special_nan_cases) { if (f2i.dest_format == DestFormat::I32) { + constexpr u32 nan_value = 0x8000'0000U; handled_special_case = true; - result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(0x8000'0000U), result)}; + result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(nan_value), result)}; } else if (f2i.dest_format == DestFormat::I64) { + constexpr u64 nan_value = 0x8000'0000'0000'0000ULL; handled_special_case = true; - result = IR::U64{ - v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(0x8000'0000'0000'0000UL), result)}; + result = IR::U64{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(nan_value), result)}; } } if (!handled_special_case && is_signed) { diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 376aae0ea..3adbd2b16 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp @@ -9,6 +9,7 @@ #include "common/settings.h" #include "shader_recompiler/exception.h" #include "shader_recompiler/frontend/ir/basic_block.h" +#include "shader_recompiler/frontend/ir/ir_emitter.h" #include "shader_recompiler/frontend/ir/post_order.h" #include "shader_recompiler/frontend/maxwell/structured_control_flow.h" #include "shader_recompiler/frontend/maxwell/translate/translate.h" @@ -233,6 +234,8 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo Optimization::VerificationPass(program); } Optimization::CollectShaderInfoPass(env, program); + Optimization::LayerPass(program, host_info); + CollectInterpolationInfo(env, program); AddNVNStorageBuffers(program); return program; @@ -331,4 +334,82 @@ void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& run } } +IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool, + ObjectPool<IR::Block>& block_pool, + const HostTranslateInfo& host_info, + IR::Program& source_program, + Shader::OutputTopology output_topology) { + IR::Program program; + program.stage = Stage::Geometry; + program.output_topology = output_topology; + switch (output_topology) { + case OutputTopology::PointList: + program.output_vertices = 1; + break; + case OutputTopology::LineStrip: + program.output_vertices = 2; + break; + default: + program.output_vertices = 3; + break; + } + + program.is_geometry_passthrough = false; + program.info.loads.mask = source_program.info.stores.mask; + program.info.stores.mask = source_program.info.stores.mask; + program.info.stores.Set(IR::Attribute::Layer, true); + program.info.stores.Set(source_program.info.emulated_layer, false); + + IR::Block* current_block = block_pool.Create(inst_pool); + auto& node{program.syntax_list.emplace_back()}; + node.type = IR::AbstractSyntaxNode::Type::Block; + node.data.block = current_block; + + IR::IREmitter ir{*current_block}; + for (u32 i = 0; i < program.output_vertices; i++) { + // Assign generics from input + for (u32 j = 0; j < 32; j++) { + if (!program.info.stores.Generic(j)) { + continue; + } + + const IR::Attribute attr = IR::Attribute::Generic0X + (j * 4); + ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); + } + + // Assign position from input + const IR::Attribute attr = IR::Attribute::PositionX; + ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); + ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); + + // Assign layer + ir.SetAttribute(IR::Attribute::Layer, ir.GetAttribute(source_program.info.emulated_layer), + ir.Imm32(0)); + + // Emit vertex + ir.EmitVertex(ir.Imm32(0)); + } + ir.EndPrimitive(ir.Imm32(0)); + + IR::Block* return_block{block_pool.Create(inst_pool)}; + IR::IREmitter{*return_block}.Epilogue(); + current_block->AddBranch(return_block); + + auto& merge{program.syntax_list.emplace_back()}; + merge.type = IR::AbstractSyntaxNode::Type::Block; + merge.data.block = return_block; + program.syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Return; + + program.blocks = GenerateBlocks(program.syntax_list); + program.post_order_blocks = PostOrder(program.syntax_list.front()); + Optimization::SsaRewritePass(program); + + return program; +} + } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.h b/src/shader_recompiler/frontend/maxwell/translate_program.h index 02ede8c9c..497afe7cb 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.h +++ b/src/shader_recompiler/frontend/maxwell/translate_program.h @@ -25,4 +25,13 @@ namespace Shader::Maxwell { void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_info); +// Maxwell v1 and older Nvidia cards don't support setting gl_Layer from non-geometry stages. +// This creates a workaround by setting the layer as a generic output and creating a +// passthrough geometry shader that reads the generic and sets the layer. +[[nodiscard]] IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool, + ObjectPool<IR::Block>& block_pool, + const HostTranslateInfo& host_info, + IR::Program& source_program, + Shader::OutputTopology output_topology); + } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/host_translate_info.h b/src/shader_recompiler/host_translate_info.h index cc1500690..d5d279554 100644 --- a/src/shader_recompiler/host_translate_info.h +++ b/src/shader_recompiler/host_translate_info.h @@ -13,7 +13,8 @@ struct HostTranslateInfo { bool support_float16{}; ///< True when the device supports 16-bit floats bool support_int64{}; ///< True when the device supports 64-bit integers bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered - bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers + bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers + bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS }; } // namespace Shader diff --git a/src/shader_recompiler/ir_opt/layer_pass.cpp b/src/shader_recompiler/ir_opt/layer_pass.cpp new file mode 100644 index 000000000..4574f7cf2 --- /dev/null +++ b/src/shader_recompiler/ir_opt/layer_pass.cpp @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <algorithm> +#include <bit> +#include <optional> + +#include <boost/container/small_vector.hpp> + +#include "shader_recompiler/environment.h" +#include "shader_recompiler/frontend/ir/basic_block.h" +#include "shader_recompiler/frontend/ir/breadth_first_search.h" +#include "shader_recompiler/frontend/ir/ir_emitter.h" +#include "shader_recompiler/host_translate_info.h" +#include "shader_recompiler/ir_opt/passes.h" +#include "shader_recompiler/shader_info.h" + +namespace Shader::Optimization { + +static IR::Attribute EmulatedLayerAttribute(VaryingState& stores) { + for (u32 i = 0; i < 32; i++) { + if (!stores.Generic(i)) { + return IR::Attribute::Generic0X + (i * 4); + } + } + return IR::Attribute::Layer; +} + +static bool PermittedProgramStage(Stage stage) { + switch (stage) { + case Stage::VertexA: + case Stage::VertexB: + case Stage::TessellationControl: + case Stage::TessellationEval: + return true; + default: + return false; + } +} + +void LayerPass(IR::Program& program, const HostTranslateInfo& host_info) { + if (host_info.support_viewport_index_layer || !PermittedProgramStage(program.stage)) { + return; + } + + const auto end{program.post_order_blocks.end()}; + const auto layer_attribute = EmulatedLayerAttribute(program.info.stores); + bool requires_layer_emulation = false; + + for (auto block = program.post_order_blocks.begin(); block != end; ++block) { + for (IR::Inst& inst : (*block)->Instructions()) { + if (inst.GetOpcode() == IR::Opcode::SetAttribute && + inst.Arg(0).Attribute() == IR::Attribute::Layer) { + requires_layer_emulation = true; + inst.SetArg(0, IR::Value{layer_attribute}); + } + } + } + + if (requires_layer_emulation) { + program.info.requires_layer_emulation = true; + program.info.emulated_layer = layer_attribute; + program.info.stores.Set(IR::Attribute::Layer, false); + program.info.stores.Set(layer_attribute, true); + } +} + +} // namespace Shader::Optimization diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index 586a0668f..11bfe801a 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h @@ -23,6 +23,7 @@ void RescalingPass(IR::Program& program); void SsaRewritePass(IR::Program& program); void PositionPass(Environment& env, IR::Program& program); void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info); +void LayerPass(IR::Program& program, const HostTranslateInfo& host_info); void VerificationPass(const IR::Program& program); // Dual Vertex diff --git a/src/shader_recompiler/precompiled_headers.h b/src/shader_recompiler/precompiled_headers.h new file mode 100644 index 000000000..5dd6b7eca --- /dev/null +++ b/src/shader_recompiler/precompiled_headers.h @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" +#include "frontend/maxwell/translate/impl/impl.h" diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index ee6252bb5..d9c6e92db 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h @@ -204,6 +204,9 @@ struct Info { u32 nvn_buffer_base{}; std::bitset<16> nvn_buffer_used{}; + bool requires_layer_emulation{}; + IR::Attribute emulated_layer{}; + boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> constant_buffer_descriptors; boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; |