gpu: Introduce the concept of "variation"

A variation is a #define/specialization constant that every shader can
use to specialize itself as it sees fit.

This commit adds the infrastrcture, future commits will add
implementations.
This commit is contained in:
Benjamin Otte 2023-12-31 05:38:56 +01:00
parent 64e5c76323
commit d900407a18
25 changed files with 70 additions and 9 deletions

View File

@ -33,6 +33,7 @@ typedef struct _GLProgramKey GLProgramKey;
struct _GLProgramKey
{
const GskGpuShaderOpClass *op_class;
guint32 variation;
GskGpuShaderClip clip;
guint n_external_textures;
};
@ -46,6 +47,7 @@ gl_program_key_hash (gconstpointer data)
return GPOINTER_TO_UINT (key->op_class) ^
key->clip ^
(key->variation << 2) ^
(key->n_external_textures << 24);
}
@ -57,6 +59,7 @@ gl_program_key_equal (gconstpointer a,
const GLProgramKey *keyb = b;
return keya->op_class == keyb->op_class &&
keya->variation == keyb->variation &&
keya->clip == keyb->clip &&
keya->n_external_textures == keyb->n_external_textures;
}
@ -358,6 +361,7 @@ static GLuint
gsk_gl_device_load_shader (GskGLDevice *self,
const char *program_name,
GLenum shader_type,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures,
GError **error)
@ -404,6 +408,8 @@ gsk_gl_device_load_shader (GskGLDevice *self,
return 0;
}
g_string_append_printf (preamble, "#define GSK_VARIATION %uu\n", variation);
switch (clip)
{
case GSK_GPU_SHADER_CLIP_NONE:
@ -455,6 +461,7 @@ gsk_gl_device_load_shader (GskGLDevice *self,
static GLuint
gsk_gl_device_load_program (GskGLDevice *self,
const char *program_name,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures,
GError **error)
@ -462,11 +469,11 @@ gsk_gl_device_load_program (GskGLDevice *self,
GLuint vertex_shader_id, fragment_shader_id, program_id;
GLint link_status;
vertex_shader_id = gsk_gl_device_load_shader (self, program_name, GL_VERTEX_SHADER, clip, n_external_textures, error);
vertex_shader_id = gsk_gl_device_load_shader (self, program_name, GL_VERTEX_SHADER, variation, clip, n_external_textures, error);
if (vertex_shader_id == 0)
return 0;
fragment_shader_id = gsk_gl_device_load_shader (self, program_name, GL_FRAGMENT_SHADER, clip, n_external_textures, error);
fragment_shader_id = gsk_gl_device_load_shader (self, program_name, GL_FRAGMENT_SHADER, variation, clip, n_external_textures, error);
if (fragment_shader_id == 0)
return 0;
@ -517,6 +524,7 @@ gsk_gl_device_load_program (GskGLDevice *self,
void
gsk_gl_device_use_program (GskGLDevice *self,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures)
{
@ -524,6 +532,7 @@ gsk_gl_device_use_program (GskGLDevice *self,
GLuint program_id;
GLProgramKey key = {
.op_class = op_class,
.variation = variation,
.clip = clip,
.n_external_textures = n_external_textures
};
@ -536,7 +545,7 @@ gsk_gl_device_use_program (GskGLDevice *self,
return;
}
program_id = gsk_gl_device_load_program (self, op_class->shader_name, clip, n_external_textures, &error);
program_id = gsk_gl_device_load_program (self, op_class->shader_name, variation, clip, n_external_textures, &error);
if (program_id == 0)
{
g_critical ("Failed to load shader program: %s", error->message);

View File

@ -13,6 +13,7 @@ GskGpuDevice * gsk_gl_device_get_for_display (GdkDisp
void gsk_gl_device_use_program (GskGLDevice *self,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures);

View File

@ -207,6 +207,7 @@ gsk_gl_frame_init (GskGLFrame *self)
void
gsk_gl_frame_use_program (GskGLFrame *self,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures)
{
@ -214,6 +215,7 @@ gsk_gl_frame_use_program (GskGLFrame *self,
gsk_gl_device_use_program (GSK_GL_DEVICE (gsk_gpu_frame_get_device (GSK_GPU_FRAME (self))),
op_class,
variation,
clip,
n_external_textures);

View File

@ -10,6 +10,7 @@ G_DECLARE_FINAL_TYPE (GskGLFrame, gsk_gl_frame, GSK, GL_FRAME, GskGpuFrame)
void gsk_gl_frame_use_program (GskGLFrame *self,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
guint n_external_textures);

View File

@ -66,6 +66,7 @@ gsk_gpu_blur_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_BLUR_OP_CLASS,
0,
clip,
desc,
&instance);

View File

@ -112,6 +112,7 @@ gsk_gpu_border_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_BORDER_OP_CLASS,
0,
clip,
NULL,
&instance);

View File

@ -93,6 +93,7 @@ gsk_gpu_box_shadow_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_BOX_SHADOW_OP_CLASS,
0,
clip,
NULL,
&instance);

View File

@ -66,6 +66,7 @@ gsk_gpu_colorize_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_COLORIZE_OP_CLASS,
0,
clip,
descriptors,
&instance);

View File

@ -66,6 +66,7 @@ gsk_gpu_color_matrix_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_COLOR_MATRIX_OP_CLASS,
0,
clip,
desc,
&instance);

View File

@ -63,6 +63,7 @@ gsk_gpu_color_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_COLOR_OP_CLASS,
0,
clip,
NULL,
&instance);

View File

@ -67,6 +67,7 @@ gsk_gpu_conic_gradient_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_CONIC_GRADIENT_OP_CLASS,
0,
clip,
NULL,
&instance);

View File

@ -70,6 +70,7 @@ gsk_gpu_cross_fade_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_CROSS_FADE_OP_CLASS,
0,
clip,
desc,
&instance);

View File

@ -71,6 +71,7 @@ gsk_gpu_linear_gradient_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_LINEAR_GRADIENT_OP_CLASS,
0,
clip,
NULL,
&instance);

View File

@ -69,6 +69,7 @@ gsk_gpu_mask_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_MASK_OP_CLASS,
0,
clip,
desc,
&instance);

View File

@ -25,6 +25,7 @@ struct _GskGLCommandState
gsize flip_y;
struct {
const GskGpuOpClass *op_class;
guint32 variation;
GskGpuShaderClip clip;
gsize n_external;
} current_program;

View File

@ -73,6 +73,7 @@ gsk_gpu_radial_gradient_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_RADIAL_GRADIENT_OP_CLASS,
0,
clip,
NULL,
&instance);

View File

@ -63,6 +63,7 @@ gsk_gpu_rounded_color_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_ROUNDED_COLOR_OP_CLASS,
0,
clip,
NULL,
&instance);

View File

@ -59,6 +59,8 @@ gsk_gpu_shader_op_vk_command_n (GskGpuOp *op,
if (next->op_class != op->op_class ||
next_shader->desc != self->desc ||
next_shader->variation != self->variation ||
next_shader->clip != self->clip ||
next_shader->vertex_offset != self->vertex_offset + i * shader_op_class->vertex_size)
break;
@ -70,6 +72,7 @@ gsk_gpu_shader_op_vk_command_n (GskGpuOp *op,
gsk_vulkan_device_get_vk_pipeline (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
gsk_vulkan_descriptors_get_pipeline_layout (state->desc),
shader_op_class,
self->variation,
self->clip,
state->blend,
state->vk_format,
@ -110,14 +113,17 @@ gsk_gpu_shader_op_gl_command_n (GskGpuOp *op,
n_external = 0;
if (state->current_program.op_class != op->op_class ||
state->current_program.variation != self->variation ||
state->current_program.clip != self->clip ||
state->current_program.n_external != n_external)
{
state->current_program.op_class = op->op_class;
state->current_program.variation = self->variation;
state->current_program.clip = self->clip;
state->current_program.n_external = n_external;
gsk_gl_frame_use_program (GSK_GL_FRAME (frame),
shader_op_class,
self->variation,
self->clip,
n_external);
}
@ -139,6 +145,8 @@ gsk_gpu_shader_op_gl_command_n (GskGpuOp *op,
if (next->op_class != op->op_class ||
next_shader->desc != self->desc ||
next_shader->variation != self->variation ||
next_shader->clip != self->clip ||
next_shader->vertex_offset != self->vertex_offset + i * shader_op_class->vertex_size)
break;
@ -177,6 +185,7 @@ gsk_gpu_shader_op_gl_command (GskGpuOp *op,
GskGpuShaderOp *
gsk_gpu_shader_op_alloc (GskGpuFrame *frame,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
GskGpuDescriptors *desc,
gpointer out_vertex_data)
@ -185,6 +194,7 @@ gsk_gpu_shader_op_alloc (GskGpuFrame *frame,
self = (GskGpuShaderOp *) gsk_gpu_op_alloc (frame, &op_class->parent_class);
self->variation = variation;
self->clip = clip;
if (desc)
self->desc = g_object_ref (desc);

View File

@ -11,6 +11,7 @@ struct _GskGpuShaderOp
GskGpuOp parent_op;
GskGpuDescriptors *desc;
guint32 variation;
GskGpuShaderClip clip;
gsize vertex_offset;
};
@ -29,6 +30,7 @@ struct _GskGpuShaderOpClass
GskGpuShaderOp * gsk_gpu_shader_op_alloc (GskGpuFrame *frame,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
GskGpuDescriptors *desc,
gpointer out_vertex_data);

View File

@ -65,6 +65,7 @@ gsk_gpu_straight_alpha_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_STRAIGHT_ALPHA_OP_CLASS,
0,
clip,
desc,
&instance);

View File

@ -64,6 +64,7 @@ gsk_gpu_texture_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_TEXTURE_OP_CLASS,
0,
clip,
desc,
&instance);

View File

@ -63,6 +63,7 @@ gsk_gpu_uber_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_UBER_OP_CLASS,
0,
clip,
desc,
&instance);

View File

@ -76,6 +76,7 @@ struct _ConversionCacheEntry
struct _PipelineCacheKey
{
const GskGpuShaderOpClass *op_class;
guint32 variation;
GskGpuShaderClip clip;
GskGpuBlend blend;
VkFormat format;
@ -113,8 +114,9 @@ pipeline_cache_key_hash (gconstpointer data)
return GPOINTER_TO_UINT (key->op_class) ^
key->clip ^
(key->blend << 2) ^
(key->format << 4);
(key->variation << 2) ^
(key->blend << 6) ^
(key->format << 8);
}
static gboolean
@ -125,6 +127,7 @@ pipeline_cache_key_equal (gconstpointer a,
const PipelineCacheKey *keyb = b;
return keya->op_class == keyb->op_class &&
keya->variation == keyb->variation &&
keya->clip == keyb->clip &&
keya->blend == keyb->blend &&
keya->format == keyb->format;
@ -880,6 +883,7 @@ struct _GskVulkanShaderSpecialization
guint32 n_immutable_samplers;
guint32 n_samplers;
guint32 n_buffers;
guint32 variation;
};
static VkPipelineColorBlendAttachmentState blend_attachment_states[2] = {
@ -915,6 +919,7 @@ VkPipeline
gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
GskVulkanPipelineLayout *layout,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
GskGpuBlend blend,
VkFormat format,
@ -928,6 +933,7 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
cache_key = (PipelineCacheKey) {
.op_class = op_class,
.variation = variation,
.clip = clip,
.blend = blend,
.format = format,
@ -966,8 +972,8 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
.module = gdk_display_get_vk_shader_module (display, vertex_shader_name),
.pName = "main",
.pSpecializationInfo = &(VkSpecializationInfo) {
.mapEntryCount = 4,
.pMapEntries = (VkSpecializationMapEntry[4]) {
.mapEntryCount = 5,
.pMapEntries = (VkSpecializationMapEntry[5]) {
{
.constantID = 0,
.offset = G_STRUCT_OFFSET (GskVulkanShaderSpecialization, clip),
@ -988,6 +994,11 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
.offset = G_STRUCT_OFFSET (GskVulkanShaderSpecialization, n_buffers),
.size = sizeof (guint32),
},
{
.constantID = 4,
.offset = G_STRUCT_OFFSET (GskVulkanShaderSpecialization, variation),
.size = sizeof (guint32),
},
},
.dataSize = sizeof (GskVulkanShaderSpecialization),
.pData = &(GskVulkanShaderSpecialization) {
@ -995,6 +1006,7 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
.n_immutable_samplers = MAX (1, layout->setup.n_immutable_samplers),
.n_samplers = layout->setup.n_samplers - MAX (3 * layout->setup.n_immutable_samplers, 1),
.n_buffers = layout->setup.n_buffers,
.variation = variation,
},
},
},
@ -1004,8 +1016,8 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
.module = gdk_display_get_vk_shader_module (display, fragment_shader_name),
.pName = "main",
.pSpecializationInfo = &(VkSpecializationInfo) {
.mapEntryCount = 4,
.pMapEntries = (VkSpecializationMapEntry[4]) {
.mapEntryCount = 5,
.pMapEntries = (VkSpecializationMapEntry[5]) {
{
.constantID = 0,
.offset = G_STRUCT_OFFSET (GskVulkanShaderSpecialization, clip),
@ -1026,6 +1038,11 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
.offset = G_STRUCT_OFFSET (GskVulkanShaderSpecialization, n_buffers),
.size = sizeof (guint32),
},
{
.constantID = 4,
.offset = G_STRUCT_OFFSET (GskVulkanShaderSpecialization, variation),
.size = sizeof (guint32),
},
},
.dataSize = sizeof (GskVulkanShaderSpecialization),
.pData = &(GskVulkanShaderSpecialization) {
@ -1033,6 +1050,7 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
.n_immutable_samplers = MAX (1, layout->setup.n_immutable_samplers),
.n_samplers = layout->setup.n_samplers - MAX (3 * layout->setup.n_immutable_samplers, 1),
.n_buffers = layout->setup.n_buffers,
.variation = variation,
},
},
},

View File

@ -73,6 +73,7 @@ VkRenderPass gsk_vulkan_device_get_vk_render_pass (GskVulk
VkPipeline gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
GskVulkanPipelineLayout*layout,
const GskGpuShaderOpClass *op_class,
guint32 variation,
GskGpuShaderClip clip,
GskGpuBlend blend,
VkFormat format,

View File

@ -14,6 +14,7 @@ layout(constant_id=0) const uint GSK_SHADER_CLIP = GSK_GPU_SHADER_CLIP_NONE;
layout(constant_id=1) const uint GSK_N_IMMUTABLE_SAMPLERS = 32;
layout(constant_id=2) const uint GSK_N_SAMPLERS = 32;
layout(constant_id=3) const uint GSK_N_BUFFERS = 32;
layout(constant_id=4) const uint GSK_VARIATION = 0;
#define GSK_GLOBAL_MVP push.mvp
#define GSK_GLOBAL_CLIP push.clip