[Fix] (MG_Backend/DirectVulkan): take a deferred window clear's sRGB decision at the glClear

This commit is contained in:
2026-11-07 08:08:48 -04:00
parent 4256a66d09
commit 13e9d0df5c
3 changed files with 12 additions and 4 deletions
@@ -633,6 +633,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Bool color = false;
VkImageAspectFlags depthStencil = 0;
ClearAttachmentPayload colorPayload{};
// colorPayload against the window format and GL_FRAMEBUFFER_SRGB as they were at the
// glClear (PreCompensateSrgbClearColor): the standalone clear a present or another
// use of the window records later must not read that state again, after the verb.
ClearAttachmentPayload colorPayloadCompensated{};
ClearAttachmentPayload depthStencilPayload{};
Bool Pending() const { return color || depthStencil != 0; }
};
@@ -642,8 +646,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void MaterializeDefaultWirePendingClear();
void FoldDefaultWirePendingClear(RenderPassEntry& begun, Uint64& variantKey, VkClearValue* merged);
// Records a clear of `area` of one wire image in a single-attachment pass of its own.
// `colorPreCompensated`: the payload already went through PreCompensateSrgbClearColor.
void RecordWireImageClear(WireImage& image, VkImageAspectFlags aspect, const ClearAttachmentPayload& payload,
const VkRect2D& area, Bool textureSurface);
const VkRect2D& area, Bool textureSurface, Bool colorPreCompensated = false);
static void NoteWirePendingClear(const WireImage& image, VkImageAspectFlags aspects, const VkClearValue& value);
VkRenderPass WireClearVariant(RenderPassEntry& begun, Uint64 variantKey);
Bool BeginWireDrawPassFolding(FrameContext::FrameData& frame, RenderPassEntry& begun, Uint64 variantKey,
@@ -1464,6 +1464,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (color) {
pending.color = true;
pending.colorPayload = payload;
pending.colorPayloadCompensated = payload;
PreCompensateSrgbClearColor(pending.colorPayloadCompensated, m_swapchainObject.GetSurfaceFormat().format);
m_swapchainObject.SetImageContentDefined(index, true);
}
if (depthStencil & VK_IMAGE_ASPECT_DEPTH_BIT) pending.depthStencilPayload.depth = payload.depth;
@@ -1494,7 +1496,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
image.image = m_swapchainObject.GetImage(pending.swapchainImageIndex);
image.format = m_swapchainObject.GetSurfaceFormat().format;
image.layout = m_swapchainObject.GetImageLayout(pending.swapchainImageIndex);
RecordWireImageClear(image, VK_IMAGE_ASPECT_COLOR_BIT, pending.colorPayload, area, false);
RecordWireImageClear(image, VK_IMAGE_ASPECT_COLOR_BIT, pending.colorPayloadCompensated, area, false,
/*colorPreCompensated=*/true);
}
if (pending.depthStencil && m_swapchainObject.GetDepthStencilImage(pending.swapchainImageIndex)) {
image.aspect = pending.depthStencil;
@@ -1115,7 +1115,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void VulkanRenderer::RecordWireImageClear(WireImage& image, VkImageAspectFlags aspect,
const ClearAttachmentPayload& payload, const VkRect2D& area,
Bool textureSurface) {
Bool textureSurface, Bool colorPreCompensated) {
const Bool color = aspect == VK_IMAGE_ASPECT_COLOR_BIT;
const auto layout =
color ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
@@ -1168,7 +1168,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
begin.framebuffer = fb;
begin.renderArea = area;
auto clearPayload = payload;
if (color) PreCompensateSrgbClearColor(clearPayload, image.format);
if (color && !colorPreCompensated) PreCompensateSrgbClearColor(clearPayload, image.format);
VkClearAttachment clear{};
clear.aspectMask = aspect;
clear.clearValue.color = MakeVkClearColorValue(clearPayload, false);