From 172308aab4bc2ef6a7ae750225c0a7720a9dd725 Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Fri, 17 Jan 2025 19:13:38 +0300 Subject: [PATCH] account for max viewport limit, add todo for ViewportIndex --- .../backend/spirv/emit_spirv_special.cpp | 16 ++++++++-------- src/shader_recompiler/profile.h | 2 ++ src/video_core/renderer_vulkan/vk_instance.h | 8 ++++++++ .../renderer_vulkan/vk_pipeline_cache.cpp | 2 ++ .../renderer_vulkan/vk_rasterizer.cpp | 19 +++++++++++++------ 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp index d0095a801..a0a3ed8ff 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp @@ -47,14 +47,14 @@ void ConvertPositionToClipSpace(EmitContext& ctx) { ctx.push_data_block, ctx.ConstU32(PushData::YScaleIndex))}; const Id yscale{ctx.OpLoad(type, yscale_ptr)}; - Id ndc_x = ctx.OpFMul(type, x, xscale); - ndc_x = ctx.OpFAdd(type, ndc_x, xoffset); - ndc_x = ctx.OpFDiv(type, ndc_x, ctx.Constant(type, float(8_KB))); - ndc_x = ctx.OpFSub(type, ndc_x, ctx.Constant(type, 1.f)); - Id ndc_y = ctx.OpFMul(type, y, yscale); - ndc_y = ctx.OpFAdd(type, ndc_y, yoffset); - ndc_y = ctx.OpFDiv(type, ndc_y, ctx.Constant(type, float(8_KB))); - ndc_y = ctx.OpFSub(type, ndc_y, ctx.Constant(type, 1.f)); + const Id vport_w = + ctx.Constant(type, float(std::min(ctx.profile.max_viewport_width / 2, 8_KB))); + const Id wnd_x = ctx.OpFAdd(type, ctx.OpFMul(type, x, xscale), xoffset); + const Id ndc_x = ctx.OpFSub(type, ctx.OpFDiv(type, wnd_x, vport_w), ctx.Constant(type, 1.f)); + const Id vport_h = + ctx.Constant(type, float(std::min(ctx.profile.max_viewport_height / 2, 8_KB))); + const Id wnd_y = ctx.OpFAdd(type, ctx.OpFMul(type, y, yscale), yoffset); + const Id ndc_y = ctx.OpFSub(type, ctx.OpFDiv(type, wnd_y, vport_h), ctx.Constant(type, 1.f)); const Id vector{ctx.OpCompositeConstruct(ctx.F32[4], std::array({ndc_x, ndc_y, z, w}))}; ctx.OpStore(ctx.output_position, vector); } diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index f8878d442..f8b91a283 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h @@ -30,6 +30,8 @@ struct Profile { bool needs_manual_interpolation{}; bool needs_lds_barriers{}; u64 min_ssbo_alignment{}; + u32 max_viewport_width{}; + u32 max_viewport_height{}; }; } // namespace Shader diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index e0d4d0b4d..67c79001e 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -274,6 +274,14 @@ public: return min_imported_host_pointer_alignment; } + u32 GetMaxViewportWidth() const { + return properties.limits.maxViewportDimensions[0]; + } + + u32 GetMaxViewportHeight() const { + return properties.limits.maxViewportDimensions[1]; + } + /// Returns the sample count flags supported by framebuffers. vk::SampleCountFlags GetFramebufferSampleCounts() const { return properties.limits.framebufferColorSampleCounts & diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 3a317646a..27400751d 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -210,6 +210,8 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, instance.GetDriverID() == vk::DriverId::eNvidiaProprietary, .needs_lds_barriers = instance.GetDriverID() == vk::DriverId::eNvidiaProprietary || instance.GetDriverID() == vk::DriverId::eMoltenvk, + .max_viewport_width = instance.GetMaxViewportWidth(), + .max_viewport_height = instance.GetMaxViewportHeight(), }; auto [cache_result, cache] = instance.GetDevice().createPipelineCacheUnique({}); ASSERT_MSG(cache_result == vk::Result::eSuccess, "Failed to create pipeline cache: {}", diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index a0d636371..07369c620 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -504,10 +504,17 @@ bool Rasterizer::BindResources(const Pipeline* pipeline) { } push_data.step0 = regs.vgt_instance_step_rate_0; push_data.step1 = regs.vgt_instance_step_rate_1; - push_data.xoffset = regs.viewport_control.xoffset_enable ? regs.viewports[0].xoffset : 0.f; - push_data.xscale = regs.viewport_control.xscale_enable ? regs.viewports[0].xscale : 1.f; - push_data.yoffset = regs.viewport_control.yoffset_enable ? regs.viewports[0].yoffset : 0.f; - push_data.yscale = regs.viewport_control.yscale_enable ? regs.viewports[0].yscale : 1.f; + + // TODO(roamic): add support for multiple viewports and geometry shaders when ViewportIndex + // is encountered and implemented in the recompiler. + if (stage->stage == Shader::Stage::Vertex) { + push_data.xoffset = + regs.viewport_control.xoffset_enable ? regs.viewports[0].xoffset : 0.f; + push_data.xscale = regs.viewport_control.xscale_enable ? regs.viewports[0].xscale : 1.f; + push_data.yoffset = + regs.viewport_control.yoffset_enable ? regs.viewports[0].yoffset : 0.f; + push_data.yscale = regs.viewport_control.yscale_enable ? regs.viewports[0].yscale : 1.f; + } stage->PushUd(binding, push_data); BindBuffers(*stage, binding, push_data, set_writes, buffer_barriers); @@ -1174,8 +1181,8 @@ void Rasterizer::UpdateViewportScissorState(const GraphicsPipeline& pipeline) { viewports.push_back({ .x = 0.f, .y = 0.f, - .width = float(16_KB), - .height = float(16_KB), + .width = float(std::min(instance.GetMaxViewportWidth(), 16_KB)), + .height = float(std::min(instance.GetMaxViewportHeight(), 16_KB)), .minDepth = 0.0, .maxDepth = 1.0, });