From ebf2bc2369eecee441a6afc589e537b91a6ab507 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Thu, 1 Dec 2022 02:28:19 +0100 Subject: [PATCH] early-access version 3171 --- README.md | 2 +- src/audio_core/precompiled_headers.h | 2 +- src/common/CMakeLists.txt | 2 +- src/common/common_precompiled_headers.h | 14 ++++ src/common/precompiled_headers.h | 2 +- src/common/string_util.cpp | 4 +- src/core/precompiled_headers.h | 4 +- src/dedicated_room/precompiled_headers.h | 2 +- src/input_common/precompiled_headers.h | 2 +- src/network/precompiled_headers.h | 2 +- src/shader_recompiler/CMakeLists.txt | 1 + src/shader_recompiler/frontend/ir/program.h | 2 + .../frontend/maxwell/translate_program.cpp | 81 +++++++++++++++++++ .../frontend/maxwell/translate_program.h | 9 +++ src/shader_recompiler/host_translate_info.h | 1 + src/shader_recompiler/ir_opt/layer_pass.cpp | 68 ++++++++++++++++ src/shader_recompiler/ir_opt/passes.h | 1 + src/shader_recompiler/precompiled_headers.h | 2 +- src/tests/precompiled_headers.h | 2 +- src/video_core/precompiled_headers.h | 2 +- .../renderer_opengl/gl_shader_cache.cpp | 37 ++++++++- .../renderer_vulkan/vk_pipeline_cache.cpp | 33 +++++++- src/web_service/precompiled_headers.h | 2 +- src/yuzu/precompiled_headers.h | 2 +- src/yuzu_cmd/precompiled_headers.h | 2 +- 25 files changed, 260 insertions(+), 21 deletions(-) create mode 100755 src/common/common_precompiled_headers.h create mode 100755 src/shader_recompiler/ir_opt/layer_pass.cpp diff --git a/README.md b/README.md index 03e095f62..66c946034 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 3170. +This is the source code for early-access 3171. ## Legal Notice diff --git a/src/audio_core/precompiled_headers.h b/src/audio_core/precompiled_headers.h index 62a8da4b5..aabae730b 100755 --- a/src/audio_core/precompiled_headers.h +++ b/src/audio_core/precompiled_headers.h @@ -3,4 +3,4 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index b8aa482de..c69247da1 100755 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -37,7 +37,7 @@ add_library(common STATIC cache_management.cpp cache_management.h common_funcs.h - common_headers.h + common_precompiled_headers.h common_types.h concepts.h div_ceil.h diff --git a/src/common/common_precompiled_headers.h b/src/common/common_precompiled_headers.h new file mode 100755 index 000000000..be7e5b5f9 --- /dev/null +++ b/src/common/common_precompiled_headers.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include + +#include + +#include "common/assert.h" +#include "common/common_types.h" diff --git a/src/common/precompiled_headers.h b/src/common/precompiled_headers.h index 62a8da4b5..aabae730b 100755 --- a/src/common/precompiled_headers.h +++ b/src/common/precompiled_headers.h @@ -3,4 +3,4 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index e4bf6ef06..b847fd4d9 100755 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -141,7 +141,7 @@ static std::wstring CPToUTF16(u32 code_page, const std::string& input) { MultiByteToWideChar(code_page, 0, input.data(), static_cast(input.size()), nullptr, 0); if (size == 0) { - return std::wstring(size, L'\0'); + return {}; } std::wstring output(size, L'\0'); @@ -158,7 +158,7 @@ std::string UTF16ToUTF8(const std::wstring& input) { const auto size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast(input.size()), nullptr, 0, nullptr, nullptr); if (size == 0) { - return std::string(size, '\0'); + return {}; } std::string output(size, '\0'); diff --git a/src/core/precompiled_headers.h b/src/core/precompiled_headers.h index 292e15e5d..30a31001d 100755 --- a/src/core/precompiled_headers.h +++ b/src/core/precompiled_headers.h @@ -6,4 +6,6 @@ #include // used by service.h which is heavily included #include // used by k_auto_object.h which is heavily included -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" + +#include "core/hle/kernel/k_process.h" diff --git a/src/dedicated_room/precompiled_headers.h b/src/dedicated_room/precompiled_headers.h index 62a8da4b5..aabae730b 100755 --- a/src/dedicated_room/precompiled_headers.h +++ b/src/dedicated_room/precompiled_headers.h @@ -3,4 +3,4 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" diff --git a/src/input_common/precompiled_headers.h b/src/input_common/precompiled_headers.h index 62a8da4b5..aabae730b 100755 --- a/src/input_common/precompiled_headers.h +++ b/src/input_common/precompiled_headers.h @@ -3,4 +3,4 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" diff --git a/src/network/precompiled_headers.h b/src/network/precompiled_headers.h index 62a8da4b5..aabae730b 100755 --- a/src/network/precompiled_headers.h +++ b/src/network/precompiled_headers.h @@ -3,4 +3,4 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index bb17ca091..e8f44f887 100755 --- 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 diff --git a/src/shader_recompiler/frontend/ir/program.h b/src/shader_recompiler/frontend/ir/program.h index 9f7b9914e..c35e2ab65 100755 --- a/src/shader_recompiler/frontend/ir/program.h +++ b/src/shader_recompiler/frontend/ir/program.h @@ -27,6 +27,8 @@ struct Program { u32 local_memory_size{}; u32 shared_memory_size{}; bool is_geometry_passthrough{}; + bool requires_layer_emulation{}; + Attribute emulated_layer{}; }; [[nodiscard]] std::string DumpProgram(const Program& program); diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 06a67eabe..221205685 100755 --- 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& inst_pool, ObjectPool& inst_pool, + ObjectPool& 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); + program.info.stores.Set(source_program.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.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 e0278b23c..78364423b 100755 --- 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 GenerateLayerPassthrough(ObjectPool& inst_pool, + ObjectPool& 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 4ddee3d1b..5ed9e45f9 100755 --- a/src/shader_recompiler/host_translate_info.h +++ b/src/shader_recompiler/host_translate_info.h @@ -14,6 +14,7 @@ struct HostTranslateInfo { 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 requires_layer_emulation{}; ///< True when the device doesn't support 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 100755 index 000000000..5f6520685 --- /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 +#include +#include + +#include + +#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.requires_layer_emulation || !PermittedProgramStage(program.stage)) { + return; + } + + const auto end{program.post_order_blocks.end()}; + const auto emulated_layer = 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{emulated_layer}); + } + } + } + + if (requires_layer_emulation) { + program.requires_layer_emulation = true; + program.emulated_layer = emulated_layer; + program.info.stores.Set(IR::Attribute::Layer, false); + program.info.stores.Set(emulated_layer, true); + } +} + +} // namespace Shader::Optimization diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index f464eff95..478318874 100755 --- 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 index fcdc5daf8..5dd6b7eca 100755 --- a/src/shader_recompiler/precompiled_headers.h +++ b/src/shader_recompiler/precompiled_headers.h @@ -3,5 +3,5 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" #include "frontend/maxwell/translate/impl/impl.h" diff --git a/src/tests/precompiled_headers.h b/src/tests/precompiled_headers.h index 62a8da4b5..aabae730b 100755 --- a/src/tests/precompiled_headers.h +++ b/src/tests/precompiled_headers.h @@ -3,4 +3,4 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" diff --git a/src/video_core/precompiled_headers.h b/src/video_core/precompiled_headers.h index 62a8da4b5..aabae730b 100755 --- a/src/video_core/precompiled_headers.h +++ b/src/video_core/precompiled_headers.h @@ -3,4 +3,4 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 3268ff08d..2b1ab260c 100755 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -39,6 +39,7 @@ using Shader::Backend::GLASM::EmitGLASM; using Shader::Backend::GLSL::EmitGLSL; using Shader::Backend::SPIRV::EmitSPIRV; using Shader::Maxwell::ConvertLegacyToGeneric; +using Shader::Maxwell::GenerateLayerPassthrough; using Shader::Maxwell::MergeDualVertexPrograms; using Shader::Maxwell::TranslateProgram; using VideoCommon::ComputeEnvironment; @@ -56,6 +57,17 @@ auto MakeSpan(Container& container) { return std::span(container.data(), container.size()); } +Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topology) { + switch (topology) { + case Maxwell::PrimitiveTopology::Points: + return Shader::OutputTopology::PointList; + case Maxwell::PrimitiveTopology::LineStrip: + return Shader::OutputTopology::LineStrip; + default: + return Shader::OutputTopology::TriangleStrip; + } +} + Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, const Shader::IR::Program& program, const Shader::IR::Program* previous_program, @@ -220,6 +232,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo .support_int64 = device.HasShaderInt64(), .needs_demote_reorder = device.IsAmd(), .support_snorm_render_buffer = false, + .requires_layer_emulation = !device.HasVertexViewportLayer(), } { if (use_asynchronous_shaders) { workers = CreateWorkers(); @@ -314,9 +327,7 @@ GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() { const auto& regs{maxwell3d->regs}; graphics_key.raw = 0; graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0); - graphics_key.gs_input_topology.Assign(graphics_key.unique_hashes[4] != 0 - ? regs.draw.topology.Value() - : Maxwell::PrimitiveTopology{}); + graphics_key.gs_input_topology.Assign(regs.draw.topology.Value()); graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value()); graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value()); graphics_key.tessellation_clockwise.Assign( @@ -415,7 +426,19 @@ std::unique_ptr ShaderCache::CreateGraphicsPipeline( std::array programs; const bool uses_vertex_a{key.unique_hashes[0] != 0}; const bool uses_vertex_b{key.unique_hashes[1] != 0}; + + // Layer passthrough generation for devices without GL_ARB_shader_viewport_layer_array + Shader::IR::Program* layer_source_program{}; + for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { + const bool is_emulated_stage = layer_source_program != nullptr && + index == static_cast(Maxwell::ShaderType::Geometry); + if (key.unique_hashes[index] == 0 && is_emulated_stage) { + auto topology = MaxwellToOutputTopology(key.gs_input_topology); + programs[index] = GenerateLayerPassthrough(pools.inst, pools.block, host_info, + *layer_source_program, topology); + continue; + } if (key.unique_hashes[index] == 0) { continue; } @@ -443,6 +466,10 @@ std::unique_ptr ShaderCache::CreateGraphicsPipeline( Shader::NumDescriptors(program_vb.info.storage_buffers_descriptors); programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); } + + if (programs[index].requires_layer_emulation) { + layer_source_program = &programs[index]; + } } const u32 glasm_storage_buffer_limit{device.GetMaxGLASMStorageBufferBlocks()}; const bool glasm_use_storage_buffers{total_storage_buffers <= glasm_storage_buffer_limit}; @@ -456,7 +483,9 @@ std::unique_ptr ShaderCache::CreateGraphicsPipeline( const bool use_glasm{device.UseAssemblyShaders()}; const size_t first_index = uses_vertex_a && uses_vertex_b ? 1 : 0; for (size_t index = first_index; index < Maxwell::MaxShaderProgram; ++index) { - if (key.unique_hashes[index] == 0) { + const bool is_emulated_stage = layer_source_program != nullptr && + index == static_cast(Maxwell::ShaderType::Geometry); + if (key.unique_hashes[index] == 0 && !is_emulated_stage) { continue; } UNIMPLEMENTED_IF(index == 0); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index cc2a0bf48..f75e6c171 100755 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -46,6 +46,7 @@ MICROPROFILE_DECLARE(Vulkan_PipelineCache); namespace { using Shader::Backend::SPIRV::EmitSPIRV; using Shader::Maxwell::ConvertLegacyToGeneric; +using Shader::Maxwell::GenerateLayerPassthrough; using Shader::Maxwell::MergeDualVertexPrograms; using Shader::Maxwell::TranslateProgram; using VideoCommon::ComputeEnvironment; @@ -60,6 +61,17 @@ auto MakeSpan(Container& container) { return std::span(container.data(), container.size()); } +Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topology) { + switch (topology) { + case Maxwell::PrimitiveTopology::Points: + return Shader::OutputTopology::PointList; + case Maxwell::PrimitiveTopology::LineStrip: + return Shader::OutputTopology::LineStrip; + default: + return Shader::OutputTopology::TriangleStrip; + } +} + Shader::CompareFunction MaxwellToCompareFunction(Maxwell::ComparisonOp comparison) { switch (comparison) { case Maxwell::ComparisonOp::Never_D3D: @@ -327,6 +339,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device .needs_demote_reorder = driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, .support_snorm_render_buffer = true, + .requires_layer_emulation = !device.IsExtShaderViewportIndexLayerSupported(), }; } @@ -509,7 +522,19 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( std::array programs; const bool uses_vertex_a{key.unique_hashes[0] != 0}; const bool uses_vertex_b{key.unique_hashes[1] != 0}; + + // Layer passthrough generation for devices without VK_EXT_shader_viewport_index_layer + Shader::IR::Program* layer_source_program{}; + for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { + const bool is_emulated_stage = layer_source_program != nullptr && + index == static_cast(Maxwell::ShaderType::Geometry); + if (key.unique_hashes[index] == 0 && is_emulated_stage) { + auto topology = MaxwellToOutputTopology(key.state.topology); + programs[index] = GenerateLayerPassthrough(pools.inst, pools.block, host_info, + *layer_source_program, topology); + continue; + } if (key.unique_hashes[index] == 0) { continue; } @@ -530,6 +555,10 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); } + + if (programs[index].requires_layer_emulation) { + layer_source_program = &programs[index]; + } } std::array infos{}; std::array modules; @@ -538,7 +567,9 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( Shader::Backend::Bindings binding; for (size_t index = uses_vertex_a && uses_vertex_b ? 1 : 0; index < Maxwell::MaxShaderProgram; ++index) { - if (key.unique_hashes[index] == 0) { + const bool is_emulated_stage = layer_source_program != nullptr && + index == static_cast(Maxwell::ShaderType::Geometry); + if (key.unique_hashes[index] == 0 && !is_emulated_stage) { continue; } UNIMPLEMENTED_IF(index == 0); diff --git a/src/web_service/precompiled_headers.h b/src/web_service/precompiled_headers.h index 62a8da4b5..aabae730b 100755 --- a/src/web_service/precompiled_headers.h +++ b/src/web_service/precompiled_headers.h @@ -3,4 +3,4 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" diff --git a/src/yuzu/precompiled_headers.h b/src/yuzu/precompiled_headers.h index 62a8da4b5..aabae730b 100755 --- a/src/yuzu/precompiled_headers.h +++ b/src/yuzu/precompiled_headers.h @@ -3,4 +3,4 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h" diff --git a/src/yuzu_cmd/precompiled_headers.h b/src/yuzu_cmd/precompiled_headers.h index 62a8da4b5..aabae730b 100755 --- a/src/yuzu_cmd/precompiled_headers.h +++ b/src/yuzu_cmd/precompiled_headers.h @@ -3,4 +3,4 @@ #pragma once -#include "common/common_headers.h" +#include "common/common_precompiled_headers.h"