Browse Source

vulkan: fix negative scissors not being clamped.

Sasha Szpakowski 1 year ago
parent
commit
0ca8cb4b41
1 changed files with 28 additions and 12 deletions
  1. 28 12
      src/modules/graphics/vulkan/Graphics.cpp

+ 28 - 12
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);