diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/shader_recompiler/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/translate_program.cpp | 81 | ||||
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/translate_program.h | 9 | ||||
| -rw-r--r-- | src/shader_recompiler/host_translate_info.h | 3 | ||||
| -rw-r--r-- | src/shader_recompiler/ir_opt/layer_pass.cpp | 68 | ||||
| -rw-r--r-- | src/shader_recompiler/ir_opt/passes.h | 1 | ||||
| -rw-r--r-- | src/shader_recompiler/shader_info.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 37 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 33 |
9 files changed, 230 insertions, 6 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 545d69c7e..8cd584154 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -221,6 +221,7 @@ add_library(shader_recompiler STATIC | |||
| 221 | ir_opt/dual_vertex_pass.cpp | 221 | ir_opt/dual_vertex_pass.cpp |
| 222 | ir_opt/global_memory_to_storage_buffer_pass.cpp | 222 | ir_opt/global_memory_to_storage_buffer_pass.cpp |
| 223 | ir_opt/identity_removal_pass.cpp | 223 | ir_opt/identity_removal_pass.cpp |
| 224 | ir_opt/layer_pass.cpp | ||
| 224 | ir_opt/lower_fp16_to_fp32.cpp | 225 | ir_opt/lower_fp16_to_fp32.cpp |
| 225 | ir_opt/lower_int64_to_int32.cpp | 226 | ir_opt/lower_int64_to_int32.cpp |
| 226 | ir_opt/passes.h | 227 | ir_opt/passes.h |
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 @@ | |||
| 9 | #include "common/settings.h" | 9 | #include "common/settings.h" |
| 10 | #include "shader_recompiler/exception.h" | 10 | #include "shader_recompiler/exception.h" |
| 11 | #include "shader_recompiler/frontend/ir/basic_block.h" | 11 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 12 | #include "shader_recompiler/frontend/ir/ir_emitter.h" | ||
| 12 | #include "shader_recompiler/frontend/ir/post_order.h" | 13 | #include "shader_recompiler/frontend/ir/post_order.h" |
| 13 | #include "shader_recompiler/frontend/maxwell/structured_control_flow.h" | 14 | #include "shader_recompiler/frontend/maxwell/structured_control_flow.h" |
| 14 | #include "shader_recompiler/frontend/maxwell/translate/translate.h" | 15 | #include "shader_recompiler/frontend/maxwell/translate/translate.h" |
| @@ -233,6 +234,8 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 233 | Optimization::VerificationPass(program); | 234 | Optimization::VerificationPass(program); |
| 234 | } | 235 | } |
| 235 | Optimization::CollectShaderInfoPass(env, program); | 236 | Optimization::CollectShaderInfoPass(env, program); |
| 237 | Optimization::LayerPass(program, host_info); | ||
| 238 | |||
| 236 | CollectInterpolationInfo(env, program); | 239 | CollectInterpolationInfo(env, program); |
| 237 | AddNVNStorageBuffers(program); | 240 | AddNVNStorageBuffers(program); |
| 238 | return program; | 241 | return program; |
| @@ -331,4 +334,82 @@ void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& run | |||
| 331 | } | 334 | } |
| 332 | } | 335 | } |
| 333 | 336 | ||
| 337 | IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool, | ||
| 338 | ObjectPool<IR::Block>& block_pool, | ||
| 339 | const HostTranslateInfo& host_info, | ||
| 340 | IR::Program& source_program, | ||
| 341 | Shader::OutputTopology output_topology) { | ||
| 342 | IR::Program program; | ||
| 343 | program.stage = Stage::Geometry; | ||
| 344 | program.output_topology = output_topology; | ||
| 345 | switch (output_topology) { | ||
| 346 | case OutputTopology::PointList: | ||
| 347 | program.output_vertices = 1; | ||
| 348 | break; | ||
| 349 | case OutputTopology::LineStrip: | ||
| 350 | program.output_vertices = 2; | ||
| 351 | break; | ||
| 352 | default: | ||
| 353 | program.output_vertices = 3; | ||
| 354 | break; | ||
| 355 | } | ||
| 356 | |||
| 357 | program.is_geometry_passthrough = false; | ||
| 358 | program.info.loads.mask = source_program.info.stores.mask; | ||
| 359 | program.info.stores.mask = source_program.info.stores.mask; | ||
| 360 | program.info.stores.Set(IR::Attribute::Layer, true); | ||
| 361 | program.info.stores.Set(source_program.info.emulated_layer, false); | ||
| 362 | |||
| 363 | IR::Block* current_block = block_pool.Create(inst_pool); | ||
| 364 | auto& node{program.syntax_list.emplace_back()}; | ||
| 365 | node.type = IR::AbstractSyntaxNode::Type::Block; | ||
| 366 | node.data.block = current_block; | ||
| 367 | |||
| 368 | IR::IREmitter ir{*current_block}; | ||
| 369 | for (u32 i = 0; i < program.output_vertices; i++) { | ||
| 370 | // Assign generics from input | ||
| 371 | for (u32 j = 0; j < 32; j++) { | ||
| 372 | if (!program.info.stores.Generic(j)) { | ||
| 373 | continue; | ||
| 374 | } | ||
| 375 | |||
| 376 | const IR::Attribute attr = IR::Attribute::Generic0X + (j * 4); | ||
| 377 | ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); | ||
| 378 | ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); | ||
| 379 | ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); | ||
| 380 | ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); | ||
| 381 | } | ||
| 382 | |||
| 383 | // Assign position from input | ||
| 384 | const IR::Attribute attr = IR::Attribute::PositionX; | ||
| 385 | ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); | ||
| 386 | ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); | ||
| 387 | ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); | ||
| 388 | ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); | ||
| 389 | |||
| 390 | // Assign layer | ||
| 391 | ir.SetAttribute(IR::Attribute::Layer, ir.GetAttribute(source_program.info.emulated_layer), | ||
| 392 | ir.Imm32(0)); | ||
| 393 | |||
| 394 | // Emit vertex | ||
| 395 | ir.EmitVertex(ir.Imm32(0)); | ||
| 396 | } | ||
| 397 | ir.EndPrimitive(ir.Imm32(0)); | ||
| 398 | |||
| 399 | IR::Block* return_block{block_pool.Create(inst_pool)}; | ||
| 400 | IR::IREmitter{*return_block}.Epilogue(); | ||
| 401 | current_block->AddBranch(return_block); | ||
| 402 | |||
| 403 | auto& merge{program.syntax_list.emplace_back()}; | ||
| 404 | merge.type = IR::AbstractSyntaxNode::Type::Block; | ||
| 405 | merge.data.block = return_block; | ||
| 406 | program.syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Return; | ||
| 407 | |||
| 408 | program.blocks = GenerateBlocks(program.syntax_list); | ||
| 409 | program.post_order_blocks = PostOrder(program.syntax_list.front()); | ||
| 410 | Optimization::SsaRewritePass(program); | ||
| 411 | |||
| 412 | return program; | ||
| 413 | } | ||
| 414 | |||
| 334 | } // namespace Shader::Maxwell | 415 | } // 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 { | |||
| 25 | 25 | ||
| 26 | void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_info); | 26 | void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_info); |
| 27 | 27 | ||
| 28 | // Maxwell v1 and older Nvidia cards don't support setting gl_Layer from non-geometry stages. | ||
| 29 | // This creates a workaround by setting the layer as a generic output and creating a | ||
| 30 | // passthrough geometry shader that reads the generic and sets the layer. | ||
| 31 | [[nodiscard]] IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool, | ||
| 32 | ObjectPool<IR::Block>& block_pool, | ||
| 33 | const HostTranslateInfo& host_info, | ||
| 34 | IR::Program& source_program, | ||
| 35 | Shader::OutputTopology output_topology); | ||
| 36 | |||
| 28 | } // namespace Shader::Maxwell | 37 | } // 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 { | |||
| 13 | bool support_float16{}; ///< True when the device supports 16-bit floats | 13 | bool support_float16{}; ///< True when the device supports 16-bit floats |
| 14 | bool support_int64{}; ///< True when the device supports 64-bit integers | 14 | bool support_int64{}; ///< True when the device supports 64-bit integers |
| 15 | bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered | 15 | bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered |
| 16 | bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers | 16 | bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers |
| 17 | bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS | ||
| 17 | }; | 18 | }; |
| 18 | 19 | ||
| 19 | } // namespace Shader | 20 | } // 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 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <bit> | ||
| 6 | #include <optional> | ||
| 7 | |||
| 8 | #include <boost/container/small_vector.hpp> | ||
| 9 | |||
| 10 | #include "shader_recompiler/environment.h" | ||
| 11 | #include "shader_recompiler/frontend/ir/basic_block.h" | ||
| 12 | #include "shader_recompiler/frontend/ir/breadth_first_search.h" | ||
| 13 | #include "shader_recompiler/frontend/ir/ir_emitter.h" | ||
| 14 | #include "shader_recompiler/host_translate_info.h" | ||
| 15 | #include "shader_recompiler/ir_opt/passes.h" | ||
| 16 | #include "shader_recompiler/shader_info.h" | ||
| 17 | |||
| 18 | namespace Shader::Optimization { | ||
| 19 | |||
| 20 | static IR::Attribute EmulatedLayerAttribute(VaryingState& stores) { | ||
| 21 | for (u32 i = 0; i < 32; i++) { | ||
| 22 | if (!stores.Generic(i)) { | ||
| 23 | return IR::Attribute::Generic0X + (i * 4); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | return IR::Attribute::Layer; | ||
| 27 | } | ||
| 28 | |||
| 29 | static bool PermittedProgramStage(Stage stage) { | ||
| 30 | switch (stage) { | ||
| 31 | case Stage::VertexA: | ||
| 32 | case Stage::VertexB: | ||
| 33 | case Stage::TessellationControl: | ||
| 34 | case Stage::TessellationEval: | ||
| 35 | return true; | ||
| 36 | default: | ||
| 37 | return false; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | void LayerPass(IR::Program& program, const HostTranslateInfo& host_info) { | ||
| 42 | if (host_info.support_viewport_index_layer || !PermittedProgramStage(program.stage)) { | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | |||
| 46 | const auto end{program.post_order_blocks.end()}; | ||
| 47 | const auto layer_attribute = EmulatedLayerAttribute(program.info.stores); | ||
| 48 | bool requires_layer_emulation = false; | ||
| 49 | |||
| 50 | for (auto block = program.post_order_blocks.begin(); block != end; ++block) { | ||
| 51 | for (IR::Inst& inst : (*block)->Instructions()) { | ||
| 52 | if (inst.GetOpcode() == IR::Opcode::SetAttribute && | ||
| 53 | inst.Arg(0).Attribute() == IR::Attribute::Layer) { | ||
| 54 | requires_layer_emulation = true; | ||
| 55 | inst.SetArg(0, IR::Value{layer_attribute}); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | if (requires_layer_emulation) { | ||
| 61 | program.info.requires_layer_emulation = true; | ||
| 62 | program.info.emulated_layer = layer_attribute; | ||
| 63 | program.info.stores.Set(IR::Attribute::Layer, false); | ||
| 64 | program.info.stores.Set(layer_attribute, true); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | } // 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); | |||
| 23 | void SsaRewritePass(IR::Program& program); | 23 | void SsaRewritePass(IR::Program& program); |
| 24 | void PositionPass(Environment& env, IR::Program& program); | 24 | void PositionPass(Environment& env, IR::Program& program); |
| 25 | void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info); | 25 | void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info); |
| 26 | void LayerPass(IR::Program& program, const HostTranslateInfo& host_info); | ||
| 26 | void VerificationPass(const IR::Program& program); | 27 | void VerificationPass(const IR::Program& program); |
| 27 | 28 | ||
| 28 | // Dual Vertex | 29 | // Dual Vertex |
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 { | |||
| 204 | u32 nvn_buffer_base{}; | 204 | u32 nvn_buffer_base{}; |
| 205 | std::bitset<16> nvn_buffer_used{}; | 205 | std::bitset<16> nvn_buffer_used{}; |
| 206 | 206 | ||
| 207 | bool requires_layer_emulation{}; | ||
| 208 | IR::Attribute emulated_layer{}; | ||
| 209 | |||
| 207 | boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> | 210 | boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS> |
| 208 | constant_buffer_descriptors; | 211 | constant_buffer_descriptors; |
| 209 | boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; | 212 | boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 3fe04a115..a38060100 100644 --- 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; | |||
| 39 | using Shader::Backend::GLSL::EmitGLSL; | 39 | using Shader::Backend::GLSL::EmitGLSL; |
| 40 | using Shader::Backend::SPIRV::EmitSPIRV; | 40 | using Shader::Backend::SPIRV::EmitSPIRV; |
| 41 | using Shader::Maxwell::ConvertLegacyToGeneric; | 41 | using Shader::Maxwell::ConvertLegacyToGeneric; |
| 42 | using Shader::Maxwell::GenerateGeometryPassthrough; | ||
| 42 | using Shader::Maxwell::MergeDualVertexPrograms; | 43 | using Shader::Maxwell::MergeDualVertexPrograms; |
| 43 | using Shader::Maxwell::TranslateProgram; | 44 | using Shader::Maxwell::TranslateProgram; |
| 44 | using VideoCommon::ComputeEnvironment; | 45 | using VideoCommon::ComputeEnvironment; |
| @@ -56,6 +57,17 @@ auto MakeSpan(Container& container) { | |||
| 56 | return std::span(container.data(), container.size()); | 57 | return std::span(container.data(), container.size()); |
| 57 | } | 58 | } |
| 58 | 59 | ||
| 60 | Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topology) { | ||
| 61 | switch (topology) { | ||
| 62 | case Maxwell::PrimitiveTopology::Points: | ||
| 63 | return Shader::OutputTopology::PointList; | ||
| 64 | case Maxwell::PrimitiveTopology::LineStrip: | ||
| 65 | return Shader::OutputTopology::LineStrip; | ||
| 66 | default: | ||
| 67 | return Shader::OutputTopology::TriangleStrip; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 59 | Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, | 71 | Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, |
| 60 | const Shader::IR::Program& program, | 72 | const Shader::IR::Program& program, |
| 61 | const Shader::IR::Program* previous_program, | 73 | const Shader::IR::Program* previous_program, |
| @@ -220,6 +232,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | |||
| 220 | .support_int64 = device.HasShaderInt64(), | 232 | .support_int64 = device.HasShaderInt64(), |
| 221 | .needs_demote_reorder = device.IsAmd(), | 233 | .needs_demote_reorder = device.IsAmd(), |
| 222 | .support_snorm_render_buffer = false, | 234 | .support_snorm_render_buffer = false, |
| 235 | .support_viewport_index_layer = device.HasVertexViewportLayer(), | ||
| 223 | } { | 236 | } { |
| 224 | if (use_asynchronous_shaders) { | 237 | if (use_asynchronous_shaders) { |
| 225 | workers = CreateWorkers(); | 238 | workers = CreateWorkers(); |
| @@ -314,9 +327,7 @@ GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() { | |||
| 314 | const auto& regs{maxwell3d->regs}; | 327 | const auto& regs{maxwell3d->regs}; |
| 315 | graphics_key.raw = 0; | 328 | graphics_key.raw = 0; |
| 316 | graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0); | 329 | graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0); |
| 317 | graphics_key.gs_input_topology.Assign(graphics_key.unique_hashes[4] != 0 | 330 | graphics_key.gs_input_topology.Assign(regs.draw.topology.Value()); |
| 318 | ? regs.draw.topology.Value() | ||
| 319 | : Maxwell::PrimitiveTopology{}); | ||
| 320 | graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value()); | 331 | graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value()); |
| 321 | graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value()); | 332 | graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value()); |
| 322 | graphics_key.tessellation_clockwise.Assign( | 333 | graphics_key.tessellation_clockwise.Assign( |
| @@ -415,7 +426,19 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( | |||
| 415 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; | 426 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; |
| 416 | const bool uses_vertex_a{key.unique_hashes[0] != 0}; | 427 | const bool uses_vertex_a{key.unique_hashes[0] != 0}; |
| 417 | const bool uses_vertex_b{key.unique_hashes[1] != 0}; | 428 | const bool uses_vertex_b{key.unique_hashes[1] != 0}; |
| 429 | |||
| 430 | // Layer passthrough generation for devices without GL_ARB_shader_viewport_layer_array | ||
| 431 | Shader::IR::Program* layer_source_program{}; | ||
| 432 | |||
| 418 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { | 433 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { |
| 434 | const bool is_emulated_stage = layer_source_program != nullptr && | ||
| 435 | index == static_cast<u32>(Maxwell::ShaderType::Geometry); | ||
| 436 | if (key.unique_hashes[index] == 0 && is_emulated_stage) { | ||
| 437 | auto topology = MaxwellToOutputTopology(key.gs_input_topology); | ||
| 438 | programs[index] = GenerateGeometryPassthrough(pools.inst, pools.block, host_info, | ||
| 439 | *layer_source_program, topology); | ||
| 440 | continue; | ||
| 441 | } | ||
| 419 | if (key.unique_hashes[index] == 0) { | 442 | if (key.unique_hashes[index] == 0) { |
| 420 | continue; | 443 | continue; |
| 421 | } | 444 | } |
| @@ -443,6 +466,10 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( | |||
| 443 | Shader::NumDescriptors(program_vb.info.storage_buffers_descriptors); | 466 | Shader::NumDescriptors(program_vb.info.storage_buffers_descriptors); |
| 444 | programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); | 467 | programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); |
| 445 | } | 468 | } |
| 469 | |||
| 470 | if (programs[index].info.requires_layer_emulation) { | ||
| 471 | layer_source_program = &programs[index]; | ||
| 472 | } | ||
| 446 | } | 473 | } |
| 447 | const u32 glasm_storage_buffer_limit{device.GetMaxGLASMStorageBufferBlocks()}; | 474 | const u32 glasm_storage_buffer_limit{device.GetMaxGLASMStorageBufferBlocks()}; |
| 448 | const bool glasm_use_storage_buffers{total_storage_buffers <= glasm_storage_buffer_limit}; | 475 | const bool glasm_use_storage_buffers{total_storage_buffers <= glasm_storage_buffer_limit}; |
| @@ -456,7 +483,9 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline( | |||
| 456 | const bool use_glasm{device.UseAssemblyShaders()}; | 483 | const bool use_glasm{device.UseAssemblyShaders()}; |
| 457 | const size_t first_index = uses_vertex_a && uses_vertex_b ? 1 : 0; | 484 | const size_t first_index = uses_vertex_a && uses_vertex_b ? 1 : 0; |
| 458 | for (size_t index = first_index; index < Maxwell::MaxShaderProgram; ++index) { | 485 | for (size_t index = first_index; index < Maxwell::MaxShaderProgram; ++index) { |
| 459 | if (key.unique_hashes[index] == 0) { | 486 | const bool is_emulated_stage = layer_source_program != nullptr && |
| 487 | index == static_cast<u32>(Maxwell::ShaderType::Geometry); | ||
| 488 | if (key.unique_hashes[index] == 0 && !is_emulated_stage) { | ||
| 460 | continue; | 489 | continue; |
| 461 | } | 490 | } |
| 462 | UNIMPLEMENTED_IF(index == 0); | 491 | 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 d4b0a542a..150413b04 100644 --- 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); | |||
| 46 | namespace { | 46 | namespace { |
| 47 | using Shader::Backend::SPIRV::EmitSPIRV; | 47 | using Shader::Backend::SPIRV::EmitSPIRV; |
| 48 | using Shader::Maxwell::ConvertLegacyToGeneric; | 48 | using Shader::Maxwell::ConvertLegacyToGeneric; |
| 49 | using Shader::Maxwell::GenerateGeometryPassthrough; | ||
| 49 | using Shader::Maxwell::MergeDualVertexPrograms; | 50 | using Shader::Maxwell::MergeDualVertexPrograms; |
| 50 | using Shader::Maxwell::TranslateProgram; | 51 | using Shader::Maxwell::TranslateProgram; |
| 51 | using VideoCommon::ComputeEnvironment; | 52 | using VideoCommon::ComputeEnvironment; |
| @@ -60,6 +61,17 @@ auto MakeSpan(Container& container) { | |||
| 60 | return std::span(container.data(), container.size()); | 61 | return std::span(container.data(), container.size()); |
| 61 | } | 62 | } |
| 62 | 63 | ||
| 64 | Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topology) { | ||
| 65 | switch (topology) { | ||
| 66 | case Maxwell::PrimitiveTopology::Points: | ||
| 67 | return Shader::OutputTopology::PointList; | ||
| 68 | case Maxwell::PrimitiveTopology::LineStrip: | ||
| 69 | return Shader::OutputTopology::LineStrip; | ||
| 70 | default: | ||
| 71 | return Shader::OutputTopology::TriangleStrip; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 63 | Shader::CompareFunction MaxwellToCompareFunction(Maxwell::ComparisonOp comparison) { | 75 | Shader::CompareFunction MaxwellToCompareFunction(Maxwell::ComparisonOp comparison) { |
| 64 | switch (comparison) { | 76 | switch (comparison) { |
| 65 | case Maxwell::ComparisonOp::Never_D3D: | 77 | case Maxwell::ComparisonOp::Never_D3D: |
| @@ -327,6 +339,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | |||
| 327 | .needs_demote_reorder = driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR || | 339 | .needs_demote_reorder = driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR || |
| 328 | driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, | 340 | driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, |
| 329 | .support_snorm_render_buffer = true, | 341 | .support_snorm_render_buffer = true, |
| 342 | .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(), | ||
| 330 | }; | 343 | }; |
| 331 | } | 344 | } |
| 332 | 345 | ||
| @@ -509,7 +522,19 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( | |||
| 509 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; | 522 | std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs; |
| 510 | const bool uses_vertex_a{key.unique_hashes[0] != 0}; | 523 | const bool uses_vertex_a{key.unique_hashes[0] != 0}; |
| 511 | const bool uses_vertex_b{key.unique_hashes[1] != 0}; | 524 | const bool uses_vertex_b{key.unique_hashes[1] != 0}; |
| 525 | |||
| 526 | // Layer passthrough generation for devices without VK_EXT_shader_viewport_index_layer | ||
| 527 | Shader::IR::Program* layer_source_program{}; | ||
| 528 | |||
| 512 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { | 529 | for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { |
| 530 | const bool is_emulated_stage = layer_source_program != nullptr && | ||
| 531 | index == static_cast<u32>(Maxwell::ShaderType::Geometry); | ||
| 532 | if (key.unique_hashes[index] == 0 && is_emulated_stage) { | ||
| 533 | auto topology = MaxwellToOutputTopology(key.state.topology); | ||
| 534 | programs[index] = GenerateGeometryPassthrough(pools.inst, pools.block, host_info, | ||
| 535 | *layer_source_program, topology); | ||
| 536 | continue; | ||
| 537 | } | ||
| 513 | if (key.unique_hashes[index] == 0) { | 538 | if (key.unique_hashes[index] == 0) { |
| 514 | continue; | 539 | continue; |
| 515 | } | 540 | } |
| @@ -530,6 +555,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( | |||
| 530 | auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; | 555 | auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)}; |
| 531 | programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); | 556 | programs[index] = MergeDualVertexPrograms(program_va, program_vb, env); |
| 532 | } | 557 | } |
| 558 | |||
| 559 | if (programs[index].info.requires_layer_emulation) { | ||
| 560 | layer_source_program = &programs[index]; | ||
| 561 | } | ||
| 533 | } | 562 | } |
| 534 | std::array<const Shader::Info*, Maxwell::MaxShaderStage> infos{}; | 563 | std::array<const Shader::Info*, Maxwell::MaxShaderStage> infos{}; |
| 535 | std::array<vk::ShaderModule, Maxwell::MaxShaderStage> modules; | 564 | std::array<vk::ShaderModule, Maxwell::MaxShaderStage> modules; |
| @@ -538,7 +567,9 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline( | |||
| 538 | Shader::Backend::Bindings binding; | 567 | Shader::Backend::Bindings binding; |
| 539 | for (size_t index = uses_vertex_a && uses_vertex_b ? 1 : 0; index < Maxwell::MaxShaderProgram; | 568 | for (size_t index = uses_vertex_a && uses_vertex_b ? 1 : 0; index < Maxwell::MaxShaderProgram; |
| 540 | ++index) { | 569 | ++index) { |
| 541 | if (key.unique_hashes[index] == 0) { | 570 | const bool is_emulated_stage = layer_source_program != nullptr && |
| 571 | index == static_cast<u32>(Maxwell::ShaderType::Geometry); | ||
| 572 | if (key.unique_hashes[index] == 0 && !is_emulated_stage) { | ||
| 542 | continue; | 573 | continue; |
| 543 | } | 574 | } |
| 544 | UNIMPLEMENTED_IF(index == 0); | 575 | UNIMPLEMENTED_IF(index == 0); |