gpu: Prepare GL rendering for samplerExternalEOS

Carry an n_external_textures variable around when selecting programs and
compile different programs for different amounts of external textures.

For now, this code is unused, but dmabufs will need it.
This commit is contained in:
Benjamin Otte 2023-11-02 02:53:50 +01:00
parent 979e4207f3
commit ef20b706e2
9 changed files with 430 additions and 143 deletions

View File

@ -9,6 +9,7 @@ struct _GskGLDescriptors
GskGpuDescriptors parent_instance;
GskGLDevice *device;
guint n_external;
};
G_DEFINE_TYPE (GskGLDescriptors, gsk_gl_descriptors, GSK_TYPE_GPU_DESCRIPTORS)
@ -29,14 +30,28 @@ gsk_gl_descriptors_add_image (GskGpuDescriptors *desc,
GskGpuSampler sampler,
guint32 *out_descriptor)
{
GskGLDescriptors *self = GSK_GL_DESCRIPTORS (desc);
gsize used_texture_units;
used_texture_units = gsk_gpu_descriptors_get_size (desc);
used_texture_units = gsk_gpu_descriptors_get_size (desc) + 2 * self->n_external;
if (gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_EXTERNAL)
{
if (16 - used_texture_units < 3)
return FALSE;
*out_descriptor = (self->n_external << 1) | 1;
self->n_external++;
return TRUE;
}
else
{
if (used_texture_units >= 16)
return FALSE;
*out_descriptor = used_texture_units;
*out_descriptor = (gsk_gpu_descriptors_get_size (desc) - self->n_external) << 1;
return TRUE;
}
}
static void
@ -67,16 +82,36 @@ gsk_gl_descriptors_new (GskGLDevice *device)
return GSK_GPU_DESCRIPTORS (self);
}
guint
gsk_gl_descriptors_get_n_external (GskGLDescriptors *self)
{
return self->n_external;
}
void
gsk_gl_descriptors_use (GskGLDescriptors *self)
{
GskGpuDescriptors *desc = GSK_GPU_DESCRIPTORS (self);
gsize i;
gsize i, ext, n_textures;
n_textures = 16 - 3 * self->n_external;
ext = 0;
for (i = 0; i < gsk_gpu_descriptors_get_size (desc); i++)
{
glActiveTexture (GL_TEXTURE0 + i);
gsk_gl_image_bind_texture (GSK_GL_IMAGE (gsk_gpu_descriptors_get_image (desc, i)));
glBindSampler (i, gsk_gl_device_get_sampler_id (self->device, gsk_gpu_descriptors_get_sampler (desc, i)));
GskGLImage *image = GSK_GL_IMAGE (gsk_gpu_descriptors_get_image (desc, i));
if (gsk_gpu_image_get_flags (GSK_GPU_IMAGE (image)) & GSK_GPU_IMAGE_EXTERNAL)
{
glActiveTexture (GL_TEXTURE0 + n_textures + 3 * ext);
gsk_gl_image_bind_texture (image);
ext++;
}
else
{
glActiveTexture (GL_TEXTURE0 + i - ext);
gsk_gl_image_bind_texture (image);
glBindSampler (i - ext, gsk_gl_device_get_sampler_id (self->device, gsk_gpu_descriptors_get_sampler (desc, i)));
}
}
}

View File

@ -12,6 +12,7 @@ G_DECLARE_FINAL_TYPE (GskGLDescriptors, gsk_gl_descriptors, GSK, GL_DESCRIPTORS,
GskGpuDescriptors * gsk_gl_descriptors_new (GskGLDevice *device);
guint gsk_gl_descriptors_get_n_external (GskGLDescriptors *self);
void gsk_gl_descriptors_use (GskGLDescriptors *self);
G_END_DECLS

View File

@ -34,6 +34,7 @@ struct _GLProgramKey
{
const GskGpuShaderOpClass *op_class;
GskGpuShaderClip clip;
guint n_external_textures;
};
G_DEFINE_TYPE (GskGLDevice, gsk_gl_device, GSK_TYPE_GPU_DEVICE)
@ -44,7 +45,8 @@ gl_program_key_hash (gconstpointer data)
const GLProgramKey *key = data;
return GPOINTER_TO_UINT (key->op_class) ^
key->clip;
key->clip ^
(key->n_external_textures << 24);
}
static gboolean
@ -55,7 +57,8 @@ gl_program_key_equal (gconstpointer a,
const GLProgramKey *keyb = b;
return keya->op_class == keyb->op_class &&
keya->clip == keyb->clip;
keya->clip == keyb->clip &&
keya->n_external_textures == keyb->n_external_textures;
}
static GskGpuImage *
@ -337,6 +340,7 @@ gsk_gl_device_load_shader (GskGLDevice *self,
const char *program_name,
GLenum shader_type,
GskGpuShaderClip clip,
guint n_external_textures,
GError **error)
{
GString *preamble;
@ -349,7 +353,22 @@ gsk_gl_device_load_shader (GskGLDevice *self,
g_string_append (preamble, self->version_string);
g_string_append (preamble, "\n");
if (self->api == GDK_GL_API_GLES)
{
if (n_external_textures > 0)
{
g_string_append (preamble, "#extension GL_OES_EGL_image_external_essl3 : require\n");
g_string_append (preamble, "#extension GL_OES_EGL_image_external : require\n");
}
g_string_append (preamble, "#define GSK_GLES 1\n");
g_assert (3 * n_external_textures <= 16);
}
else
{
g_assert (n_external_textures == 0);
}
g_string_append_printf (preamble, "#define N_TEXTURES %u\n", 16 - 3 * n_external_textures);
g_string_append_printf (preamble, "#define N_EXTERNAL_TEXTURES %u\n", n_external_textures);
switch (shader_type)
{
@ -418,16 +437,17 @@ static GLuint
gsk_gl_device_load_program (GskGLDevice *self,
const char *program_name,
GskGpuShaderClip clip,
guint n_external_textures,
GError **error)
{
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, error);
vertex_shader_id = gsk_gl_device_load_shader (self, program_name, GL_VERTEX_SHADER, 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, error);
fragment_shader_id = gsk_gl_device_load_shader (self, program_name, GL_FRAGMENT_SHADER, clip, n_external_textures, error);
if (fragment_shader_id == 0)
return 0;
@ -478,15 +498,17 @@ gsk_gl_device_load_program (GskGLDevice *self,
void
gsk_gl_device_use_program (GskGLDevice *self,
const GskGpuShaderOpClass *op_class,
GskGpuShaderClip clip)
GskGpuShaderClip clip,
guint n_external_textures)
{
GError *error = NULL;
GLuint program_id;
GLProgramKey key = {
.op_class = op_class,
.clip = clip,
.n_external_textures = n_external_textures
};
guint i;
guint i, n_textures;
program_id = GPOINTER_TO_UINT (g_hash_table_lookup (self->gl_programs, &key));
if (program_id)
@ -495,7 +517,7 @@ gsk_gl_device_use_program (GskGLDevice *self,
return;
}
program_id = gsk_gl_device_load_program (self, op_class->shader_name, clip, &error);
program_id = gsk_gl_device_load_program (self, op_class->shader_name, clip, n_external_textures, &error);
if (program_id == 0)
{
g_critical ("Failed to load shader program: %s", error->message);
@ -507,7 +529,16 @@ gsk_gl_device_use_program (GskGLDevice *self,
glUseProgram (program_id);
for (i = 0; i < 16; i++)
n_textures = 16 - 3 * n_external_textures;
for (i = 0; i < n_external_textures; i++)
{
char *name = g_strdup_printf ("external_textures[%u]", i);
glUniform1i (glGetUniformLocation (program_id, name), n_textures + 3 * i);
g_free (name);
}
for (i = 0; i < n_textures; i++)
{
char *name = g_strdup_printf ("textures[%u]", i);
glUniform1i (glGetUniformLocation (program_id, name), i);

View File

@ -13,7 +13,8 @@ GskGpuDevice * gsk_gl_device_get_for_display (GdkDisp
void gsk_gl_device_use_program (GskGLDevice *self,
const GskGpuShaderOpClass *op_class,
GskGpuShaderClip clip);
GskGpuShaderClip clip,
guint n_external_textures);
GLuint gsk_gl_device_get_sampler_id (GskGLDevice *self,
GskGpuSampler sampler);

View File

@ -193,13 +193,15 @@ gsk_gl_frame_init (GskGLFrame *self)
void
gsk_gl_frame_use_program (GskGLFrame *self,
const GskGpuShaderOpClass *op_class,
GskGpuShaderClip clip)
GskGpuShaderClip clip,
guint n_external_textures)
{
GLuint vao;
gsk_gl_device_use_program (GSK_GL_DEVICE (gsk_gpu_frame_get_device (GSK_GPU_FRAME (self))),
op_class,
clip);
clip,
n_external_textures);
vao = GPOINTER_TO_UINT (g_hash_table_lookup (self->vaos, op_class));
if (vao)

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,
GskGpuShaderClip clip);
GskGpuShaderClip clip,
guint n_external_textures);
G_END_DECLS

View File

@ -194,6 +194,9 @@ gsk_gl_image_new_for_texture (GskGLDevice *device,
void
gsk_gl_image_bind_texture (GskGLImage *self)
{
if (gsk_gpu_image_get_flags (GSK_GPU_IMAGE (self)) & GSK_GPU_IMAGE_EXTERNAL)
glBindTexture (GL_TEXTURE_EXTERNAL_OES, self->texture_id);
else
glBindTexture (GL_TEXTURE_2D, self->texture_id);
}

View File

@ -91,15 +91,18 @@ gsk_gpu_shader_op_gl_command_n (GskGpuOp *op,
{
GskGpuShaderOp *self = (GskGpuShaderOp *) op;
GskGpuShaderOpClass *shader_op_class = (GskGpuShaderOpClass *) op->op_class;
GskGLDescriptors *desc;
GskGpuOp *next;
gsize i, n;
desc = GSK_GL_DESCRIPTORS (self->desc);
gsk_gl_frame_use_program (GSK_GL_FRAME (frame),
shader_op_class,
self->clip);
self->clip,
desc ? gsk_gl_descriptors_get_n_external (desc) : 0);
if (self->desc)
gsk_gl_descriptors_use (GSK_GL_DESCRIPTORS (self->desc));
if (desc)
gsk_gl_descriptors_use (GSK_GL_DESCRIPTORS (desc));
if (gsk_gpu_frame_should_optimize (frame, GSK_GPU_OPTIMIZE_MERGE))
n = MAX_MERGE_OPS;

View File

@ -27,7 +27,12 @@ uniform Floats
vec4 really_just_floats[1024];
} floats;
uniform sampler2D textures[16];
#if N_EXTERNAL_TEXTURES > 0
uniform samplerExternalOES external_textures[N_EXTERNAL_TEXTURES];
#endif
#if N_TEXTURES > 0
uniform sampler2D textures[N_TEXTURES];
#endif
#define GSK_VERTEX_INDEX gl_VertexID
@ -59,90 +64,227 @@ gsk_get_float (uint id)
#define gsk_get_uint(id) (floatBitsToUint(gsk_get_float(id)))
#ifdef GSK_GLES
vec4
gsk_texture (uint id,
vec2 pos)
{
switch(id)
if ((id & 1u) != 0u)
{
switch (id >> 1u)
{
case 0u:
return texture (textures[0], pos);
#if N_EXTERNAL_TEXTURES > 0
return texture (external_textures[0], pos);
#endif
#if N_EXTERNAL_TEXTURES > 1
case 1u:
return texture (textures[1], pos);
return texture (external_textures[1], pos);
#endif
case 2u:
return texture (textures[2], pos);
#if N_EXTERNAL_TEXTURES > 2
return texture (external_textures[2], pos);
#endif
case 3u:
return texture (textures[3], pos);
#if N_EXTERNAL_TEXTURES > 3
return texture (external_textures[3], pos);
#endif
case 4u:
return texture (textures[4], pos);
#if N_EXTERNAL_TEXTURES > 4
return texture (external_textures[4], pos);
#endif
case 5u:
return texture (textures[5], pos);
case 6u:
return texture (textures[6], pos);
case 7u:
return texture (textures[7], pos);
case 8u:
return texture (textures[8], pos);
case 9u:
return texture (textures[9], pos);
case 10u:
return texture (textures[10], pos);
case 11u:
return texture (textures[11], pos);
case 12u:
return texture (textures[12], pos);
case 13u:
return texture (textures[13], pos);
case 14u:
return texture (textures[14], pos);
case 15u:
return texture (textures[15], pos);
#if N_EXTERNAL_TEXTURES > 5
return texture (external_textures[5], pos);
#endif
default:
return vec4 (1.0, 0.0, 0.8, 1.0);
break;
}
}
else
{
switch (id >> 1u)
{
case 0u:
#if N_TEXTURES > 0
return texture (textures[0], pos);
#endif
case 1u:
#if N_TEXTURES > 1
return texture (textures[1], pos);
#endif
case 2u:
#if N_TEXTURES > 2
return texture (textures[2], pos);
#endif
case 3u:
#if N_TEXTURES > 3
return texture (textures[3], pos);
#endif
case 4u:
#if N_TEXTURES > 4
return texture (textures[4], pos);
#endif
case 5u:
#if N_TEXTURES > 5
return texture (textures[5], pos);
#endif
case 6u:
#if N_TEXTURES > 6
return texture (textures[6], pos);
#endif
case 7u:
#if N_TEXTURES > 7
return texture (textures[7], pos);
#endif
case 8u:
#if N_TEXTURES > 8
return texture (textures[8], pos);
#endif
case 9u:
#if N_TEXTURES > 9
return texture (textures[9], pos);
#endif
case 10u:
#if N_TEXTURES > 10
return texture (textures[10], pos);
#endif
case 11u:
#if N_TEXTURES > 11
return texture (textures[11], pos);
#endif
case 12u:
#if N_TEXTURES > 12
return texture (textures[12], pos);
#endif
case 13u:
#if N_TEXTURES > 13
return texture (textures[13], pos);
#endif
case 14u:
#if N_TEXTURES > 14
return texture (textures[14], pos);
#endif
case 15u:
#if N_TEXTURES > 15
return texture (textures[15], pos);
#endif
default:
break;
}
}
return vec4 (1.0, 0.0, 0.8, 1.0);
}
ivec2
gsk_texture_size (uint id,
int lod)
{
switch(id)
if ((id & 1u) != 0u)
{
switch (id >> 1u)
{
case 0u:
return textureSize (textures[0], lod);
#if N_EXTERNAL_TEXTURES > 0
return textureSize (external_textures[0], lod);
#endif
#if N_EXTERNAL_TEXTURES > 1
case 1u:
return textureSize (textures[1], lod);
return textureSize (external_textures[1], lod);
#endif
case 2u:
return textureSize (textures[2], lod);
#if N_EXTERNAL_TEXTURES > 2
return textureSize (external_textures[2], lod);
#endif
case 3u:
return textureSize (textures[3], lod);
#if N_EXTERNAL_TEXTURES > 3
return textureSize (external_textures[3], lod);
#endif
case 4u:
return textureSize (textures[4], lod);
#if N_EXTERNAL_TEXTURES > 4
return textureSize (external_textures[4], lod);
#endif
case 5u:
return textureSize (textures[5], lod);
case 6u:
return textureSize (textures[6], lod);
case 7u:
return textureSize (textures[7], lod);
case 8u:
return textureSize (textures[8], lod);
case 9u:
return textureSize (textures[9], lod);
case 10u:
return textureSize (textures[10], lod);
case 11u:
return textureSize (textures[11], lod);
case 12u:
return textureSize (textures[12], lod);
case 13u:
return textureSize (textures[13], lod);
case 14u:
return textureSize (textures[14], lod);
case 15u:
return textureSize (textures[15], lod);
#if N_EXTERNAL_TEXTURES > 5
return textureSize (external_textures[5], lod);
#endif
default:
return ivec2 (1, 1);
break;
}
}
else
{
switch (id >> 1u)
{
case 0u:
#if N_TEXTURES > 0
return textureSize (textures[0], lod);
#endif
case 1u:
#if N_TEXTURES > 1
return textureSize (textures[1], lod);
#endif
case 2u:
#if N_TEXTURES > 2
return textureSize (textures[2], lod);
#endif
case 3u:
#if N_TEXTURES > 3
return textureSize (textures[3], lod);
#endif
case 4u:
#if N_TEXTURES > 4
return textureSize (textures[4], lod);
#endif
case 5u:
#if N_TEXTURES > 5
return textureSize (textures[5], lod);
#endif
case 6u:
#if N_TEXTURES > 6
return textureSize (textures[6], lod);
#endif
case 7u:
#if N_TEXTURES > 7
return textureSize (textures[7], lod);
#endif
case 8u:
#if N_TEXTURES > 8
return textureSize (textures[8], lod);
#endif
case 9u:
#if N_TEXTURES > 9
return textureSize (textures[9], lod);
#endif
case 10u:
#if N_TEXTURES > 10
return textureSize (textures[10], lod);
#endif
case 11u:
#if N_TEXTURES > 11
return textureSize (textures[11], lod);
#endif
case 12u:
#if N_TEXTURES > 12
return textureSize (textures[12], lod);
#endif
case 13u:
#if N_TEXTURES > 13
return textureSize (textures[13], lod);
#endif
case 14u:
#if N_TEXTURES > 14
return textureSize (textures[14], lod);
#endif
case 15u:
#if N_TEXTURES > 15
return textureSize (textures[15], lod);
#endif
default:
break;
}
}
return ivec2 (1, 1);
}
vec4
@ -150,50 +292,118 @@ gsk_texel_fetch (uint id,
ivec2 pos,
int lod)
{
switch(id)
if ((id & 1u) != 0u)
{
switch (id >> 1u)
{
case 0u:
return texelFetch (textures[0], pos, lod);
#if N_EXTERNAL_TEXTURES > 0
return texelFetch (external_textures[0], pos, lod);
#endif
#if N_EXTERNAL_TEXTURES > 1
case 1u:
return texelFetch (textures[1], pos, lod);
return texelFetch (external_textures[1], pos, lod);
#endif
case 2u:
return texelFetch (textures[2], pos, lod);
#if N_EXTERNAL_TEXTURES > 2
return texelFetch (external_textures[2], pos, lod);
#endif
case 3u:
return texelFetch (textures[3], pos, lod);
#if N_EXTERNAL_TEXTURES > 3
return texelFetch (external_textures[3], pos, lod);
#endif
case 4u:
return texelFetch (textures[4], pos, lod);
#if N_EXTERNAL_TEXTURES > 4
return texelFetch (external_textures[4], pos, lod);
#endif
case 5u:
return texelFetch (textures[5], pos, lod);
case 6u:
return texelFetch (textures[6], pos, lod);
case 7u:
return texelFetch (textures[7], pos, lod);
case 8u:
return texelFetch (textures[8], pos, lod);
case 9u:
return texelFetch (textures[9], pos, lod);
case 10u:
return texelFetch (textures[10], pos, lod);
case 11u:
return texelFetch (textures[11], pos, lod);
case 12u:
return texelFetch (textures[12], pos, lod);
case 13u:
return texelFetch (textures[13], pos, lod);
case 14u:
return texelFetch (textures[14], pos, lod);
case 15u:
return texelFetch (textures[15], pos, lod);
#if N_EXTERNAL_TEXTURES > 5
return texelFetch (external_textures[5], pos, lod);
#endif
default:
return vec4 (1.0, 0.0, 0.8, 1.0);
break;
}
}
else
{
switch (id >> 1u)
{
case 0u:
#if N_TEXTURES > 0
return texelFetch (textures[0], pos, lod);
#endif
case 1u:
#if N_TEXTURES > 1
return texelFetch (textures[1], pos, lod);
#endif
case 2u:
#if N_TEXTURES > 2
return texelFetch (textures[2], pos, lod);
#endif
case 3u:
#if N_TEXTURES > 3
return texelFetch (textures[3], pos, lod);
#endif
case 4u:
#if N_TEXTURES > 4
return texelFetch (textures[4], pos, lod);
#endif
case 5u:
#if N_TEXTURES > 5
return texelFetch (textures[5], pos, lod);
#endif
case 6u:
#if N_TEXTURES > 6
return texelFetch (textures[6], pos, lod);
#endif
case 7u:
#if N_TEXTURES > 7
return texelFetch (textures[7], pos, lod);
#endif
case 8u:
#if N_TEXTURES > 8
return texelFetch (textures[8], pos, lod);
#endif
case 9u:
#if N_TEXTURES > 9
return texelFetch (textures[9], pos, lod);
#endif
case 10u:
#if N_TEXTURES > 10
return texelFetch (textures[10], pos, lod);
#endif
case 11u:
#if N_TEXTURES > 11
return texelFetch (textures[11], pos, lod);
#endif
case 12u:
#if N_TEXTURES > 12
return texelFetch (textures[12], pos, lod);
#endif
case 13u:
#if N_TEXTURES > 13
return texelFetch (textures[13], pos, lod);
#endif
case 14u:
#if N_TEXTURES > 14
return texelFetch (textures[14], pos, lod);
#endif
case 15u:
#if N_TEXTURES > 15
return texelFetch (textures[15], pos, lod);
#endif
default:
break;
}
}
return vec4 (1.0, 0.0, 0.8, 1.0);
}
#else /* !GSK_GLES */
#define gsk_texture(id, pos) texture (textures[id], pos)
#define gsk_texture_size(id, lod) textureSize (textures[id], lod)
#define gsk_texel_fetch(id, pos, lod) texelFetch (textures[id], pos, lod)
#define gsk_texture(id, pos) texture (textures[id >> 1], pos)
#define gsk_texture_size(id, lod) textureSize (textures[id >> 1], lod)
#define gsk_texel_fetch(id, pos, lod) texelFetch (textures[id >> 1], pos, lod)
#endif