From c966cd3b2644d036f2ee9a5dd1dc403331a7213d Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 4 Aug 2022 20:04:40 +0100 Subject: [PATCH] Prevent runtimeInfo vertex state from leaking into wrong shaders This vertex state must only be present for the last pipeline stage that touches vertices, if it is present for other stages it could result in incorrect behaviour like performing TFB in the fragment shader or flipping device coordinates twice. --- .../gpu/interconnect/graphics_context.h | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index 7d28dddb..e75f32c2 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -1076,13 +1076,40 @@ namespace skyline::gpu::interconnect { size_t bufferIndex{}, imageIndex{}; boost::container::static_vector shaderModules; boost::container::static_vector shaderStages; + + // These parts of runtime info can only be set for the last stage that handles vertices in the current pipeline (either vertex or geometry) and should be unset for all others + struct StashedRuntimeInfo { + std::vector<::Shader::TransformFeedbackVarying> transformFeedbackVaryings; + std::optional fixedStatePointSize; + bool convertDepthMode; + } stashedRuntimeInfo{ + .fixedStatePointSize = runtimeInfo.fixed_state_point_size, + .convertDepthMode = runtimeInfo.convert_depth_mode, + }; + + auto stashRuntimeInfo{[&]() { + stashedRuntimeInfo.transformFeedbackVaryings = std::move(runtimeInfo.xfb_varyings); + runtimeInfo.xfb_varyings.clear(); + runtimeInfo.fixed_state_point_size = {}; + runtimeInfo.convert_depth_mode = false; + }}; + + auto unstashRuntimeInfo{[&]() { + runtimeInfo.xfb_varyings = std::move(stashedRuntimeInfo.transformFeedbackVaryings); + runtimeInfo.fixed_state_point_size = stashedRuntimeInfo.fixedStatePointSize; + runtimeInfo.convert_depth_mode = stashedRuntimeInfo.convertDepthMode; + }}; + + stashRuntimeInfo(); + bool hasFullGeometryStage{pipelineStages[maxwell3d::PipelineStage::Geometry].enabled && !pipelineStages[maxwell3d::PipelineStage::Geometry].program->program.is_geometry_passthrough}; for (auto &pipelineStage : pipelineStages) { if (!pipelineStage.enabled) continue; - auto fixedPointSize{runtimeInfo.fixed_state_point_size}; - if (fixedPointSize && pipelineStage.vkStage != vk::ShaderStageFlagBits::eVertex && pipelineStage.vkStage != vk::ShaderStageFlagBits::eGeometry) - runtimeInfo.fixed_state_point_size.reset(); // Only vertex/geometry stages are allowed to have a point size + bool needsUnstash{(pipelineStage.vkStage == vk::ShaderStageFlagBits::eGeometry && hasFullGeometryStage) || + (pipelineStage.vkStage == vk::ShaderStageFlagBits::eVertex && !hasFullGeometryStage)}; + if (needsUnstash) + unstashRuntimeInfo(); if (pipelineStage.needsRecompile || bindings.unified != pipelineStage.bindingBase || pipelineStage.previousStageStores.mask != runtimeInfo.previous_stage_stores.mask) { pipelineStage.previousStageStores = runtimeInfo.previous_stage_stores; @@ -1091,7 +1118,8 @@ namespace skyline::gpu::interconnect { pipelineStage.bindingLast = bindings.unified; } - runtimeInfo.fixed_state_point_size = fixedPointSize; + if (needsUnstash) + stashRuntimeInfo(); auto &program{pipelineStage.program->program}; runtimeInfo.previous_stage_stores = program.info.stores; @@ -1236,6 +1264,8 @@ namespace skyline::gpu::interconnect { }); } + unstashRuntimeInfo(); + return { std::move(shaderModules), std::move(shaderStages),