diff --git a/src/shader_recompiler/ir/position.h b/src/shader_recompiler/ir/position.h index eb67634f0..41e27c5fe 100644 --- a/src/shader_recompiler/ir/position.h +++ b/src/shader_recompiler/ir/position.h @@ -10,8 +10,9 @@ namespace Shader::IR { /// Maps special position export to builtin attribute stores -inline void ExportPosition(IREmitter& ir, const auto& stage, Attribute attribute, u32 comp, - const IR::F32& value) { +template +inline void ExportPosition(IREmitter& ir, const StageRuntimeInfo& stage, Attribute attribute, + u32 comp, const IR::F32& value) { if (attribute == Attribute::Position0) { ir.SetAttribute(attribute, value, comp); return; @@ -44,6 +45,18 @@ inline void ExportPosition(IREmitter& ir, const auto& stage, Attribute attribute break; } case Output::GsMrtIndex: + if constexpr (std::is_same_v) { + // When using tessellation, layer is supposed to be set by the tessellation evaluation + // stage. We don't currently have a mechanism for that when emulating rect/quad lists + // using tessellation, so just ignore the write for now. Note that this only matters + // for vertex shaders, as geometry shaders come last in the pre-rasterization stage. + if (stage.tess_emulated_primitive) { + LOG_WARNING(Render, + "Exporting Layer from a vertex shader when using tessellation-based " + "primitive emulation is currently unsupported."); + return; + } + } ir.SetAttribute(IR::Attribute::RenderTargetId, value); break; case Output::None: diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 7ac876c50..6e138888a 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -82,6 +82,7 @@ using OutputMap = std::array; struct VertexRuntimeInfo { u32 num_outputs; std::array outputs; + bool tess_emulated_primitive{}; bool emulate_depth_negative_one_to_one{}; bool clip_disable{}; u32 step_rate_0; @@ -94,6 +95,7 @@ struct VertexRuntimeInfo { bool operator==(const VertexRuntimeInfo& other) const noexcept { return num_outputs == other.num_outputs && outputs == other.outputs && + tess_emulated_primitive == other.tess_emulated_primitive && emulate_depth_negative_one_to_one == other.emulate_depth_negative_one_to_one && clip_disable == other.clip_disable && tess_type == other.tess_type && tess_topology == other.tess_topology && diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index e95260554..dd7875bcb 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -128,6 +128,9 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS info.vs_info.emulate_depth_negative_one_to_one = !instance.IsDepthClipControlSupported() && regs.clipper_control.clip_space == Liverpool::ClipSpace::MinusWToW; + info.vs_info.tess_emulated_primitive = + regs.primitive_type == AmdGpu::PrimitiveType::RectList || + regs.primitive_type == AmdGpu::PrimitiveType::QuadList; info.vs_info.clip_disable = regs.IsClipDisabled(); if (l_stage == LogicalStage::TessellationEval) { info.vs_info.tess_type = regs.tess_config.type;