Skip to content

Commit

Permalink
vulkan: love.graphics.clear fixes.
Browse files Browse the repository at this point in the history
- Fix love.graphics.clear(color) when multiple canvases are active.
- Fix love.graphics.clear when an integer-format canvas is active.
  • Loading branch information
slime73 committed Mar 28, 2024
1 parent d82922f commit b33afc4
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 126 deletions.
130 changes: 28 additions & 102 deletions src/modules/graphics/vulkan/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
}
Expand All @@ -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;
Expand All @@ -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();
}
}

Expand Down
52 changes: 30 additions & 22 deletions src/modules/graphics/vulkan/Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);
}
Expand All @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions src/modules/graphics/vulkan/Texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ class Texture final
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;
Expand Down

0 comments on commit b33afc4

Please sign in to comment.