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.
This commit is contained in:
Sasha Szpakowski
2024-03-28 19:00:29 -03:00
parent d82922f774
commit b33afc4371
3 changed files with 60 additions and 126 deletions
+28 -102
View File
@@ -185,89 +185,12 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d
if (!color.hasValue && !stencil.hasValue && !depth.hasValue) if (!color.hasValue && !stencil.hasValue && !depth.hasValue)
return; return;
flushBatchedDraws(); std::vector<OptionalColorD> colors;
if (renderPassState.active) if (color.hasValue)
{ colors.resize(std::max(1, (int)states.back().renderTargets.colors.size()), color);
VkClearAttachment attachment{};
if (color.hasValue) clear(colors, stencil, depth);
{
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;
Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a);
gammaCorrectColor(cf);
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();
}
} }
void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble 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(); 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) if (renderPassState.active)
{ {
std::vector<VkClearAttachment> attachments; std::vector<VkClearAttachment> attachments;
for (const auto &color : colors) for (size_t i = 0; i < ncolors; i++)
{ {
const OptionalColorD &color = colors[i];
VkClearAttachment attachment{}; VkClearAttachment attachment{};
if (color.hasValue) if (color.hasValue)
{ {
Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); auto texture = i < rts.size() ? rts[i].texture.get() : nullptr;
gammaCorrectColor(cf);
attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
attachment.clearValue.color.float32[0] = static_cast<float>(cf.r); attachment.clearValue.color = Texture::getClearColor(texture, color.value);
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);
} }
attachments.push_back(attachment); 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); depthStencilAttachment.clearValue.depthStencil.depth = static_cast<float>(depth.value);
} }
attachments.push_back(depthStencilAttachment); if (stencil.hasValue || depth.hasValue)
attachments.push_back(depthStencilAttachment);
VkClearRect rect{}; VkClearRect rect{};
rect.layerCount = 1; rect.layerCount = 1;
@@ -324,36 +248,38 @@ void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt sten
} }
else else
{ {
for (size_t i = 0; i < colors.size(); i++) for (size_t i = 0; i < ncolors; i++)
{ {
if (colors[i].hasValue) if (colors[i].hasValue)
{ {
renderPassState.renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; renderPassState.renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
auto &color = colors[i]; auto texture = i < rts.size() ? rts[i].texture.get() : nullptr;
Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); renderPassState.clearColors[i].color = Texture::getClearColor(texture, colors[i].value);
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);
} }
} }
if (depth.hasValue) if (depth.hasValue)
{ {
renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; 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) if (stencil.hasValue)
{ {
renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; 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
View File
@@ -383,7 +383,7 @@ void Texture::clear()
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); 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); 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) 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); 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 clearColor{}; VkClearColorValue c{};
switch (vulkanFormat.internalFormatRepresentation)
switch (formattype)
{ {
case FORMATREPRESENTATION_FLOAT: case PIXELFORMATTYPE_SINT:
clearColor.float32[0] = 0.0f; c.int32[0] = (int32)color.r;
clearColor.float32[1] = 0.0f; c.int32[1] = (int32)color.g;
clearColor.float32[2] = 0.0f; c.int32[2] = (int32)color.b;
clearColor.float32[3] = 0.0f; c.int32[3] = (int32)color.a;
break; break;
case FORMATREPRESENTATION_SINT: case PIXELFORMATTYPE_UINT:
clearColor.int32[0] = 0; c.uint32[0] = (uint32)color.r;
clearColor.int32[1] = 0; c.uint32[1] = (uint32)color.g;
clearColor.int32[2] = 0; c.uint32[2] = (uint32)color.b;
clearColor.int32[3] = 0; c.uint32[3] = (uint32)color.a;
break; break;
case FORMATREPRESENTATION_UINT: default:
clearColor.uint32[0] = 0; {
clearColor.uint32[1] = 0; Colorf cf((float)color.r, (float)color.g, (float)color.b, (float)color.a);
clearColor.uint32[2] = 0; gammaCorrectColor(cf);
clearColor.uint32[3] = 0; c.float32[0] = cf.r;
c.float32[1] = cf.g;
c.float32[2] = cf.b;
c.float32[3] = cf.a;
}
break; break;
} }
return clearColor;
return c;
} }
void Texture::generateMipmapsInternal() void Texture::generateMipmapsInternal()
+2 -2
View File
@@ -68,12 +68,12 @@ public:
int getMSAA() const override; int getMSAA() const override;
ptrdiff_t getHandle() const override; ptrdiff_t getHandle() const override;
static VkClearColorValue getClearColor(love::graphics::Texture *texture, const ColorD &color);
private: private:
void createTextureImageView(); void createTextureImageView();
void clear(); void clear();
VkClearColorValue getClearValue();
Graphics *vgfx = nullptr; Graphics *vgfx = nullptr;
VkDevice device = VK_NULL_HANDLE; VkDevice device = VK_NULL_HANDLE;
VkImageAspectFlags imageAspect; VkImageAspectFlags imageAspect;