shader: Implement NDC [-1, 1], attribute types and default varying initialization
This commit is contained in:
		| @@ -14,6 +14,7 @@ add_library(shader_recompiler STATIC | ||||
|     backend/spirv/emit_spirv_logical.cpp | ||||
|     backend/spirv/emit_spirv_memory.cpp | ||||
|     backend/spirv/emit_spirv_select.cpp | ||||
|     backend/spirv/emit_spirv_special.cpp | ||||
|     backend/spirv/emit_spirv_undefined.cpp | ||||
|     backend/spirv/emit_spirv_vote.cpp | ||||
|     environment.h | ||||
|   | ||||
| @@ -67,6 +67,18 @@ Id DefineInput(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin = | ||||
| Id DefineOutput(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin = std::nullopt) { | ||||
|     return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); | ||||
| } | ||||
|  | ||||
| Id GetAttributeType(EmitContext& ctx, AttributeType type) { | ||||
|     switch (type) { | ||||
|     case AttributeType::Float: | ||||
|         return ctx.F32[4]; | ||||
|     case AttributeType::SignedInt: | ||||
|         return ctx.TypeVector(ctx.TypeInt(32, true), 4); | ||||
|     case AttributeType::UnsignedInt: | ||||
|         return ctx.U32[4]; | ||||
|     } | ||||
|     throw InvalidArgument("Invalid attribute type {}", type); | ||||
| } | ||||
| } // Anonymous namespace | ||||
|  | ||||
| void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { | ||||
| @@ -82,11 +94,11 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie | ||||
| } | ||||
|  | ||||
| EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& binding) | ||||
|     : Sirit::Module(0x00010000), profile{profile_} { | ||||
|     : Sirit::Module(0x00010000), profile{profile_}, stage{program.stage} { | ||||
|     AddCapability(spv::Capability::Shader); | ||||
|     DefineCommonTypes(program.info); | ||||
|     DefineCommonConstants(); | ||||
|     DefineInterfaces(program.info, program.stage); | ||||
|     DefineInterfaces(program.info); | ||||
|     DefineConstantBuffers(program.info, binding); | ||||
|     DefineStorageBuffers(program.info, binding); | ||||
|     DefineTextures(program.info, binding); | ||||
| @@ -130,6 +142,9 @@ void EmitContext::DefineCommonTypes(const Info& info) { | ||||
|     U32.Define(*this, TypeInt(32, false), "u32"); | ||||
|  | ||||
|     input_f32 = Name(TypePointer(spv::StorageClass::Input, F32[1]), "input_f32"); | ||||
|     input_u32 = Name(TypePointer(spv::StorageClass::Input, U32[1]), "input_u32"); | ||||
|     input_s32 = Name(TypePointer(spv::StorageClass::Input, TypeInt(32, true)), "input_s32"); | ||||
|  | ||||
|     output_f32 = Name(TypePointer(spv::StorageClass::Output, F32[1]), "output_f32"); | ||||
|  | ||||
|     if (info.uses_int8) { | ||||
| @@ -162,9 +177,9 @@ void EmitContext::DefineCommonConstants() { | ||||
|     u32_zero_value = Constant(U32[1], 0U); | ||||
| } | ||||
|  | ||||
| void EmitContext::DefineInterfaces(const Info& info, Stage stage) { | ||||
|     DefineInputs(info, stage); | ||||
|     DefineOutputs(info, stage); | ||||
| void EmitContext::DefineInterfaces(const Info& info) { | ||||
|     DefineInputs(info); | ||||
|     DefineOutputs(info); | ||||
| } | ||||
|  | ||||
| void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { | ||||
| @@ -252,7 +267,7 @@ void EmitContext::DefineLabels(IR::Program& program) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmitContext::DefineInputs(const Info& info, Stage stage) { | ||||
| void EmitContext::DefineInputs(const Info& info) { | ||||
|     if (info.uses_workgroup_id) { | ||||
|         workgroup_id = DefineInput(*this, U32[3], spv::BuiltIn::WorkgroupId); | ||||
|     } | ||||
| @@ -288,8 +303,8 @@ void EmitContext::DefineInputs(const Info& info, Stage stage) { | ||||
|         if (!info.loads_generics[index]) { | ||||
|             continue; | ||||
|         } | ||||
|         // FIXME: Declare size from input | ||||
|         const Id id{DefineInput(*this, F32[4])}; | ||||
|         const Id type{GetAttributeType(*this, profile.generic_input_types[index])}; | ||||
|         const Id id{DefineInput(*this, type)}; | ||||
|         Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); | ||||
|         Name(id, fmt::format("in_attr{}", index)); | ||||
|         input_generics[index] = id; | ||||
| @@ -323,8 +338,8 @@ void EmitContext::DefineConstantBuffers(const Info& info, Id UniformDefinitions: | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmitContext::DefineOutputs(const Info& info, Stage stage) { | ||||
|     if (info.stores_position) { | ||||
| void EmitContext::DefineOutputs(const Info& info) { | ||||
|     if (info.stores_position || stage == Stage::VertexB) { | ||||
|         output_position = DefineOutput(*this, F32[4], spv::BuiltIn::Position); | ||||
|     } | ||||
|     for (size_t i = 0; i < info.stores_generics.size(); ++i) { | ||||
|   | ||||
| @@ -52,6 +52,7 @@ public: | ||||
|     [[nodiscard]] Id Def(const IR::Value& value); | ||||
|  | ||||
|     const Profile& profile; | ||||
|     Stage stage{}; | ||||
|  | ||||
|     Id void_id{}; | ||||
|     Id U1{}; | ||||
| @@ -72,6 +73,9 @@ public: | ||||
|     UniformDefinitions uniform_types; | ||||
|  | ||||
|     Id input_f32{}; | ||||
|     Id input_u32{}; | ||||
|     Id input_s32{}; | ||||
|  | ||||
|     Id output_f32{}; | ||||
|  | ||||
|     Id storage_u32{}; | ||||
| @@ -104,7 +108,7 @@ public: | ||||
| private: | ||||
|     void DefineCommonTypes(const Info& info); | ||||
|     void DefineCommonConstants(); | ||||
|     void DefineInterfaces(const Info& info, Stage stage); | ||||
|     void DefineInterfaces(const Info& info); | ||||
|     void DefineConstantBuffers(const Info& info, u32& binding); | ||||
|     void DefineStorageBuffers(const Info& info, u32& binding); | ||||
|     void DefineTextures(const Info& info, u32& binding); | ||||
| @@ -113,8 +117,8 @@ private: | ||||
|     void DefineConstantBuffers(const Info& info, Id UniformDefinitions::*member_type, u32 binding, | ||||
|                                Id type, char type_char, u32 element_size); | ||||
|  | ||||
|     void DefineInputs(const Info& info, Stage stage); | ||||
|     void DefineOutputs(const Info& info, Stage stage); | ||||
|     void DefineInputs(const Info& info); | ||||
|     void DefineOutputs(const Info& info); | ||||
| }; | ||||
|  | ||||
| } // namespace Shader::Backend::SPIRV | ||||
|   | ||||
| @@ -28,6 +28,8 @@ void EmitLoopMerge(EmitContext& ctx, Id merge_label, Id continue_label); | ||||
| void EmitSelectionMerge(EmitContext& ctx, Id merge_label); | ||||
| void EmitReturn(EmitContext& ctx); | ||||
| void EmitDemoteToHelperInvocation(EmitContext& ctx, Id continue_label); | ||||
| void EmitPrologue(EmitContext& ctx); | ||||
| void EmitEpilogue(EmitContext& ctx); | ||||
| void EmitGetRegister(EmitContext& ctx); | ||||
| void EmitSetRegister(EmitContext& ctx); | ||||
| void EmitGetPred(EmitContext& ctx); | ||||
|   | ||||
| @@ -2,30 +2,26 @@ | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <tuple> | ||||
|  | ||||
| #include "shader_recompiler/backend/spirv/emit_spirv.h" | ||||
|  | ||||
| #pragma optimize("", off) | ||||
|  | ||||
| namespace Shader::Backend::SPIRV { | ||||
| namespace { | ||||
| Id InputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | ||||
|     const u32 element{static_cast<u32>(attr) % 4}; | ||||
|     const auto element_id{[&] { return ctx.Constant(ctx.U32[1], element); }}; | ||||
|     if (IR::IsGeneric(attr)) { | ||||
|         const u32 index{IR::GenericAttributeIndex(attr)}; | ||||
|         return ctx.OpAccessChain(ctx.input_f32, ctx.input_generics.at(index), element_id()); | ||||
|     } | ||||
|     switch (attr) { | ||||
|     case IR::Attribute::PositionX: | ||||
|     case IR::Attribute::PositionY: | ||||
|     case IR::Attribute::PositionZ: | ||||
|     case IR::Attribute::PositionW: | ||||
|         return ctx.OpAccessChain(ctx.input_f32, ctx.input_position, element_id()); | ||||
|     case IR::Attribute::InstanceId: | ||||
|         return ctx.OpLoad(ctx.U32[1], ctx.instance_id); | ||||
|     case IR::Attribute::VertexId: | ||||
|         return ctx.OpLoad(ctx.U32[1], ctx.vertex_id); | ||||
|     default: | ||||
|         throw NotImplementedException("Read attribute {}", attr); | ||||
| std::tuple<Id, Id, bool> AttrTypes(EmitContext& ctx, u32 index) { | ||||
|     const bool is_first_reader{ctx.stage == Stage::VertexB}; | ||||
|     const AttributeType type{ctx.profile.generic_input_types.at(index)}; | ||||
|     switch (type) { | ||||
|     case AttributeType::Float: | ||||
|         return {ctx.input_f32, ctx.F32[1], false}; | ||||
|     case AttributeType::UnsignedInt: | ||||
|         return {ctx.input_u32, ctx.U32[1], true}; | ||||
|     case AttributeType::SignedInt: | ||||
|         return {ctx.input_s32, ctx.TypeInt(32, true), true}; | ||||
|     } | ||||
|     throw InvalidArgument("Invalid attribute type {}", type); | ||||
| } | ||||
|  | ||||
| Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | ||||
| @@ -129,20 +125,41 @@ Id EmitGetCbufU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& o | ||||
| } | ||||
|  | ||||
| Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr) { | ||||
|     if (!ctx.profile.support_vertex_instance_id) { | ||||
|     const u32 element{static_cast<u32>(attr) % 4}; | ||||
|     const auto element_id{[&] { return ctx.Constant(ctx.U32[1], element); }}; | ||||
|     if (IR::IsGeneric(attr)) { | ||||
|         const u32 index{IR::GenericAttributeIndex(attr)}; | ||||
|         const auto [pointer_type, type, needs_cast]{AttrTypes(ctx, index)}; | ||||
|         const Id generic_id{ctx.input_generics.at(index)}; | ||||
|         const Id pointer{ctx.OpAccessChain(pointer_type, generic_id, element_id())}; | ||||
|         const Id value{ctx.OpLoad(type, pointer)}; | ||||
|         return needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value; | ||||
|     } | ||||
|     switch (attr) { | ||||
|     case IR::Attribute::PositionX: | ||||
|     case IR::Attribute::PositionY: | ||||
|     case IR::Attribute::PositionZ: | ||||
|     case IR::Attribute::PositionW: | ||||
|         return ctx.OpLoad(ctx.F32[1], | ||||
|                           ctx.OpAccessChain(ctx.input_f32, ctx.input_position, element_id())); | ||||
|     case IR::Attribute::InstanceId: | ||||
|         if (ctx.profile.support_vertex_instance_id) { | ||||
|             return ctx.OpLoad(ctx.U32[1], ctx.instance_id); | ||||
|         } else { | ||||
|             return ctx.OpISub(ctx.U32[1], ctx.OpLoad(ctx.U32[1], ctx.instance_index), | ||||
|                               ctx.OpLoad(ctx.U32[1], ctx.base_instance)); | ||||
|         } | ||||
|     case IR::Attribute::VertexId: | ||||
|         if (ctx.profile.support_vertex_instance_id) { | ||||
|             return ctx.OpLoad(ctx.U32[1], ctx.vertex_id); | ||||
|         } else { | ||||
|             return ctx.OpISub(ctx.U32[1], ctx.OpLoad(ctx.U32[1], ctx.vertex_index), | ||||
|                               ctx.OpLoad(ctx.U32[1], ctx.base_vertex)); | ||||
|         } | ||||
|     default: | ||||
|             break; | ||||
|         throw NotImplementedException("Read attribute {}", attr); | ||||
|     } | ||||
| } | ||||
|     return ctx.OpLoad(ctx.F32[1], InputAttrPointer(ctx, attr)); | ||||
| } | ||||
|  | ||||
| void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value) { | ||||
|     ctx.OpStore(OutputAttrPointer(ctx, attr), value); | ||||
|   | ||||
							
								
								
									
										35
									
								
								src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| // Copyright 2021 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include "shader_recompiler/backend/spirv/emit_spirv.h" | ||||
|  | ||||
| namespace Shader::Backend::SPIRV { | ||||
|  | ||||
| void EmitPrologue(EmitContext& ctx) { | ||||
|     if (ctx.stage == Stage::VertexB) { | ||||
|         const Id zero{ctx.Constant(ctx.F32[1], 0.0f)}; | ||||
|         const Id one{ctx.Constant(ctx.F32[1], 1.0f)}; | ||||
|         const Id null_vector{ctx.ConstantComposite(ctx.F32[4], zero, zero, zero, zero)}; | ||||
|         ctx.OpStore(ctx.output_position, ctx.ConstantComposite(ctx.F32[4], zero, zero, zero, one)); | ||||
|         for (const Id generic_id : ctx.output_generics) { | ||||
|             if (Sirit::ValidId(generic_id)) { | ||||
|                 ctx.OpStore(generic_id, null_vector); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmitEpilogue(EmitContext& ctx) { | ||||
|     if (ctx.profile.convert_depth_mode) { | ||||
|         const Id type{ctx.F32[1]}; | ||||
|         const Id position{ctx.OpLoad(ctx.F32[4], ctx.output_position)}; | ||||
|         const Id z{ctx.OpCompositeExtract(type, position, 2u)}; | ||||
|         const Id w{ctx.OpCompositeExtract(type, position, 3u)}; | ||||
|         const Id screen_depth{ctx.OpFMul(type, ctx.OpFAdd(type, z, w), ctx.Constant(type, 0.5f))}; | ||||
|         const Id vector{ctx.OpCompositeInsert(ctx.F32[4], screen_depth, position, 2u)}; | ||||
|         ctx.OpStore(ctx.output_position, vector); | ||||
|     } | ||||
| } | ||||
|  | ||||
| } // namespace Shader::Backend::SPIRV | ||||
| @@ -92,6 +92,14 @@ void IREmitter::DemoteToHelperInvocation(Block* continue_label) { | ||||
|     Inst(Opcode::DemoteToHelperInvocation, continue_label); | ||||
| } | ||||
|  | ||||
| void IREmitter::Prologue() { | ||||
|     Inst(Opcode::Prologue); | ||||
| } | ||||
|  | ||||
| void IREmitter::Epilogue() { | ||||
|     Inst(Opcode::Epilogue); | ||||
| } | ||||
|  | ||||
| U32 IREmitter::GetReg(IR::Reg reg) { | ||||
|     return Inst<U32>(Opcode::GetRegister, reg); | ||||
| } | ||||
|   | ||||
| @@ -39,6 +39,9 @@ public: | ||||
|     void Return(); | ||||
|     void DemoteToHelperInvocation(Block* continue_label); | ||||
|  | ||||
|     void Prologue(); | ||||
|     void Epilogue(); | ||||
|  | ||||
|     [[nodiscard]] U32 GetReg(IR::Reg reg); | ||||
|     void SetReg(IR::Reg reg, const U32& value); | ||||
|  | ||||
|   | ||||
| @@ -56,6 +56,8 @@ bool Inst::MayHaveSideEffects() const noexcept { | ||||
|     case Opcode::SelectionMerge: | ||||
|     case Opcode::Return: | ||||
|     case Opcode::DemoteToHelperInvocation: | ||||
|     case Opcode::Prologue: | ||||
|     case Opcode::Epilogue: | ||||
|     case Opcode::SetAttribute: | ||||
|     case Opcode::SetAttributeIndexed: | ||||
|     case Opcode::SetFragColor: | ||||
|   | ||||
| @@ -15,6 +15,10 @@ OPCODE(SelectionMerge,                                      Void,           Labe | ||||
| OPCODE(Return,                                              Void,                                                                                           ) | ||||
| OPCODE(DemoteToHelperInvocation,                            Void,           Label,                                                                          ) | ||||
|  | ||||
| // Special operations | ||||
| OPCODE(Prologue,                                            Void,                                                                                           ) | ||||
| OPCODE(Epilogue,                                            Void,                                                                                           ) | ||||
|  | ||||
| // Context getters/setters | ||||
| OPCODE(GetRegister,                                         U32,            Reg,                                                                            ) | ||||
| OPCODE(SetRegister,                                         Void,           Reg,            U32,                                                            ) | ||||
|   | ||||
| @@ -634,6 +634,9 @@ public: | ||||
|         : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, env{env_}, | ||||
|           block_list{block_list_} { | ||||
|         Visit(root_stmt, nullptr, nullptr); | ||||
|  | ||||
|         IR::IREmitter ir{*block_list.front()}; | ||||
|         ir.Prologue(); | ||||
|     } | ||||
|  | ||||
| private: | ||||
| @@ -734,7 +737,9 @@ private: | ||||
|                     current_block = block_pool.Create(inst_pool); | ||||
|                     block_list.push_back(current_block); | ||||
|                 } | ||||
|                 IR::IREmitter{*current_block}.Return(); | ||||
|                 IR::IREmitter ir{*current_block}; | ||||
|                 ir.Epilogue(); | ||||
|                 ir.Return(); | ||||
|                 current_block = nullptr; | ||||
|                 break; | ||||
|             } | ||||
|   | ||||
| @@ -4,8 +4,18 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
|  | ||||
| #include "common/common_types.h" | ||||
|  | ||||
| namespace Shader { | ||||
|  | ||||
| enum class AttributeType : u8 { | ||||
|     Float, | ||||
|     SignedInt, | ||||
|     UnsignedInt, | ||||
| }; | ||||
|  | ||||
| struct Profile { | ||||
|     bool unified_descriptor_binding{}; | ||||
|     bool support_vertex_instance_id{}; | ||||
| @@ -24,6 +34,9 @@ struct Profile { | ||||
|  | ||||
|     // FClamp is broken and OpFMax + OpFMin should be used instead | ||||
|     bool has_broken_spirv_clamp{}; | ||||
|  | ||||
|     std::array<AttributeType, 32> generic_input_types{}; | ||||
|     bool convert_depth_mode{}; | ||||
| }; | ||||
|  | ||||
| } // namespace Shader | ||||
|   | ||||
| @@ -181,6 +181,9 @@ void GraphicsPipeline::Configure(bool is_indexed) { | ||||
|         PushImageDescriptors(stage_infos[stage], samplers.data(), image_view_ids.data(), | ||||
|                              *texture_cache, *update_descriptor_queue, index); | ||||
|     } | ||||
|     if (!descriptor_set_layout) { | ||||
|         return; | ||||
|     } | ||||
|     const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()}; | ||||
|     update_descriptor_queue->Send(*descriptor_update_template, descriptor_set); | ||||
|  | ||||
|   | ||||
| @@ -437,7 +437,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_, | ||||
|       buffer_cache{buffer_cache_}, texture_cache{texture_cache_} { | ||||
|     const auto& float_control{device.FloatControlProperties()}; | ||||
|     const VkDriverIdKHR driver_id{device.GetDriverID()}; | ||||
|     profile = Shader::Profile{ | ||||
|     base_profile = Shader::Profile{ | ||||
|         .unified_descriptor_binding = true, | ||||
|         .support_vertex_instance_id = false, | ||||
|         .support_float_controls = true, | ||||
| @@ -458,6 +458,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_, | ||||
|         .support_vote = true, | ||||
|         .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), | ||||
|         .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR, | ||||
|         .generic_input_types{}, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| @@ -589,6 +590,7 @@ GraphicsPipeline PipelineCache::CreateGraphicsPipeline(ShaderPools& pools, | ||||
|         Shader::Environment& env{*envs[env_index]}; | ||||
|         ++env_index; | ||||
|  | ||||
|         const Shader::Profile profile{MakeProfile(key, env.ShaderStage())}; | ||||
|         const std::vector<u32> code{EmitSPIRV(profile, env, program, binding)}; | ||||
|         modules[stage_index] = BuildShader(device, code); | ||||
|     } | ||||
| @@ -645,9 +647,36 @@ ComputePipeline PipelineCache::CreateComputePipeline(ShaderPools& pools, | ||||
|     Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()}; | ||||
|     Shader::IR::Program program{TranslateProgram(pools.inst, pools.block, env, cfg)}; | ||||
|     u32 binding{0}; | ||||
|     std::vector<u32> code{EmitSPIRV(profile, env, program, binding)}; | ||||
|     std::vector<u32> code{EmitSPIRV(base_profile, env, program, binding)}; | ||||
|     return ComputePipeline{device, descriptor_pool, update_descriptor_queue, program.info, | ||||
|                            BuildShader(device, code)}; | ||||
| } | ||||
|  | ||||
| static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribute& attr) { | ||||
|     switch (attr.Type()) { | ||||
|     case Maxwell::VertexAttribute::Type::SignedNorm: | ||||
|     case Maxwell::VertexAttribute::Type::UnsignedNorm: | ||||
|     case Maxwell::VertexAttribute::Type::UnsignedScaled: | ||||
|     case Maxwell::VertexAttribute::Type::SignedScaled: | ||||
|     case Maxwell::VertexAttribute::Type::Float: | ||||
|         return Shader::AttributeType::Float; | ||||
|     case Maxwell::VertexAttribute::Type::SignedInt: | ||||
|         return Shader::AttributeType::SignedInt; | ||||
|     case Maxwell::VertexAttribute::Type::UnsignedInt: | ||||
|         return Shader::AttributeType::UnsignedInt; | ||||
|     } | ||||
|     return Shader::AttributeType::Float; | ||||
| } | ||||
|  | ||||
| Shader::Profile PipelineCache::MakeProfile(const GraphicsPipelineCacheKey& key, | ||||
|                                            Shader::Stage stage) { | ||||
|     Shader::Profile profile{base_profile}; | ||||
|     if (stage == Shader::Stage::VertexB) { | ||||
|         profile.convert_depth_mode = key.state.ndc_minus_one_to_one != 0; | ||||
|         std::ranges::transform(key.state.attributes, profile.generic_input_types.begin(), | ||||
|                                &CastAttributeType); | ||||
|     } | ||||
|     return profile; | ||||
| } | ||||
|  | ||||
| } // namespace Vulkan | ||||
|   | ||||
| @@ -156,6 +156,8 @@ private: | ||||
|     ComputePipeline CreateComputePipeline(ShaderPools& pools, const ComputePipelineCacheKey& key, | ||||
|                                           Shader::Environment& env) const; | ||||
|  | ||||
|     Shader::Profile MakeProfile(const GraphicsPipelineCacheKey& key, Shader::Stage stage); | ||||
|  | ||||
|     Tegra::GPU& gpu; | ||||
|     Tegra::Engines::Maxwell3D& maxwell3d; | ||||
|     Tegra::Engines::KeplerCompute& kepler_compute; | ||||
| @@ -176,7 +178,7 @@ private: | ||||
|  | ||||
|     ShaderPools main_pools; | ||||
|  | ||||
|     Shader::Profile profile; | ||||
|     Shader::Profile base_profile; | ||||
|     std::string pipeline_cache_filename; | ||||
| }; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user