forked from AuroraMiddleware/gtk
Check for pixel-alignedness for interpolation
When rendering to an offscreen because of transforms, check if transforming the bounds of the node results in a non-axis-aligned quad. If it doesn't, we want GL_NEAREST interpolation to get sharp edges. Otherwise, we use GL_LINEAR to get better results for things that are actually transformed.
This commit is contained in:
parent
9843515736
commit
e0cc7b5d86
@ -594,6 +594,8 @@ void
|
||||
gsk_gl_driver_create_render_target (GskGLDriver *self,
|
||||
int width,
|
||||
int height,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
int *out_texture_id,
|
||||
int *out_render_target_id)
|
||||
{
|
||||
@ -604,7 +606,7 @@ gsk_gl_driver_create_render_target (GskGLDriver *self,
|
||||
|
||||
texture = create_texture (self, width, height);
|
||||
gsk_gl_driver_bind_source_texture (self, texture->texture_id);
|
||||
gsk_gl_driver_init_texture_empty (self, texture->texture_id, GL_NEAREST, GL_NEAREST);
|
||||
gsk_gl_driver_init_texture_empty (self, texture->texture_id, min_filter, mag_filter);
|
||||
|
||||
glGenFramebuffers (1, &fbo_id);
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, fbo_id);
|
||||
|
@ -45,6 +45,8 @@ int gsk_gl_driver_create_texture (GskGLDriver *driver
|
||||
void gsk_gl_driver_create_render_target (GskGLDriver *driver,
|
||||
int width,
|
||||
int height,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
int *out_texture_id,
|
||||
int *out_render_target_id);
|
||||
void gsk_gl_driver_mark_texture_permanent (GskGLDriver *self,
|
||||
|
@ -71,6 +71,7 @@ typedef enum
|
||||
RESET_OPACITY = 1 << 2,
|
||||
DUMP_FRAMEBUFFER = 1 << 3,
|
||||
NO_CACHE_PLZ = 1 << 5,
|
||||
LINEAR_FILTER = 1 << 6,
|
||||
} OffscreenFlags;
|
||||
|
||||
static inline void
|
||||
@ -1000,6 +1001,38 @@ render_texture_node (GskGLRenderer *self,
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns TRUE is applying transform to bounds
|
||||
* yields an axis-aligned rectangle
|
||||
*/
|
||||
static gboolean
|
||||
result_is_axis_aligned (GskTransform *transform,
|
||||
const graphene_rect_t *bounds)
|
||||
{
|
||||
graphene_matrix_t m;
|
||||
graphene_quad_t q;
|
||||
graphene_rect_t b;
|
||||
graphene_point_t b1, b2;
|
||||
const graphene_point_t *p;
|
||||
int i;
|
||||
|
||||
gsk_transform_to_matrix (transform, &m);
|
||||
gsk_matrix_transform_rect (&m, bounds, &q);
|
||||
graphene_quad_bounds (&q, &b);
|
||||
graphene_rect_get_top_left (&b, &b1);
|
||||
graphene_rect_get_bottom_right (&b, &b2);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
p = graphene_quad_get_point (&q, i);
|
||||
if (fabs (p->x - b1.x) > FLT_EPSILON && fabs (p->x - b2.x) > FLT_EPSILON)
|
||||
return FALSE;
|
||||
if (fabs (p->y - b1.y) > FLT_EPSILON && fabs (p->y - b2.y) > FLT_EPSILON)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
render_transform_node (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
@ -1051,27 +1084,33 @@ render_transform_node (GskGLRenderer *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
int filter_flag = 0;
|
||||
|
||||
if (!result_is_axis_aligned (node_transform, &child->bounds))
|
||||
filter_flag = LINEAR_FILTER;
|
||||
|
||||
if (add_offscreen_ops (self, builder,
|
||||
&child->bounds,
|
||||
child,
|
||||
®ion, &is_offscreen,
|
||||
RESET_CLIP | RESET_OPACITY))
|
||||
{
|
||||
/* For non-trivial transforms, we draw everything on a texture and then
|
||||
* draw the texture transformed. */
|
||||
/* TODO: We should compute a modelview containing only the "non-trivial"
|
||||
* part (e.g. the rotation) and use that. We want to keep the scale
|
||||
* for the texture.
|
||||
*/
|
||||
ops_push_modelview (builder, node_transform);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
RESET_CLIP | RESET_OPACITY | filter_flag))
|
||||
{
|
||||
/* For non-trivial transforms, we draw everything on a texture and then
|
||||
* draw the texture transformed. */
|
||||
/* TODO: We should compute a modelview containing only the "non-trivial"
|
||||
* part (e.g. the rotation) and use that. We want to keep the scale
|
||||
* for the texture.
|
||||
*/
|
||||
ops_push_modelview (builder, node_transform);
|
||||
ops_set_texture (builder, region.texture_id);
|
||||
ops_set_program (builder, &self->programs->blit_program);
|
||||
|
||||
load_vertex_data_with_region (ops_draw (builder, NULL),
|
||||
child, builder,
|
||||
®ion,
|
||||
is_offscreen);
|
||||
ops_pop_modelview (builder);
|
||||
load_vertex_data_with_region (ops_draw (builder, NULL),
|
||||
child, builder,
|
||||
®ion,
|
||||
is_offscreen);
|
||||
ops_pop_modelview (builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1457,10 +1496,12 @@ blur_texture (GskGLRenderer *self,
|
||||
|
||||
gsk_gl_driver_create_render_target (self->gl_driver,
|
||||
texture_to_blur_width, texture_to_blur_height,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&pass1_texture_id, &pass1_render_target);
|
||||
|
||||
gsk_gl_driver_create_render_target (self->gl_driver,
|
||||
texture_to_blur_width, texture_to_blur_height,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&pass2_texture_id, &pass2_render_target);
|
||||
|
||||
graphene_matrix_init_ortho (&item_proj,
|
||||
@ -1702,6 +1743,7 @@ render_inset_shadow_node (GskGLRenderer *self,
|
||||
|
||||
gsk_gl_driver_create_render_target (self->gl_driver,
|
||||
texture_width, texture_height,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&texture_id, &render_target);
|
||||
|
||||
graphene_matrix_init_ortho (&item_proj,
|
||||
@ -1875,7 +1917,9 @@ render_outset_shadow_node (GskGLRenderer *self,
|
||||
graphene_rect_t prev_viewport;
|
||||
graphene_matrix_t item_proj;
|
||||
|
||||
gsk_gl_driver_create_render_target (self->gl_driver, texture_width, texture_height,
|
||||
gsk_gl_driver_create_render_target (self->gl_driver,
|
||||
texture_width, texture_height,
|
||||
GL_NEAREST, GL_NEAREST,
|
||||
&texture_id, &render_target);
|
||||
if (gdk_gl_context_has_debug (self->gl_context))
|
||||
{
|
||||
@ -3355,6 +3399,7 @@ add_offscreen_ops (GskGLRenderer *self,
|
||||
float prev_opacity = 1.0;
|
||||
int texture_id = 0;
|
||||
int max_texture_size;
|
||||
int filter;
|
||||
|
||||
if (node_is_invisible (child_node))
|
||||
{
|
||||
@ -3407,7 +3452,14 @@ add_offscreen_ops (GskGLRenderer *self,
|
||||
width = ceilf (width * scale);
|
||||
height = ceilf (height * scale);
|
||||
|
||||
gsk_gl_driver_create_render_target (self->gl_driver, width, height, &texture_id, &render_target);
|
||||
if (flags & LINEAR_FILTER)
|
||||
filter = GL_LINEAR;
|
||||
else
|
||||
filter = GL_NEAREST;
|
||||
gsk_gl_driver_create_render_target (self->gl_driver,
|
||||
width, height,
|
||||
filter, filter,
|
||||
&texture_id, &render_target);
|
||||
if (gdk_gl_context_has_debug (self->gl_context))
|
||||
{
|
||||
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
|
||||
|
Loading…
Reference in New Issue
Block a user