From 0ca8cb4b41a80db9be9ef4bb884660cf9991a12b Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Mon, 5 Aug 2024 10:21:10 -0300 Subject: [PATCH] vulkan: fix negative scissors not being clamped. --- src/modules/graphics/vulkan/Graphics.cpp | 40 +++++++++++++++++------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index aa5c9b1ee..2d1b48c71 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -970,24 +970,40 @@ void Graphics::applyScissor() { VkRect2D scissor{}; - if (renderPassState.isWindow) - scissor.extent = swapChainExtent; - else - { - scissor.extent.width = renderPassState.width; - scissor.extent.height = renderPassState.height; - } + bool win = renderPassState.isWindow; + scissor.extent.width = win ? swapChainExtent.width : renderPassState.width; + scissor.extent.height = win ? swapChainExtent.height : renderPassState.height; if (states.back().scissor) { const Rect &rect = states.back().scissorRect; double dpiScale = getCurrentDPIScale(); - // TODO: clamp this to the above viewport size. - scissor.offset.x = (int)(rect.x * dpiScale); - scissor.offset.y = (int)(rect.y * dpiScale); - scissor.extent.width = (uint32)(rect.w * dpiScale); - scissor.extent.height = (uint32)(rect.h * dpiScale); + int minScissorX = (int)(rect.x * dpiScale); + int minScissorY = (int)(rect.y * dpiScale); + + int maxScissorX = minScissorX + (int)(rect.w * dpiScale) - 1; + int maxScissorY = minScissorY + (int)(rect.h * dpiScale) - 1; + + // Avoid negative offsets. + int minX = std::max(scissor.offset.x, minScissorX); + int minY = std::max(scissor.offset.y, minScissorY); + + int maxX = std::min(scissor.offset.x + (int)scissor.extent.width - 1, maxScissorX); + int maxY = std::min(scissor.offset.y + (int)scissor.extent.height - 1, maxScissorY); + + if (maxX >= minX && maxY >= minY) + { + scissor.offset.x = minX; + scissor.offset.y = minY; + scissor.extent.width = (maxX - minX) + 1; + scissor.extent.height = (maxY - minY) + 1; + } + else + { + scissor.extent.width = 0; + scissor.extent.height = 0; + } } vkCmdSetScissor(commandBuffers.at(currentFrame), 0, 1, &scissor);