Browse Source

vulkan: love.graphics.clear fixes.

- Fix love.graphics.clear(color) when multiple canvases are active.
- Fix love.graphics.clear when an integer-format canvas is active.
Sasha Szpakowski 1 year ago
parent
commit
b33afc4371

+ 28 - 102
src/modules/graphics/vulkan/Graphics.cpp

@@ -185,89 +185,12 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d
 	if (!color.hasValue && !stencil.hasValue && !depth.hasValue)
 		return;
 
-	flushBatchedDraws();
-
-	if (renderPassState.active)
-	{
-		VkClearAttachment attachment{};
-
-		if (color.hasValue)
-		{
-			Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a);
-			gammaCorrectColor(cf);
-
-			attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-			attachment.clearValue.color.float32[0] = static_cast<float>(cf.r);
-			attachment.clearValue.color.float32[1] = static_cast<float>(cf.g);
-			attachment.clearValue.color.float32[2] = static_cast<float>(cf.b);
-			attachment.clearValue.color.float32[3] = static_cast<float>(cf.a);
-		}
-
-		VkClearAttachment depthStencilAttachment{};
-
-		if (stencil.hasValue)
-		{
-			depthStencilAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
-			depthStencilAttachment.clearValue.depthStencil.stencil = static_cast<uint32_t>(stencil.value);
-		}
-		if (depth.hasValue)
-		{
-			depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
-			depthStencilAttachment.clearValue.depthStencil.depth = static_cast<float>(depth.value);
-		}
-
-		std::array<VkClearAttachment, 2> attachments = {
-			attachment,
-			depthStencilAttachment
-		};
-
-		VkClearRect rect{};
-		rect.layerCount = 1;
-		rect.rect.extent.width = static_cast<uint32_t>(renderPassState.width);
-		rect.rect.extent.height = static_cast<uint32_t>(renderPassState.height);
-
-		vkCmdClearAttachments(
-			commandBuffers[currentFrame], 
-			static_cast<uint32_t>(attachments.size()), attachments.data(),
-			1, &rect);
-	}
-	else
-	{
-		if (color.hasValue)
-		{
-			renderPassState.renderPassConfiguration.colorAttachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+	std::vector<OptionalColorD> colors;
 
-			Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a);
-			gammaCorrectColor(cf);
+	if (color.hasValue)
+		colors.resize(std::max(1, (int)states.back().renderTargets.colors.size()), color);
 
-			renderPassState.clearColors[0].color.float32[0] = static_cast<float>(cf.r);
-			renderPassState.clearColors[0].color.float32[1] = static_cast<float>(cf.g);
-			renderPassState.clearColors[0].color.float32[2] = static_cast<float>(cf.b);
-			renderPassState.clearColors[0].color.float32[3] = static_cast<float>(cf.a);
-		}
-
-		if (depth.hasValue)
-		{
-			renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-			renderPassState.clearColors[1].depthStencil.depth = static_cast<float>(depth.value);
-		}
-
-		if (stencil.hasValue)
-		{
-			renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-			renderPassState.clearColors[1].depthStencil.stencil = static_cast<uint32_t>(stencil.value);
-		}
-
-		if (renderPassState.isWindow)
-		{
-			renderPassState.windowClearRequested = true;
-			renderPassState.mainWindowClearColorValue = color;
-			renderPassState.mainWindowClearDepthValue = depth;
-			renderPassState.mainWindowClearStencilValue = stencil;
-		}
-		else
-			startRenderPass();
-	}
+	clear(colors, stencil, depth);
 }
 
 void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth)
@@ -277,22 +200,22 @@ void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt sten
 
 	flushBatchedDraws();
 
+	const auto &rts = states.back().renderTargets.colors;
+	size_t ncolorbuffers = isRenderTargetActive() ? rts.size() : 1;
+	size_t ncolors = std::min(ncolorbuffers, colors.size());
+
 	if (renderPassState.active)
 	{
 		std::vector<VkClearAttachment> attachments;
-		for (const auto &color : colors)
+		for (size_t i = 0; i < ncolors; i++)
 		{
+			const OptionalColorD &color = colors[i];
 			VkClearAttachment attachment{};
 			if (color.hasValue)
 			{
-				Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a);
-				gammaCorrectColor(cf);
-
+				auto texture = i < rts.size() ? rts[i].texture.get() : nullptr;
 				attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-				attachment.clearValue.color.float32[0] = static_cast<float>(cf.r);
-				attachment.clearValue.color.float32[1] = static_cast<float>(cf.g);
-				attachment.clearValue.color.float32[2] = static_cast<float>(cf.b);
-				attachment.clearValue.color.float32[3] = static_cast<float>(cf.a);
+				attachment.clearValue.color = Texture::getClearColor(texture, color.value);
 			}
 			attachments.push_back(attachment);
 		}
@@ -310,7 +233,8 @@ void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt sten
 			depthStencilAttachment.clearValue.depthStencil.depth = static_cast<float>(depth.value);
 		}
 
-		attachments.push_back(depthStencilAttachment);
+		if (stencil.hasValue || depth.hasValue)
+			attachments.push_back(depthStencilAttachment);
 
 		VkClearRect rect{};
 		rect.layerCount = 1;
@@ -324,36 +248,38 @@ void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt sten
 	}
 	else
 	{
-		for (size_t i = 0; i < colors.size(); i++)
+		for (size_t i = 0; i < ncolors; i++)
 		{
 			if (colors[i].hasValue)
 			{
 				renderPassState.renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
 
-				auto &color = colors[i];
-				Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a);
-				gammaCorrectColor(cf);
-
-				renderPassState.clearColors[i].color.float32[0] = static_cast<float>(cf.r);
-				renderPassState.clearColors[i].color.float32[1] = static_cast<float>(cf.g);
-				renderPassState.clearColors[i].color.float32[2] = static_cast<float>(cf.b);
-				renderPassState.clearColors[i].color.float32[3] = static_cast<float>(cf.a);
+				auto texture = i < rts.size() ? rts[i].texture.get() : nullptr;
+				renderPassState.clearColors[i].color = Texture::getClearColor(texture, colors[i].value);
 			}
 		}
 
 		if (depth.hasValue)
 		{
 			renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-			renderPassState.clearColors[colors.size()].depthStencil.depth = static_cast<float>(depth.value);
+			renderPassState.clearColors[ncolorbuffers].depthStencil.depth = static_cast<float>(depth.value);
 		}
 
 		if (stencil.hasValue)
 		{
 			renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-			renderPassState.clearColors[colors.size()].depthStencil.stencil = static_cast<uint32_t>(stencil.value);
+			renderPassState.clearColors[ncolorbuffers].depthStencil.stencil = static_cast<uint32_t>(stencil.value);
 		}
 
-		startRenderPass();
+		if (renderPassState.isWindow)
+		{
+			renderPassState.windowClearRequested = true;
+			renderPassState.mainWindowClearColorValue = colors.empty() ? OptionalColorD() : colors[0];
+			renderPassState.mainWindowClearDepthValue = depth;
+			renderPassState.mainWindowClearStencilValue = stencil;
+		}
+		else
+			startRenderPass();
 	}
 }
 

+ 30 - 22
src/modules/graphics/vulkan/Texture.cpp

@@ -383,7 +383,7 @@ void Texture::clear()
 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
 			0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
 
-		auto clearColor = getClearValue();
+		auto clearColor = getClearColor(this, ColorD(0, 0, 0, 0));
 
 		vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range);
 
@@ -393,7 +393,7 @@ void Texture::clear()
 	}
 	else if (imageLayout == VK_IMAGE_LAYOUT_GENERAL)
 	{
-		auto clearColor = getClearValue();
+		auto clearColor = getClearColor(this, ColorD(0, 0, 0, 0));
 
 		vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range);
 	}
@@ -415,33 +415,41 @@ void Texture::clear()
 	}
 }
 
-VkClearColorValue Texture::getClearValue()
+VkClearColorValue Texture::getClearColor(love::graphics::Texture *texture, const ColorD &color)
 {
-	auto vulkanFormat = Vulkan::getTextureFormat(format);
+	PixelFormatType formattype = PIXELFORMATTYPE_SFLOAT;
+	if (texture != nullptr)
+		formattype = getPixelFormatInfo(texture->getPixelFormat()).dataType;
+
+	VkClearColorValue c{};
 
-	VkClearColorValue clearColor{};
-	switch (vulkanFormat.internalFormatRepresentation)
+	switch (formattype)
 	{
-	case FORMATREPRESENTATION_FLOAT:
-		clearColor.float32[0] = 0.0f;
-		clearColor.float32[1] = 0.0f;
-		clearColor.float32[2] = 0.0f;
-		clearColor.float32[3] = 0.0f;
+	case PIXELFORMATTYPE_SINT:
+		c.int32[0] = (int32)color.r;
+		c.int32[1] = (int32)color.g;
+		c.int32[2] = (int32)color.b;
+		c.int32[3] = (int32)color.a;
 		break;
-	case FORMATREPRESENTATION_SINT:
-		clearColor.int32[0] = 0;
-		clearColor.int32[1] = 0;
-		clearColor.int32[2] = 0;
-		clearColor.int32[3] = 0;
+	case PIXELFORMATTYPE_UINT:
+		c.uint32[0] = (uint32)color.r;
+		c.uint32[1] = (uint32)color.g;
+		c.uint32[2] = (uint32)color.b;
+		c.uint32[3] = (uint32)color.a;
 		break;
-	case FORMATREPRESENTATION_UINT:
-		clearColor.uint32[0] = 0;
-		clearColor.uint32[1] = 0;
-		clearColor.uint32[2] = 0;
-		clearColor.uint32[3] = 0;
+	default:
+		{
+			Colorf cf((float)color.r, (float)color.g, (float)color.b, (float)color.a);
+			gammaCorrectColor(cf);
+			c.float32[0] = cf.r;
+			c.float32[1] = cf.g;
+			c.float32[2] = cf.b;
+			c.float32[3] = cf.a;
+		}
 		break;
 	}
-	return clearColor;
+
+	return c;
 }
 
 void Texture::generateMipmapsInternal()

+ 2 - 2
src/modules/graphics/vulkan/Texture.h

@@ -68,12 +68,12 @@ public:
 	int getMSAA() const override;
 	ptrdiff_t getHandle() const override;
 
+	static VkClearColorValue getClearColor(love::graphics::Texture *texture, const ColorD &color);
+
 private:
 	void createTextureImageView();
 	void clear();
 
-	VkClearColorValue getClearValue();
-
 	Graphics *vgfx = nullptr;
 	VkDevice device = VK_NULL_HANDLE;
 	VkImageAspectFlags imageAspect;