Merge branch 'mipmap-tracking' into 'main'

gsk: Avoid copying GL texture in more cases

See merge request GNOME/gtk!5704
This commit is contained in:
Matthias Clasen 2023-03-24 03:43:21 +00:00
commit 65acf8500f
4 changed files with 52 additions and 12 deletions

View File

@ -38,6 +38,7 @@ struct _GdkGLTexture {
GdkGLContext *context;
guint id;
gboolean has_mipmap;
GdkTexture *saved;
@ -284,6 +285,12 @@ gdk_gl_texture_get_id (GdkGLTexture *self)
return self->id;
}
gboolean
gdk_gl_texture_has_mipmap (GdkGLTexture *self)
{
return self->has_mipmap;
}
/**
* gdk_gl_texture_release:
* @self: a `GdkTexture` wrapping a GL texture
@ -315,13 +322,15 @@ gdk_gl_texture_determine_format (GdkGLTexture *self)
GdkTexture *texture = GDK_TEXTURE (self);
GLint active_texture;
GLint internal_format;
GLint width, height;
/* Abort if somebody else is GL-ing here... */
if (self->context != gdk_gl_context_get_current () ||
if (!gdk_gl_context_is_shared (self->context, gdk_gl_context_get_current ()) ||
/* ... or glGetTexLevelParameter() isn't supported */
!gdk_gl_context_check_version (self->context, 0, 0, 3, 1))
!gdk_gl_context_check_version (gdk_gl_context_get_current (), 0, 0, 3, 1))
{
texture->format = GDK_MEMORY_DEFAULT;
self->has_mipmap = FALSE;
return;
}
@ -411,6 +420,20 @@ gdk_gl_texture_determine_format (GdkGLTexture *self)
break;
}
/* Determine if the texture has a mipmap.
* We do this here, since it requires binding the texture,
* and we're already doing that here.
* GL has no way to directly query 'mipmap completeness' of textures,
* so we just check that level 1 has the expected size, and assume
* that means somebody called glGenerateMipmap().
*/
glGetTexLevelParameteriv (GL_TEXTURE_2D, 1, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv (GL_TEXTURE_2D, 1, GL_TEXTURE_HEIGHT, &height);
self->has_mipmap = width == texture->width / 2 &&
height == texture->height / 2;
/* restore previous state */
glBindTexture (GL_TEXTURE_2D, active_texture);
}

View File

@ -9,6 +9,7 @@ G_BEGIN_DECLS
GdkGLContext * gdk_gl_texture_get_context (GdkGLTexture *self);
guint gdk_gl_texture_get_id (GdkGLTexture *self);
gboolean gdk_gl_texture_has_mipmap (GdkGLTexture *self);
G_END_DECLS

View File

@ -744,12 +744,13 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
return t->texture_id;
}
if (GDK_IS_GL_TEXTURE (texture) && !ensure_mipmap)
if (GDK_IS_GL_TEXTURE (texture))
{
GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture);
if (gdk_gl_context_is_shared (context, texture_context))
if (gdk_gl_context_is_shared (context, texture_context) &&
(!ensure_mipmap || gdk_gl_texture_has_mipmap (gl_texture)))
{
/* A GL texture from the same GL context is a simple task... */
return gdk_gl_texture_get_id (gl_texture);

View File

@ -201,6 +201,7 @@ typedef struct _GskGLRenderOffscreen
/* Return location for whether we created a texture */
guint was_offscreen : 1;
guint has_mipmap : 1;
} GskGLRenderOffscreen;
static void gsk_gl_render_job_visit_node (GskGLRenderJob *job,
@ -3513,22 +3514,36 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
gboolean ensure_mipmap,
GskGLRenderOffscreen *offscreen)
{
GdkGLTexture *gl_texture = NULL;
if (GDK_IS_GL_TEXTURE (texture))
gl_texture = GDK_GL_TEXTURE (texture);
if (!ensure_mipmap &&
gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
texture->width,
texture->height) &&
!GDK_IS_GL_TEXTURE (texture))
!gl_texture)
{
const GskGLIconData *icon_data;
gsk_gl_icon_library_lookup_or_add (job->driver->icons_library, texture, &icon_data);
offscreen->texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (icon_data);
memcpy (&offscreen->area, &icon_data->entry.area, sizeof offscreen->area);
offscreen->has_mipmap = FALSE;
}
else
{
/* Only generate a mipmap if it does not make use reupload
* a GL texture which we could otherwise use directly.
*/
if (gl_texture &&
gdk_gl_context_is_shared (gdk_gl_texture_get_context (gl_texture), job->command_queue->context))
ensure_mipmap = gdk_gl_texture_has_mipmap (gl_texture);
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, ensure_mipmap);
init_full_texture_region (offscreen);
offscreen->has_mipmap = ensure_mipmap;
}
}
@ -3540,17 +3555,17 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
int max_texture_size = job->command_queue->max_texture_size;
float scale_x = bounds->size.width / texture->width;
float scale_y = bounds->size.height / texture->height;
gboolean use_mipmaps;
gboolean use_mipmap;
use_mipmaps = (scale_x * job->scale_x) < 0.5 ||
(scale_y * job->scale_y) < 0.5;
use_mipmap = (scale_x * job->scale_x) < 0.5 ||
(scale_y * job->scale_y) < 0.5;
if G_LIKELY (texture->width <= max_texture_size &&
texture->height <= max_texture_size)
{
GskGLRenderOffscreen offscreen = {0};
gsk_gl_render_job_upload_texture (job, texture, use_mipmaps, &offscreen);
gsk_gl_render_job_upload_texture (job, texture, use_mipmap, &offscreen);
g_assert (offscreen.texture_id);
g_assert (offscreen.was_offscreen == FALSE);
@ -3561,7 +3576,7 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
offscreen.texture_id,
use_mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR,
offscreen.has_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR,
GL_LINEAR);
gsk_gl_render_job_draw_offscreen (job, bounds, &offscreen);
gsk_gl_render_job_end_draw (job);
@ -3573,7 +3588,7 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
GskGLTextureSlice *slices = NULL;
guint n_slices = 0;
gsk_gl_driver_slice_texture (job->driver, texture, use_mipmaps, &slices, &n_slices);
gsk_gl_driver_slice_texture (job->driver, texture, use_mipmap, &slices, &n_slices);
g_assert (slices != NULL);
g_assert (n_slices > 0);
@ -3597,7 +3612,7 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
GL_TEXTURE_2D,
GL_TEXTURE0,
slice->texture_id,
use_mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR,
use_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR,
GL_LINEAR);
gsk_gl_render_job_draw_coords (job,