mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-06-13 14:32:57 -04:00
render/vulkan: clear blend image on first use
The two-pass blend image is created with VK_IMAGE_LAYOUT_UNDEFINED, so on its first use loadOp=LOAD loads uninitialized memory. This oughtn't be an issue, as we render onto it before we read it. These renders are blends, so even opaque content is rendered with reference to an uninit dst. This too ought to be fine: src*1 + dst*0 = src for all finite dst. But the blend image pixfmt is VK_FORMAT_R16G16B16A16_SFLOAT, so uninit pixels can be NaN, inf, or -inf, and now src*1 + dst*0 = NaN/inf/-inf. This is bad enough assuming the uninitialized blend image holds random bytes (2048/65536 values are not finite), even worse on any driver/GPU with a framebuffer compression scheme that so happens to reliably read NaNs from any uninitialized compressed image... Most Mesa drivers happen not to do this perfectly valid thing, so this is only reliably a problem (afaict) for honeykrisp i.e. AGX i.e. Asahi Linux i.e. Apple Silicon, where after an upgrade to wlroots 0.20, sway renders a black screen forever, unless you get quite lucky spamming VT switches, in which case there's flickery garbage on exactly one of the two swapchain buffers. The blend image persists across frames, so it suffices to clear before first real use. Rather than clear by hand, make a loadOp=CLEAR variant of the render pass and use it for that first frame only. Adding a pass sounds heavy, but render pass compatibility ignores loadOp and layouts such that the new pass reuses the pipelines and framebuffer, and costs one VkRenderPass object but not the usual pipeline/shader (re)compile.
This commit is contained in:
parent
63318d28b1
commit
5d150267e2
3 changed files with 40 additions and 27 deletions
|
|
@ -169,6 +169,7 @@ static void destroy_render_format_setup(struct wlr_vk_renderer *renderer,
|
|||
|
||||
VkDevice dev = renderer->dev->dev;
|
||||
vkDestroyRenderPass(dev, setup->render_pass, NULL);
|
||||
vkDestroyRenderPass(dev, setup->render_pass_clear, NULL);
|
||||
vkDestroyPipeline(dev, setup->output_pipe_identity, NULL);
|
||||
vkDestroyPipeline(dev, setup->output_pipe_srgb, NULL);
|
||||
vkDestroyPipeline(dev, setup->output_pipe_pq, NULL);
|
||||
|
|
@ -2585,6 +2586,14 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
|||
goto error;
|
||||
}
|
||||
|
||||
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
res = vkCreateRenderPass(dev, &rp_info, NULL, &setup->render_pass_clear);
|
||||
if (res != VK_SUCCESS) {
|
||||
wlr_vk_error("Failed to create 2-step clear render pass", res);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// this is only well defined if render pass has a 2nd subpass
|
||||
if (!init_blend_to_output_pipeline(
|
||||
renderer, setup->render_pass, renderer->output_pipe_layout,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue