mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 06:00:22 +00:00
gsk: Add slicing to texture scale nodes
This makes it possible to use large textures with filtering. Fixes: #5664
This commit is contained in:
parent
f3b0aa27ea
commit
b14a134a46
@ -29,6 +29,7 @@
|
|||||||
#include <gsk/gskrendernodeprivate.h>
|
#include <gsk/gskrendernodeprivate.h>
|
||||||
#include <gsk/gskglshaderprivate.h>
|
#include <gsk/gskglshaderprivate.h>
|
||||||
#include <gdk/gdktextureprivate.h>
|
#include <gdk/gdktextureprivate.h>
|
||||||
|
#include <gdk/gdkmemorytextureprivate.h>
|
||||||
#include <gsk/gsktransformprivate.h>
|
#include <gsk/gsktransformprivate.h>
|
||||||
#include <gsk/gskroundedrectprivate.h>
|
#include <gsk/gskroundedrectprivate.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@ -3626,11 +3627,11 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
|
|||||||
{
|
{
|
||||||
GdkTexture *texture = gsk_texture_scale_node_get_texture (node);
|
GdkTexture *texture = gsk_texture_scale_node_get_texture (node);
|
||||||
const graphene_rect_t *bounds = &node->bounds;
|
const graphene_rect_t *bounds = &node->bounds;
|
||||||
GskScalingFilter scaling_filter = gsk_texture_scale_node_get_filter (node);
|
GskScalingFilter filter = gsk_texture_scale_node_get_filter (node);
|
||||||
int min_filters[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR };
|
int min_filters[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR };
|
||||||
int mag_filters[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR };
|
int mag_filters[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR };
|
||||||
int min_filter = min_filters[scaling_filter];
|
int min_filter = min_filters[filter];
|
||||||
int mag_filter = mag_filters[scaling_filter];
|
int mag_filter = mag_filters[filter];
|
||||||
int max_texture_size = job->command_queue->max_texture_size;
|
int max_texture_size = job->command_queue->max_texture_size;
|
||||||
graphene_rect_t clip_rect;
|
graphene_rect_t clip_rect;
|
||||||
GskGLRenderTarget *render_target;
|
GskGLRenderTarget *render_target;
|
||||||
@ -3640,22 +3641,23 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
|
|||||||
graphene_matrix_t prev_projection;
|
graphene_matrix_t prev_projection;
|
||||||
float prev_alpha;
|
float prev_alpha;
|
||||||
guint prev_fbo;
|
guint prev_fbo;
|
||||||
guint texture_id;
|
|
||||||
float u0, u1, v0, v1;
|
float u0, u1, v0, v1;
|
||||||
GskTextureKey key;
|
GskTextureKey key;
|
||||||
|
GdkTexture *subtexture = NULL;
|
||||||
|
graphene_rect_t subbounds;
|
||||||
|
guint texture_id;
|
||||||
|
|
||||||
|
if (filter == GSK_SCALING_FILTER_LINEAR)
|
||||||
|
{
|
||||||
|
gsk_gl_render_job_visit_texture (job, texture, bounds);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
gsk_gl_render_job_untransform_bounds (job, &job->current_clip->rect.bounds, &clip_rect);
|
gsk_gl_render_job_untransform_bounds (job, &job->current_clip->rect.bounds, &clip_rect);
|
||||||
|
|
||||||
if (!graphene_rect_intersection (bounds, &clip_rect, &clip_rect))
|
if (!graphene_rect_intersection (bounds, &clip_rect, &clip_rect))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if G_UNLIKELY (clip_rect.size.width > max_texture_size ||
|
|
||||||
clip_rect.size.height > max_texture_size)
|
|
||||||
{
|
|
||||||
gsk_gl_render_job_visit_texture (job, texture, bounds);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
key.pointer = node;
|
key.pointer = node;
|
||||||
key.pointer_is_child = TRUE;
|
key.pointer_is_child = TRUE;
|
||||||
key.parent_rect = clip_rect;
|
key.parent_rect = clip_rect;
|
||||||
@ -3664,6 +3666,7 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
|
|||||||
key.filter = min_filter;
|
key.filter = min_filter;
|
||||||
|
|
||||||
texture_id = gsk_gl_driver_lookup_texture (job->driver, &key);
|
texture_id = gsk_gl_driver_lookup_texture (job->driver, &key);
|
||||||
|
|
||||||
if (texture_id != 0)
|
if (texture_id != 0)
|
||||||
goto render_texture;
|
goto render_texture;
|
||||||
|
|
||||||
@ -3682,15 +3685,35 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gsk_gl_render_job_upload_texture (job, texture, min_filter, mag_filter, &offscreen);
|
if G_UNLIKELY (texture->width > max_texture_size ||
|
||||||
|
texture->height > max_texture_size)
|
||||||
|
{
|
||||||
|
float scale_x = bounds->size.width / texture->width;
|
||||||
|
float scale_y = bounds->size.height / texture->height;
|
||||||
|
int x, y, width, height;
|
||||||
|
|
||||||
g_assert (offscreen.texture_id);
|
x = (int) floorf ((clip_rect.origin.x - bounds->origin.x) / scale_x);
|
||||||
g_assert (offscreen.was_offscreen == FALSE);
|
y = (int) floorf ((clip_rect.origin.y - bounds->origin.y) / scale_y);
|
||||||
|
width = (int) ceilf (clip_rect.size.width / scale_x);
|
||||||
|
height = (int) ceilf (clip_rect.size.height / scale_y);
|
||||||
|
|
||||||
u0 = (clip_rect.origin.x - bounds->origin.x) / bounds->size.width;
|
if (width <= max_texture_size && height <= max_texture_size)
|
||||||
v0 = (clip_rect.origin.y - bounds->origin.y) / bounds->size.height;
|
{
|
||||||
u1 = (clip_rect.origin.x + clip_rect.size.width - bounds->origin.x) / bounds->size.width;
|
GdkMemoryTexture *memtex;
|
||||||
v1 = (clip_rect.origin.y + clip_rect.size.height - bounds->origin.y) / bounds->size.height;
|
|
||||||
|
memtex = gdk_memory_texture_from_texture (texture, gdk_texture_get_format (texture));
|
||||||
|
subtexture = gdk_memory_texture_new_subtexture (memtex, x, y, width, height);
|
||||||
|
g_object_unref (memtex);
|
||||||
|
|
||||||
|
subbounds.origin.x = bounds->origin.x + x * scale_x;
|
||||||
|
subbounds.origin.y = bounds->origin.y + y * scale_y;
|
||||||
|
subbounds.size.width = width * scale_x;
|
||||||
|
subbounds.size.height = height * scale_y;
|
||||||
|
|
||||||
|
texture = subtexture;
|
||||||
|
bounds = &subbounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gsk_gl_render_job_set_viewport (job, &viewport, &prev_viewport);
|
gsk_gl_render_job_set_viewport (job, &viewport, &prev_viewport);
|
||||||
gsk_gl_render_job_set_projection_from_rect (job, &viewport, &prev_projection);
|
gsk_gl_render_job_set_projection_from_rect (job, &viewport, &prev_projection);
|
||||||
@ -3701,17 +3724,66 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
|
|||||||
prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
|
prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
|
||||||
gsk_gl_command_queue_clear (job->command_queue, 0, &viewport);
|
gsk_gl_command_queue_clear (job->command_queue, 0, &viewport);
|
||||||
|
|
||||||
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
|
if G_LIKELY (texture->width <= max_texture_size &&
|
||||||
gsk_gl_program_set_uniform_texture (job->current_program,
|
texture->height <= max_texture_size)
|
||||||
UNIFORM_SHARED_SOURCE, 0,
|
{
|
||||||
GL_TEXTURE_2D,
|
gsk_gl_render_job_upload_texture (job, texture, min_filter, mag_filter, &offscreen);
|
||||||
GL_TEXTURE0,
|
|
||||||
offscreen.texture_id);
|
g_assert (offscreen.texture_id);
|
||||||
gsk_gl_render_job_draw_coords (job,
|
g_assert (offscreen.was_offscreen == FALSE);
|
||||||
0, 0, clip_rect.size.width, clip_rect.size.height,
|
|
||||||
u0, v0, u1, v1,
|
u0 = (clip_rect.origin.x - bounds->origin.x) / bounds->size.width;
|
||||||
(guint16[]) { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO });
|
v0 = (clip_rect.origin.y - bounds->origin.y) / bounds->size.height;
|
||||||
gsk_gl_render_job_end_draw (job);
|
u1 = (clip_rect.origin.x + clip_rect.size.width - bounds->origin.x) / bounds->size.width;
|
||||||
|
v1 = (clip_rect.origin.y + clip_rect.size.height - bounds->origin.y) / bounds->size.height;
|
||||||
|
|
||||||
|
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
|
||||||
|
gsk_gl_program_set_uniform_texture (job->current_program,
|
||||||
|
UNIFORM_SHARED_SOURCE, 0,
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
GL_TEXTURE0,
|
||||||
|
offscreen.texture_id);
|
||||||
|
gsk_gl_render_job_draw_coords (job,
|
||||||
|
0, 0, clip_rect.size.width, clip_rect.size.height,
|
||||||
|
u0, v0, u1, v1,
|
||||||
|
(guint16[]) { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO });
|
||||||
|
gsk_gl_render_job_end_draw (job);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float scale_x = bounds->size.width / texture->width;
|
||||||
|
float scale_y = bounds->size.height / texture->height;
|
||||||
|
GskGLTextureSlice *slices = NULL;
|
||||||
|
guint n_slices = 0;
|
||||||
|
|
||||||
|
gsk_gl_driver_slice_texture (job->driver, texture, min_filter, mag_filter, 0, 0, &slices, &n_slices);
|
||||||
|
|
||||||
|
for (guint i = 0; i < n_slices; i++)
|
||||||
|
{
|
||||||
|
const GskGLTextureSlice *slice = &slices[i];
|
||||||
|
graphene_rect_t slice_bounds;
|
||||||
|
|
||||||
|
slice_bounds.origin.x = bounds->origin.x - clip_rect.origin.x + slice->rect.x * scale_x;
|
||||||
|
slice_bounds.origin.y = bounds->origin.y - clip_rect.origin.y + slice->rect.y * scale_y;
|
||||||
|
slice_bounds.size.width = slice->rect.width * scale_x;
|
||||||
|
slice_bounds.size.height = slice->rect.height * scale_y;
|
||||||
|
|
||||||
|
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
|
||||||
|
gsk_gl_program_set_uniform_texture (job->current_program,
|
||||||
|
UNIFORM_SHARED_SOURCE, 0,
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
GL_TEXTURE0,
|
||||||
|
slice->texture_id);
|
||||||
|
gsk_gl_render_job_draw_coords (job,
|
||||||
|
slice_bounds.origin.x,
|
||||||
|
slice_bounds.origin.y,
|
||||||
|
slice_bounds.origin.x + slice_bounds.size.width,
|
||||||
|
slice_bounds.origin.y + slice_bounds.size.height,
|
||||||
|
0, 0, 1, 1,
|
||||||
|
(guint16[]){ FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO } );
|
||||||
|
gsk_gl_render_job_end_draw (job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gsk_gl_render_job_pop_clip (job);
|
gsk_gl_render_job_pop_clip (job);
|
||||||
gsk_gl_render_job_pop_modelview (job);
|
gsk_gl_render_job_pop_modelview (job);
|
||||||
@ -3721,7 +3793,6 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
|
|||||||
gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo);
|
gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo);
|
||||||
|
|
||||||
texture_id = gsk_gl_driver_release_render_target (job->driver, render_target, FALSE);
|
texture_id = gsk_gl_driver_release_render_target (job->driver, render_target, FALSE);
|
||||||
|
|
||||||
gsk_gl_driver_cache_texture (job->driver, &key, texture_id);
|
gsk_gl_driver_cache_texture (job->driver, &key, texture_id);
|
||||||
|
|
||||||
render_texture:
|
render_texture:
|
||||||
@ -3740,6 +3811,8 @@ render_texture:
|
|||||||
clip_rect.size.height / ceilf (clip_rect.size.height), 0,
|
clip_rect.size.height / ceilf (clip_rect.size.height), 0,
|
||||||
(guint16[]){ FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO } );
|
(guint16[]){ FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO } );
|
||||||
gsk_gl_render_job_end_draw (job);
|
gsk_gl_render_job_end_draw (job);
|
||||||
|
|
||||||
|
g_clear_object (&subtexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
Loading…
Reference in New Issue
Block a user