gfx/drivers/vulkan: collapse display.pipelines to STRIP-only layout

Continuation of the prim_type dead-code sweep (1ee88d08de,
696efa0f3d, 6cd9ea6f0f).  Vulkan didn't have a prim_to_vk helper
to delete, but the same dead pattern is present, expressed
through array slot indexing instead of a switch statement.

Old layout
----------

vk->display.pipelines was an 18-slot array (9 logical pipelines x
2 topologies) indexed by `(prim_type == TRIANGLESTRIP) << 1 | blend`
for the display alpha-blend pair, and by to_menu_pipeline()
returning `6 + 2*shader_idx + (prim_type == TRIANGLESTRIP)` for
the menu shaders.  Since every draw passes TRIANGLESTRIP (same
audit as the d3d/gl/metal cleanups: 15 of 15 prim_type assignments
in the codebase assign TRIANGLESTRIP, never TRIANGLES, never NONE),
the LIST entries get built by init and never read.

Slots [0], [1], [6], [8], [10], [12], [14], [16] -- the LIST
variants -- were dead at runtime in every configuration.

Slots [4] and [5] -- the HDR-only display pipelines populated by
the for(i=4;i<6;i++) loop introduced in 12d188ee1d -- were also
dead.  Both iterations of that loop produce identical pipeline
objects (no varying state between them) and no consumer ever
indexes those slots.  The dedicated vk->pipelines.hdr field
built right above the dead loop is the actual HDR composition
pipeline used by vulkan_run_hdr_pipeline at swapchain present.
The dead [4,5] population looks like copy-paste residue from
the SDR alpha-blend loop above it.

New layout
----------

Drop the LIST variants and the dead HDR slots.  Collapse to 8
slots, all TRIANGLE_STRIP:

    [0] alpha_blend, no blend
    [1] alpha_blend, blend
    [2] ribbon
    [3] ribbon_simple
    [4] snow_simple
    [5] snow
    [6] bokeh
    [7] snowflake

Same layout for vk->display.pipelines_sdr (the parallel HDR-on
SDR-offscreen variants).

Consumer updates
----------------

  - gfx_display_vk_draw at the disp_pipeline site:
        ((prim_type == TRIANGLESTRIP) << 1) | blend  ->  blend
    (always picks slot 0 or 1 in the new layout)

  - to_menu_pipeline drops its prim_type parameter and returns
    a constant 2..7 keyed off pipeline_id.

  - The overlay path's hardcoded vk->display.pipelines[3]
    ("Strip with blend") becomes vk->display.pipelines[1] (same
    pipeline, new slot number).

Init loop changes
-----------------

  - The display alpha-blend build (was for(i=0;i<4;i++) varying
    topology and blend on i bits) becomes for(i=0;i<2;i++) with
    topology set once before the loop.
  - The menu shader build (was for(i=0;i<SIZE-6;i++) using
    `i >> 1` for shader index and `i & 1` for topology) becomes
    for(i=0;i<6;i++), one iteration per shader.
  - Mirror changes for the SDR sibling loops.
  - The dead HDR-display loop at lines 3537-3542 (for(i=4;i<6;i++))
    is removed.  The vk->pipelines.hdr build right above it stays.

Why STRIP for everything is fine
--------------------------------

Same argument as the prior sweep commits: all menu draws are
axis-aligned quads (4 vertices = 2 triangles).  A tristrip
issues N-2 triangles for N vertices; a list needs 3*N vertices
for N triangles.  For a quad: 4 vs 6 vertex shader invocations.
STRIP is strictly cheaper per draw than LIST for this geometry,
so there is no performance reason to keep the LIST pipelines.

Init-time saving is small but real: 8 fewer vkCreateGraphicsPipelines
calls per init in SDR builds, 10 fewer when HDR is on.  Pipeline
creation is one of Vulkan's more expensive operations on first
compile (shader bytecode + state object).  Most of the saving
is in driver pipeline cache footprint and shader-module count;
hot-path draws hit the same pipelines they did before, just at
different slot numbers.

Verification
------------

  - clang -fsyntax-only -Wall on three configuration permutations:
    HDR + shaderpipeline, no HDR + shaderpipeline, no HDR + no
    shaderpipeline.  All clean.
  - Brace and paren balance preserved against master.
  - Diff is +78/-75 (net +3 lines) because most additions are
    layout-documenting comments; the executable code shrinks
    substantially.
This commit is contained in:
U-DESKTOP-SPFP6AQ\twistedtechre committed 2026-04-30 02:35:28 +02:00
1 parent 6cd9ea6f0f
commit 9915c52f08
1 file changed
+79 -76
+79 -76
View File
@@ -298,9 +298,25 @@ typedef struct vk
struct
{
VkPipeline pipelines[9 * 2];
/* Layout: every menu draw in the codebase uses
* GFX_DISPLAY_PRIM_TRIANGLESTRIP, so this driver only keeps
* STRIP variants:
* [0] alpha_blend, no blend
* [1] alpha_blend, blend
* [2] ribbon
* [3] ribbon_simple
* [4] snow_simple
* [5] snow
* [6] bokeh
* [7] snowflake
* All entries are TRIANGLE_STRIP topology. The history of
* this array previously included parallel TRIANGLE_LIST
* variants in even slots, but no caller ever set prim_type to
* anything other than TRIANGLESTRIP, so the LIST pipelines
* were built and never used. */
VkPipeline pipelines[8];
#ifdef VULKAN_HDR_SWAPCHAIN
VkPipeline pipelines_sdr[9 * 2]; /* SDR offscreen variants */
VkPipeline pipelines_sdr[8]; /* SDR offscreen variants, same layout */
#endif
struct vk_texture blank_texture;
} display;
@@ -1774,23 +1790,27 @@ static const float *gfx_display_vk_get_default_tex_coords(void)
}
#ifdef HAVE_SHADERPIPELINE
static unsigned to_menu_pipeline(
enum gfx_display_prim_type type, unsigned pipeline)
static unsigned to_menu_pipeline(unsigned pipeline)
{
/* The display pipeline array slots [2..7] hold the six menu
* shader pipelines (ribbon, ribbon_simple, snow_simple, snow,
* bokeh, snowflake) in that order. VIDEO_SHADER_MENU through
* VIDEO_SHADER_MENU_6 are consecutive descending #defines, so
* the mapping is a simple offset. */
switch (pipeline)
{
case VIDEO_SHADER_MENU:
return 6 + (type == GFX_DISPLAY_PRIM_TRIANGLESTRIP);
return 2;
case VIDEO_SHADER_MENU_2:
return 8 + (type == GFX_DISPLAY_PRIM_TRIANGLESTRIP);
return 3;
case VIDEO_SHADER_MENU_3:
return 10 + (type == GFX_DISPLAY_PRIM_TRIANGLESTRIP);
return 4;
case VIDEO_SHADER_MENU_4:
return 12 + (type == GFX_DISPLAY_PRIM_TRIANGLESTRIP);
return 5;
case VIDEO_SHADER_MENU_5:
return 14 + (type == GFX_DISPLAY_PRIM_TRIANGLESTRIP);
return 6;
case VIDEO_SHADER_MENU_6:
return 16 + (type == GFX_DISPLAY_PRIM_TRIANGLESTRIP);
return 7;
default:
break;
}
@@ -1987,7 +2007,7 @@ static void gfx_display_vk_draw(gfx_display_ctx_draw_t *draw,
case VIDEO_SHADER_MENU_6:
{
struct vk_draw_triangles call;
unsigned idx = to_menu_pipeline(draw->prim_type, draw->pipeline_id);
unsigned idx = to_menu_pipeline(draw->pipeline_id);
#ifdef VULKAN_HDR_SWAPCHAIN
call.pipeline = (vk->flags & VK_FLAG_SDR_PIPELINE)
@@ -2012,10 +2032,11 @@ static void gfx_display_vk_draw(gfx_display_ctx_draw_t *draw,
default:
{
struct vk_draw_triangles call;
/* Slot 0 = no blend, slot 1 = blend. Both are TRIANGLE_STRIP
* (every menu draw is a tristrip; see the comment on
* display.pipelines for the layout). */
unsigned
disp_pipeline =
((draw->prim_type == GFX_DISPLAY_PRIM_TRIANGLESTRIP) << 1)
| (((vk->flags & VK_FLAG_DISPLAY_BLEND) > 0) << 0);
disp_pipeline = ((vk->flags & VK_FLAG_DISPLAY_BLEND) > 0);
#ifdef VULKAN_HDR_SWAPCHAIN
call.pipeline = (vk->flags & VK_FLAG_SDR_PIPELINE)
? vk->display.pipelines_sdr[disp_pipeline]
@@ -3499,13 +3520,12 @@ static void vulkan_init_pipelines(vk_t *vk)
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
1, &pipe, NULL, &vk->pipelines.alpha_blend);
/* Build display pipelines. */
for (i = 0; i < 4; i++)
/* Build display pipelines (STRIP topology only).
* [0]: blend off, [1]: blend on. */
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
for (i = 0; i < 2; i++)
{
input_assembly.topology = i & 2 ?
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP :
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
blend_attachment.blendEnable = i & 1;
blend_attachment.blendEnable = i;
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
1, &pipe, NULL, &vk->display.pipelines[i]);
}
@@ -3533,13 +3553,16 @@ static void vulkan_init_pipelines(vk_t *vk)
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
1, &pipe, NULL, &vk->pipelines.hdr);
/* Build display hdr pipelines. */
for (i = 4; i < 6; i++)
{
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
1, &pipe, NULL, &vk->display.pipelines[i]);
}
/* The previous code built two additional display pipelines
* here (in old slots 4 and 5) using the hdr_frag shader. Both
* iterations of that loop produced identical pipeline objects
* (no varying state between them), and no consumer ever
* indexed slots 4 or 5 -- they were copy-paste residue from
* the SDR-side loop above and went unused even with HDR
* enabled. The dedicated `vk->pipelines.hdr` field built
* just above is the actual HDR composition pipeline; it is
* still used by vulkan_run_hdr_pipeline at the swapchain
* presentation path. */
vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL);
@@ -3572,10 +3595,13 @@ static void vulkan_init_pipelines(vk_t *vk)
* readback_render_pass. */
pipe.renderPass = vk->render_pass;
/* Other menu pipelines. */
for (i = 0; i < (int)ARRAY_SIZE(vk->display.pipelines) - 6; i++)
/* Other menu pipelines. Six STRIP-only variants populate
* slots [2..7]: ribbon, ribbon_simple, snow_simple, snow,
* bokeh, snowflake. See display.pipelines for layout. */
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
for (i = 0; i < 6; i++)
{
switch (i >> 1)
switch (i)
{
case 0:
module_info.codeSize = sizeof(pipeline_ribbon_vert);
@@ -3587,27 +3613,9 @@ static void vulkan_init_pipelines(vk_t *vk)
module_info.pCode = pipeline_ribbon_simple_vert;
break;
case 2:
module_info.codeSize = sizeof(alpha_blend_vert);
module_info.pCode = alpha_blend_vert;
break;
case 3:
module_info.codeSize = sizeof(alpha_blend_vert);
module_info.pCode = alpha_blend_vert;
break;
case 4:
module_info.codeSize = sizeof(alpha_blend_vert);
module_info.pCode = alpha_blend_vert;
break;
case 5:
module_info.codeSize = sizeof(alpha_blend_vert);
module_info.pCode = alpha_blend_vert;
break;
default:
module_info.codeSize = sizeof(alpha_blend_vert);
module_info.pCode = alpha_blend_vert;
break;
}
@@ -3616,7 +3624,7 @@ static void vulkan_init_pipelines(vk_t *vk)
vkCreateShaderModule(vk->context->device,
&module_info, NULL, &shader_stages[0].module);
switch (i >> 1)
switch (i)
{
case 0:
module_info.codeSize = sizeof(pipeline_ribbon_frag);
@@ -3657,7 +3665,7 @@ static void vulkan_init_pipelines(vk_t *vk)
vkCreateShaderModule(vk->context->device,
&module_info, NULL, &shader_stages[1].module);
switch (i >> 1)
switch (i)
{
case 0:
case 1:
@@ -3670,12 +3678,8 @@ static void vulkan_init_pipelines(vk_t *vk)
break;
}
input_assembly.topology = i & 1 ?
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP :
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
1, &pipe, NULL, &vk->display.pipelines[6 + i]);
1, &pipe, NULL, &vk->display.pipelines[2 + i]);
vkDestroyShaderModule(vk->context->device, shader_stages[0].module, NULL);
vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL);
@@ -3731,16 +3735,15 @@ static void vulkan_init_pipelines(vk_t *vk)
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
1, &pipe, NULL, &vk->pipelines.alpha_blend_sdr);
/* SDR display pipelines 0-3.
/* SDR display pipelines, slots [0..1]. STRIP-only, see the
* matching comment on the main display.pipelines build above.
* Reuse the alpha_blend vertex shader (stages[0]) and
* alpha_blend fragment shader (stages[1]) still alive
* from just above. */
for (i = 0; i < 4; i++)
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
for (i = 0; i < 2; i++)
{
input_assembly.topology = i & 2 ?
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP :
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
blend_attachment.blendEnable = i & 1;
blend_attachment.blendEnable = i;
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
1, &pipe, NULL, &vk->display.pipelines_sdr[i]);
}
@@ -3749,10 +3752,12 @@ static void vulkan_init_pipelines(vk_t *vk)
vkDestroyShaderModule(vk->context->device, shader_stages[0].module, NULL);
vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL);
/* SDR menu shader pipelines 6+ */
for (i = 0; i < (int)ARRAY_SIZE(vk->display.pipelines) - 6; i++)
/* SDR menu shader pipelines, slots [2..7]. STRIP-only;
* mirror of the main display.pipelines build. */
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
for (i = 0; i < 6; i++)
{
switch (i >> 1)
switch (i)
{
case 0:
module_info.codeSize = sizeof(pipeline_ribbon_vert);
@@ -3772,7 +3777,7 @@ static void vulkan_init_pipelines(vk_t *vk)
vkCreateShaderModule(vk->context->device,
&module_info, NULL, &shader_stages[0].module);
switch (i >> 1)
switch (i)
{
case 0:
module_info.codeSize = sizeof(pipeline_ribbon_frag);
@@ -3806,7 +3811,7 @@ static void vulkan_init_pipelines(vk_t *vk)
vkCreateShaderModule(vk->context->device,
&module_info, NULL, &shader_stages[1].module);
switch (i >> 1)
switch (i)
{
case 0:
case 1:
@@ -3819,12 +3824,8 @@ static void vulkan_init_pipelines(vk_t *vk)
break;
}
input_assembly.topology = i & 1 ?
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP :
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache,
1, &pipe, NULL, &vk->display.pipelines_sdr[6 + i]);
1, &pipe, NULL, &vk->display.pipelines_sdr[2 + i]);
vkDestroyShaderModule(vk->context->device, shader_stages[0].module, NULL);
vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL);
@@ -8149,12 +8150,14 @@ static void vulkan_render_overlay(vk_t *vk, unsigned width,
{
int idx = base + i;
struct vk_texture *tex = &vk->overlay.images[idx];
/* Slot [1] is alpha-blend, TRIANGLE_STRIP (the only
* topology this driver builds; see display.pipelines). */
#ifdef VULKAN_HDR_SWAPCHAIN
VkPipeline pipeline = (vk->flags & VK_FLAG_SDR_PIPELINE)
? vk->display.pipelines_sdr[3]
: vk->display.pipelines[3]; /* Strip with blend */
? vk->display.pipelines_sdr[1]
: vk->display.pipelines[1];
#else
VkPipeline pipeline = vk->display.pipelines[3]; /* Strip with blend */
VkPipeline pipeline = vk->display.pipelines[1];
#endif
if (tex->image)