forked from AuroraMiddleware/gtk
Merge branch 'gl-linear' into 'master'
Gl: use linear interpolation See merge request GNOME/gtk!2523
This commit is contained in:
commit
bab7092a69
@ -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,
|
||||
@ -1035,11 +1068,10 @@ render_transform_node (GskGLRenderer *self,
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
|
||||
case GSK_TRANSFORM_CATEGORY_ANY:
|
||||
case GSK_TRANSFORM_CATEGORY_3D:
|
||||
case GSK_TRANSFORM_CATEGORY_2D:
|
||||
default:
|
||||
case GSK_TRANSFORM_CATEGORY_3D:
|
||||
case GSK_TRANSFORM_CATEGORY_ANY:
|
||||
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
|
||||
{
|
||||
TextureRegion region;
|
||||
gboolean is_offscreen;
|
||||
@ -1050,29 +1082,42 @@ render_transform_node (GskGLRenderer *self,
|
||||
gsk_gl_renderer_add_render_ops (self, child, builder);
|
||||
ops_pop_modelview (builder);
|
||||
}
|
||||
else if (add_offscreen_ops (self, builder,
|
||||
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;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1451,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,
|
||||
@ -1696,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,
|
||||
@ -1869,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))
|
||||
{
|
||||
@ -3349,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))
|
||||
{
|
||||
@ -3401,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,
|
||||
|
@ -2204,13 +2204,11 @@ gsk_matrix_transform_point3d (const graphene_matrix_t *m,
|
||||
}
|
||||
|
||||
void
|
||||
gsk_matrix_transform_bounds (const graphene_matrix_t *m,
|
||||
const graphene_rect_t *r,
|
||||
graphene_rect_t *res)
|
||||
gsk_matrix_transform_rect (const graphene_matrix_t *m,
|
||||
const graphene_rect_t *r,
|
||||
graphene_quad_t *res)
|
||||
{
|
||||
graphene_point_t ret[4];
|
||||
float min_x, min_y;
|
||||
float max_x, max_y;
|
||||
graphene_rect_t rr;
|
||||
|
||||
graphene_rect_normalize_r (r, &rr);
|
||||
@ -2233,12 +2231,15 @@ gsk_matrix_transform_bounds (const graphene_matrix_t *m,
|
||||
|
||||
#undef TRANSFORM_POINT
|
||||
|
||||
/* FIXME: graphene doesn't export a fast way to do this */
|
||||
min_x = MIN (MIN (ret[0].x, ret[1].x), MIN (ret[2].x, ret[3].x));
|
||||
min_y = MIN (MIN (ret[0].y, ret[1].y), MIN (ret[2].y, ret[3].y));
|
||||
|
||||
max_x = MAX (MAX (ret[0].x, ret[1].x), MAX (ret[2].x, ret[3].x));
|
||||
max_y = MAX (MAX (ret[0].y, ret[1].y), MAX (ret[2].y, ret[3].y));
|
||||
|
||||
graphene_rect_init (res, min_x, min_y, max_x - min_x, max_y - min_y);
|
||||
graphene_quad_init (res, &ret[0], &ret[1], &ret[2], &ret[3]);
|
||||
}
|
||||
void
|
||||
gsk_matrix_transform_bounds (const graphene_matrix_t *m,
|
||||
const graphene_rect_t *r,
|
||||
graphene_rect_t *res)
|
||||
{
|
||||
graphene_quad_t q;
|
||||
|
||||
gsk_matrix_transform_rect (m, r, &q);
|
||||
graphene_quad_bounds (&q, res);
|
||||
}
|
||||
|
@ -41,7 +41,9 @@ void gsk_matrix_transform_point3d (const graphene_matrix_t *m,
|
||||
void gsk_matrix_transform_bounds (const graphene_matrix_t *m,
|
||||
const graphene_rect_t *r,
|
||||
graphene_rect_t *res);
|
||||
|
||||
void gsk_matrix_transform_rect (const graphene_matrix_t *m,
|
||||
const graphene_rect_t *r,
|
||||
graphene_quad_t *res);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -36,6 +36,7 @@ int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GtkWidget *window, *fixed, *button;
|
||||
GtkWidget *fixed2, *frame;
|
||||
gboolean done = FALSE;
|
||||
GskTransform *transform;
|
||||
|
||||
@ -52,8 +53,7 @@ main (int argc, char *argv[])
|
||||
gtk_widget_set_vexpand (fixed, TRUE);
|
||||
|
||||
button = gtk_button_new ();
|
||||
gtk_button_set_label (GTK_BUTTON (button), "Hello world");
|
||||
//gtk_widget_set_size_request (button, 50, 50);
|
||||
gtk_button_set_label (GTK_BUTTON (button), "Button");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (hello), NULL);
|
||||
|
||||
gtk_fixed_put (GTK_FIXED (fixed), button, 0, 0);
|
||||
@ -62,11 +62,27 @@ main (int argc, char *argv[])
|
||||
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (0, 0, 50));
|
||||
transform = gsk_transform_perspective (transform, 170);
|
||||
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (50, 0, 50));
|
||||
transform = gsk_transform_rotate (transform, 30);
|
||||
transform = gsk_transform_rotate_3d (transform, 30, graphene_vec3_y_axis ());
|
||||
transform = gsk_transform_rotate (transform, 20);
|
||||
transform = gsk_transform_rotate_3d (transform, 20, graphene_vec3_y_axis ());
|
||||
gtk_fixed_set_child_transform (GTK_FIXED (fixed), button, transform);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), fixed);
|
||||
frame = gtk_frame_new ("Frame");
|
||||
gtk_widget_add_css_class (frame, "view");
|
||||
gtk_frame_set_child (GTK_FRAME (frame), fixed);
|
||||
|
||||
fixed2 = gtk_fixed_new ();
|
||||
|
||||
gtk_fixed_put (GTK_FIXED (fixed2), frame, 0, 0);
|
||||
|
||||
transform = NULL;
|
||||
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (0, 0, 50));
|
||||
transform = gsk_transform_perspective (transform, 170);
|
||||
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (50, 0, 50));
|
||||
transform = gsk_transform_rotate (transform, 20);
|
||||
transform = gsk_transform_rotate_3d (transform, 20, graphene_vec3_y_axis ());
|
||||
gtk_fixed_set_child_transform (GTK_FIXED (fixed2), frame, transform);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), fixed2);
|
||||
|
||||
gtk_widget_show (window);
|
||||
|
||||
|
22
testsuite/gsk/compare/clip-coordinates-2d.node
Normal file
22
testsuite/gsk/compare/clip-coordinates-2d.node
Normal file
@ -0,0 +1,22 @@
|
||||
/* This test checks that we get sharp clip boundaries
|
||||
* for 2d transforms. Compare with clip-coordinates-3d.node,
|
||||
* which uses a general transform and gets offscreen
|
||||
* rendering with GL_LINEAR.
|
||||
*/
|
||||
transform {
|
||||
transform: scale(2);
|
||||
child: container {
|
||||
color {
|
||||
bounds: 0 0 50 50;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
clip {
|
||||
clip: 10 10 30 30;
|
||||
child: color {
|
||||
bounds: 0 0 50 50;
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
BIN
testsuite/gsk/compare/clip-coordinates-2d.png
Normal file
BIN
testsuite/gsk/compare/clip-coordinates-2d.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 269 B |
@ -22,6 +22,7 @@ node_parser = executable(
|
||||
compare_render_tests = [
|
||||
'blend-normal',
|
||||
'blend-difference',
|
||||
'clip-coordinates-2d',
|
||||
'clip-coordinates-3d',
|
||||
'clipped_rounded_clip',
|
||||
'color-blur0',
|
||||
|
@ -406,6 +406,122 @@ test_print_parse (void)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_matrix_transform_rect (const graphene_matrix_t *m,
|
||||
const graphene_rect_t *r,
|
||||
graphene_quad_t *res)
|
||||
{
|
||||
graphene_point_t ret[4];
|
||||
graphene_rect_t rr;
|
||||
|
||||
graphene_rect_normalize_r (r, &rr);
|
||||
|
||||
#define TRANSFORM_POINT(matrix, rect, corner, out_p) do {\
|
||||
graphene_vec4_t __s; \
|
||||
graphene_point_t __p; \
|
||||
float w; \
|
||||
graphene_rect_get_ ## corner (rect, &__p); \
|
||||
graphene_vec4_init (&__s, __p.x, __p.y, 0.f, 1.f); \
|
||||
graphene_matrix_transform_vec4 (matrix, &__s, &__s); \
|
||||
w = graphene_vec4_get_w (&__s); \
|
||||
out_p.x = graphene_vec4_get_x (&__s) / w; \
|
||||
out_p.y = graphene_vec4_get_y (&__s) / w; } while (0)
|
||||
|
||||
TRANSFORM_POINT (m, &rr, top_left, ret[0]);
|
||||
TRANSFORM_POINT (m, &rr, top_right, ret[1]);
|
||||
TRANSFORM_POINT (m, &rr, bottom_right, ret[2]);
|
||||
TRANSFORM_POINT (m, &rr, bottom_left, ret[3]);
|
||||
|
||||
#undef TRANSFORM_POINT
|
||||
|
||||
graphene_quad_init (res, &ret[0], &ret[1], &ret[2], &ret[3]);
|
||||
}
|
||||
|
||||
/* This is an auxiliary function used in the GL renderer to
|
||||
* determine if transforming an axis-aligned rectangle produces
|
||||
* axis-aligned output, to decide whether to use linear
|
||||
* interpolation or not.
|
||||
*
|
||||
* Keep this in sync with gsk/gl/gskglrenderer.c
|
||||
*/
|
||||
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 void
|
||||
test_axis_aligned (void)
|
||||
{
|
||||
graphene_rect_t r = GRAPHENE_RECT_INIT (0, 0, 10, 10);
|
||||
GskTransform *transform = NULL;
|
||||
|
||||
transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10, 10));
|
||||
g_assert_true (result_is_axis_aligned (transform, &r));
|
||||
gsk_transform_unref (transform);
|
||||
|
||||
transform = gsk_transform_translate_3d (NULL, &GRAPHENE_POINT3D_INIT(0, 10, 10));
|
||||
g_assert_true (result_is_axis_aligned (transform, &r));
|
||||
gsk_transform_unref (transform);
|
||||
|
||||
transform = gsk_transform_rotate (NULL, 90);
|
||||
g_assert_true (result_is_axis_aligned (transform, &r));
|
||||
gsk_transform_unref (transform);
|
||||
|
||||
transform = gsk_transform_scale (NULL, 2, 3);
|
||||
g_assert_true (result_is_axis_aligned (transform, &r));
|
||||
gsk_transform_unref (transform);
|
||||
|
||||
/* rotating around the y axis does not affect axis alignedness,
|
||||
* as long as we don't involve perspective
|
||||
*/
|
||||
transform = gsk_transform_rotate_3d (NULL, 45, graphene_vec3_y_axis ());
|
||||
g_assert_true (result_is_axis_aligned (transform, &r));
|
||||
gsk_transform_unref (transform);
|
||||
|
||||
/* rotating by 45 around the z axis, not axis aligned */
|
||||
transform = gsk_transform_rotate (NULL, 45);
|
||||
g_assert_false (result_is_axis_aligned (transform, &r));
|
||||
gsk_transform_unref (transform);
|
||||
|
||||
/* perspective is harmless as long as we stay in the z=0 plane */
|
||||
transform = gsk_transform_perspective (NULL, 100);
|
||||
g_assert_true (result_is_axis_aligned (transform, &r));
|
||||
gsk_transform_unref (transform);
|
||||
|
||||
/* a complex transform that makes things look '3d' */
|
||||
transform = gsk_transform_translate_3d (NULL, &GRAPHENE_POINT3D_INIT (0, 0, 50));
|
||||
transform = gsk_transform_perspective (transform, 170);
|
||||
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (50, 0, 50));
|
||||
transform = gsk_transform_rotate (transform, 20);
|
||||
transform = gsk_transform_rotate_3d (transform, 20, graphene_vec3_y_axis ());
|
||||
g_assert_false (result_is_axis_aligned (transform, &r));
|
||||
gsk_transform_unref (transform);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
@ -418,6 +534,7 @@ main (int argc,
|
||||
g_test_add_func ("/transform/identity-equal", test_identity_equal);
|
||||
g_test_add_func ("/transform/invert", test_invert);
|
||||
g_test_add_func ("/transform/print-parse", test_print_parse);
|
||||
g_test_add_func ("/transform/check-axis-aligneness", test_axis_aligned);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user