Skip to content

Commit 8fa8418

Browse files
committed
VULKAN: Build SDR display pipeline set for HDR offscreen compositing
Follow-up to d250194 (build display pipelines against swapchain render pass). That commit fixed the KMS crash (#18761) by building all display/menu pipelines against vk->render_pass (the swapchain format) instead of vk->sdr_render_pass (hardcoded B8G8R8A8_UNORM). This was correct for the non-HDR path but left a gap in the HDR offscreen compositing path. When HDR is active, the menu is rendered into a B8G8R8A8 offscreen buffer under sdr_render_pass, then composited onto the HDR swapchain. If the swapchain format differs from B8G8R8A8 (which is the common HDR case -- the swapchain uses a wide-gamut format like R16G16B16A16_SFLOAT or A2B10G10R10_UNORM), the main pipeline set (built against render_pass) is incompatible with sdr_render_pass. Using those pipelines in the HDR offscreen render pass would be the same class of render-pass compatibility violation that d250194 fixed for the non-HDR path. Fix: when VK_CTX_FLAG_HDR_SUPPORT is set, build a parallel set of display/menu pipelines against sdr_render_pass. At runtime, switch to the SDR pipeline variants while rendering into the HDR offscreen buffer, and switch back when the render pass ends. New storage: - vk->pipelines.font_sdr - vk->pipelines.alpha_blend_sdr - vk->display.pipelines_sdr[9 * 2] These are created alongside the existing pipeline set during vulkan_init_pipelines, using identical shader modules and pipeline state -- only pipe.renderPass differs. Destroyed in vulkan_deinit_pipelines. Runtime switching via VK_FLAG_SDR_PIPELINE (new flag, bit 16): - Set after vkCmdBeginRenderPass with sdr_render_pass on the HDR offscreen compositing path - Cleared before vkCmdEndRenderPass - Checked in four draw paths: * gfx_display_vk_draw menu shader case (ribbon/snow/bokeh) * gfx_display_vk_draw default case (display quads) * vulkan_raster_font_render_msg (font pipeline) * vulkan_frame menu texture overlay (alpha_blend pipeline) Non-HDR builds: all SDR pipeline code is #ifdef VULKAN_HDR_SWAPCHAIN guarded. Zero impact on builds without HDR support. Non-HDR runtime: VK_FLAG_SDR_PIPELINE is never set. All draw paths use the main pipeline set unconditionally. Zero overhead. HDR with B8G8R8A8 swapchain (unusual but possible): render_pass and sdr_render_pass have the same format, so both pipeline sets are identical. No visual difference, small extra memory for the duplicate pipelines. Cost: 18 additional VkPipeline objects + 2 named pipelines when HDR is supported. One-time creation cost at driver init. Runtime cost is one flag check per draw call on HDR paths only.
1 parent d250194 commit 8fa8418

2 files changed

Lines changed: 196 additions & 6 deletions

File tree

gfx/common/vulkan_common.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ enum vk_flags
107107
VK_FLAG_READBACK_PENDING = (1 << 12),
108108
VK_FLAG_READBACK_STREAMED = (1 << 13),
109109
VK_FLAG_OVERLAY_ENABLE = (1 << 14),
110-
VK_FLAG_OVERLAY_FULLSCREEN = (1 << 15)
110+
VK_FLAG_OVERLAY_FULLSCREEN = (1 << 15),
111+
VK_FLAG_SDR_PIPELINE = (1 << 16)
111112
};
112113

113114
enum vk_texture_type

gfx/drivers/vulkan.c

Lines changed: 194 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,8 @@ typedef struct vk
288288
#ifdef VULKAN_HDR_SWAPCHAIN
289289
VkPipeline hdr;
290290
VkPipeline hdr_to_sdr; /* for readback */
291+
VkPipeline alpha_blend_sdr; /* for SDR offscreen compositing */
292+
VkPipeline font_sdr; /* for SDR offscreen compositing */
291293
#endif /* VULKAN_HDR_SWAPCHAIN */
292294
VkDescriptorSetLayout set_layout;
293295
VkPipelineLayout layout;
@@ -297,6 +299,9 @@ typedef struct vk
297299
struct
298300
{
299301
VkPipeline pipelines[9 * 2];
302+
#ifdef VULKAN_HDR_SWAPCHAIN
303+
VkPipeline pipelines_sdr[9 * 2]; /* SDR offscreen variants */
304+
#endif
300305
struct vk_texture blank_texture;
301306
} display;
302307

@@ -1946,9 +1951,15 @@ static void gfx_display_vk_draw(gfx_display_ctx_draw_t *draw,
19461951
case VIDEO_SHADER_MENU_6:
19471952
{
19481953
struct vk_draw_triangles call;
1954+
unsigned idx = to_menu_pipeline(draw->prim_type, draw->pipeline_id);
19491955

1950-
call.pipeline = vk->display.pipelines[
1951-
to_menu_pipeline(draw->prim_type, draw->pipeline_id)];
1956+
#ifdef VULKAN_HDR_SWAPCHAIN
1957+
call.pipeline = (vk->flags & VK_FLAG_SDR_PIPELINE)
1958+
? vk->display.pipelines_sdr[idx]
1959+
: vk->display.pipelines[idx];
1960+
#else
1961+
call.pipeline = vk->display.pipelines[idx];
1962+
#endif
19521963
call.texture = NULL;
19531964
call.sampler = VK_NULL_HANDLE;
19541965
call.uniform = draw->backend_data;
@@ -1969,7 +1980,13 @@ static void gfx_display_vk_draw(gfx_display_ctx_draw_t *draw,
19691980
disp_pipeline =
19701981
((draw->prim_type == GFX_DISPLAY_PRIM_TRIANGLESTRIP) << 1)
19711982
| (((vk->flags & VK_FLAG_DISPLAY_BLEND) > 0) << 0);
1983+
#ifdef VULKAN_HDR_SWAPCHAIN
1984+
call.pipeline = (vk->flags & VK_FLAG_SDR_PIPELINE)
1985+
? vk->display.pipelines_sdr[disp_pipeline]
1986+
: vk->display.pipelines[disp_pipeline];
1987+
#else
19721988
call.pipeline = vk->display.pipelines[disp_pipeline];
1989+
#endif
19731990
call.texture = texture;
19741991
call.sampler = (texture->flags & VK_TEX_FLAG_MIPMAP)
19751992
? vk->samplers.mipmap_linear
@@ -2643,12 +2660,20 @@ static void vulkan_font_render_msg(
26432660
vulkan_transition_texture(vk, vk->cmd, &font->texture_optimal);
26442661

26452662
/* Pipeline and dynamic state. */
2646-
if (vk->pipelines.font != vk->tracker.pipeline)
2663+
{
2664+
#ifdef VULKAN_HDR_SWAPCHAIN
2665+
VkPipeline font_pipe = (vk->flags & VK_FLAG_SDR_PIPELINE)
2666+
? vk->pipelines.font_sdr
2667+
: vk->pipelines.font;
2668+
#else
2669+
VkPipeline font_pipe = vk->pipelines.font;
2670+
#endif
2671+
if (font_pipe != vk->tracker.pipeline)
26472672
{
26482673
VkRect2D sci;
26492674
vkCmdBindPipeline(vk->cmd,
2650-
VK_PIPELINE_BIND_POINT_GRAPHICS, vk->pipelines.font);
2651-
vk->tracker.pipeline = vk->pipelines.font;
2675+
VK_PIPELINE_BIND_POINT_GRAPHICS, font_pipe);
2676+
vk->tracker.pipeline = font_pipe;
26522677
vk->tracker.dirty |= VULKAN_DIRTY_DYNAMIC_BIT;
26532678

26542679
if (vk->flags & VK_FLAG_TRACKER_USE_SCISSOR)
@@ -2682,6 +2707,7 @@ static void vulkan_font_render_msg(
26822707
vkCmdSetScissor (vk->cmd, 0, 1, &sci);
26832708
vk->tracker.dirty &= ~VULKAN_DIRTY_DYNAMIC_BIT;
26842709
}
2710+
} /* end of font_pipe scope */
26852711

26862712
/* Descriptor set: UBO (mvp) + combined image sampler (font atlas). */
26872713
{
@@ -3619,6 +3645,148 @@ static void vulkan_init_pipelines(vk_t *vk)
36193645
vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL);
36203646
}
36213647

3648+
#ifdef VULKAN_HDR_SWAPCHAIN
3649+
/* When HDR is supported, the menu is rendered into an SDR
3650+
* offscreen buffer (B8G8R8A8_UNORM) under sdr_render_pass,
3651+
* then composited onto the HDR swapchain. If the swapchain
3652+
* format differs from B8G8R8A8, the main pipeline set (built
3653+
* against render_pass) is incompatible with sdr_render_pass.
3654+
* Build a parallel SDR set against sdr_render_pass. */
3655+
if (vk->context->flags & VK_CTX_FLAG_HDR_SUPPORT)
3656+
{
3657+
pipe.renderPass = vk->sdr_render_pass;
3658+
3659+
/* SDR font pipeline */
3660+
module_info.codeSize = sizeof(alpha_blend_vert);
3661+
module_info.pCode = alpha_blend_vert;
3662+
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
3663+
shader_stages[0].pName = "main";
3664+
vkCreateShaderModule(vk->context->device,
3665+
&module_info, NULL, &shader_stages[0].module);
3666+
3667+
module_info.codeSize = sizeof(font_frag);
3668+
module_info.pCode = font_frag;
3669+
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
3670+
shader_stages[1].pName = "main";
3671+
vkCreateShaderModule(vk->context->device,
3672+
&module_info, NULL, &shader_stages[1].module);
3673+
3674+
blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
3675+
blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
3676+
blend_attachment.blendEnable = VK_TRUE;
3677+
3678+
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
3679+
1, &pipe, NULL, &vk->pipelines.font_sdr);
3680+
vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL);
3681+
3682+
/* SDR alpha_blend pipeline */
3683+
module_info.codeSize = sizeof(alpha_blend_frag);
3684+
module_info.pCode = alpha_blend_frag;
3685+
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
3686+
shader_stages[1].pName = "main";
3687+
vkCreateShaderModule(vk->context->device,
3688+
&module_info, NULL, &shader_stages[1].module);
3689+
3690+
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
3691+
1, &pipe, NULL, &vk->pipelines.alpha_blend_sdr);
3692+
vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL);
3693+
3694+
/* SDR display pipelines 0-3 */
3695+
for (i = 0; i < 4; i++)
3696+
{
3697+
input_assembly.topology = i & 2 ?
3698+
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP :
3699+
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
3700+
blend_attachment.blendEnable = i & 1;
3701+
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
3702+
1, &pipe, NULL, &vk->display.pipelines_sdr[i]);
3703+
}
3704+
3705+
/* SDR menu shader pipelines 6+ */
3706+
for (i = 0; i < (int)ARRAY_SIZE(vk->display.pipelines) - 6; i++)
3707+
{
3708+
switch (i >> 1)
3709+
{
3710+
case 0:
3711+
module_info.codeSize = sizeof(pipeline_ribbon_vert);
3712+
module_info.pCode = pipeline_ribbon_vert;
3713+
break;
3714+
case 1:
3715+
module_info.codeSize = sizeof(pipeline_ribbon_simple_vert);
3716+
module_info.pCode = pipeline_ribbon_simple_vert;
3717+
break;
3718+
default:
3719+
module_info.codeSize = sizeof(alpha_blend_vert);
3720+
module_info.pCode = alpha_blend_vert;
3721+
break;
3722+
}
3723+
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
3724+
shader_stages[0].pName = "main";
3725+
vkCreateShaderModule(vk->context->device,
3726+
&module_info, NULL, &shader_stages[0].module);
3727+
3728+
switch (i >> 1)
3729+
{
3730+
case 0:
3731+
module_info.codeSize = sizeof(pipeline_ribbon_frag);
3732+
module_info.pCode = pipeline_ribbon_frag;
3733+
break;
3734+
case 1:
3735+
module_info.codeSize = sizeof(pipeline_ribbon_simple_frag);
3736+
module_info.pCode = pipeline_ribbon_simple_frag;
3737+
break;
3738+
case 2:
3739+
module_info.codeSize = sizeof(pipeline_snow_simple_frag);
3740+
module_info.pCode = pipeline_snow_simple_frag;
3741+
break;
3742+
case 3:
3743+
module_info.codeSize = sizeof(pipeline_snow_frag);
3744+
module_info.pCode = pipeline_snow_frag;
3745+
break;
3746+
case 4:
3747+
module_info.codeSize = sizeof(pipeline_bokeh_frag);
3748+
module_info.pCode = pipeline_bokeh_frag;
3749+
break;
3750+
case 5:
3751+
module_info.codeSize = sizeof(pipeline_snowflake_frag);
3752+
module_info.pCode = pipeline_snowflake_frag;
3753+
break;
3754+
default:
3755+
break;
3756+
}
3757+
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
3758+
shader_stages[1].pName = "main";
3759+
vkCreateShaderModule(vk->context->device,
3760+
&module_info, NULL, &shader_stages[1].module);
3761+
3762+
switch (i >> 1)
3763+
{
3764+
case 0:
3765+
case 1:
3766+
blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_DST_COLOR;
3767+
blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
3768+
break;
3769+
default:
3770+
blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
3771+
blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
3772+
break;
3773+
}
3774+
3775+
input_assembly.topology = i & 1 ?
3776+
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP :
3777+
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
3778+
3779+
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
3780+
1, &pipe, NULL, &vk->display.pipelines_sdr[6 + i]);
3781+
3782+
vkDestroyShaderModule(vk->context->device, shader_stages[0].module, NULL);
3783+
vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL);
3784+
}
3785+
3786+
vkDestroyShaderModule(vk->context->device, shader_stages[0].module, NULL);
3787+
}
3788+
#endif /* VULKAN_HDR_SWAPCHAIN */
3789+
36223790
cpipe.layout = vk->pipelines.layout;
36233791
cpipe.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
36243792
cpipe.stage.pName = "main";
@@ -3817,6 +3985,14 @@ if (vk->context->flags & VK_CTX_FLAG_HDR_SUPPORT)
38173985
vk->pipelines.hdr, NULL);
38183986
vkDestroyPipeline(vk->context->device,
38193987
vk->pipelines.hdr_to_sdr, NULL);
3988+
vkDestroyPipeline(vk->context->device,
3989+
vk->pipelines.font_sdr, NULL);
3990+
vkDestroyPipeline(vk->context->device,
3991+
vk->pipelines.alpha_blend_sdr, NULL);
3992+
3993+
for (i = 0; i < (int)ARRAY_SIZE(vk->display.pipelines_sdr); i++)
3994+
vkDestroyPipeline(vk->context->device,
3995+
vk->display.pipelines_sdr[i], NULL);
38203996
}
38213997
#endif /* VULKAN_HDR_SWAPCHAIN */
38223998

@@ -6568,6 +6744,10 @@ static bool vulkan_frame(void *data, const void *frame,
65686744

65696745
/* Begin render pass and set up viewport */
65706746
vkCmdBeginRenderPass(vk->cmd, &rp_info, VK_SUBPASS_CONTENTS_INLINE);
6747+
6748+
/* Signal draw functions to use SDR pipeline variants
6749+
* while rendering into the B8G8R8A8 offscreen buffer. */
6750+
vk->flags |= VK_FLAG_SDR_PIPELINE;
65716751
}
65726752
#endif /* VULKAN_HDR_SWAPCHAIN */
65736753

@@ -6592,7 +6772,13 @@ static bool vulkan_frame(void *data, const void *frame,
65926772
vulkan_set_viewport(vk, width, height, ((vk->flags &
65936773
VK_FLAG_MENU_FULLSCREEN) > 0), false);
65946774

6775+
#ifdef VULKAN_HDR_SWAPCHAIN
6776+
quad.pipeline = (vk->flags & VK_FLAG_SDR_PIPELINE)
6777+
? vk->pipelines.alpha_blend_sdr
6778+
: vk->pipelines.alpha_blend;
6779+
#else
65956780
quad.pipeline = vk->pipelines.alpha_blend;
6781+
#endif
65966782
quad.texture = &vk->menu.textures[vk->menu.last_index];
65976783

65986784
if (optimal->memory != VK_NULL_HANDLE)
@@ -6636,6 +6822,9 @@ static bool vulkan_frame(void *data, const void *frame,
66366822
#endif
66376823

66386824
/* End the render pass. We're done rendering to backbuffer now. */
6825+
#ifdef VULKAN_HDR_SWAPCHAIN
6826+
vk->flags &= ~VK_FLAG_SDR_PIPELINE;
6827+
#endif
66396828
if(end_main_pass) vkCmdEndRenderPass(vk->cmd);
66406829

66416830
#ifdef VULKAN_HDR_SWAPCHAIN

0 commit comments

Comments
 (0)