@ -70,6 +70,7 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
} ) ;
} ) ;
}
}
// Rotate the final destination size into source coordinates
struct wlr_box orig_box ;
struct wlr_box orig_box ;
wlr_box_transform ( & orig_box , & dst_box , options - > transform ,
wlr_box_transform ( & orig_box , & dst_box , options - > transform ,
buffer - > buffer - > width , buffer - > buffer - > height ) ;
buffer - > buffer - > width , buffer - > buffer - > height ) ;
@ -87,58 +88,66 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
case WL_OUTPUT_TRANSFORM_FLIPPED_90 :
case WL_OUTPUT_TRANSFORM_FLIPPED_90 :
tr_cos = 0 ;
tr_cos = 0 ;
tr_sin = 1 ;
tr_sin = 1 ;
tr_ x = buffer - > buffer - > height ;
tr_ y = src_box . width ;
break ;
break ;
case WL_OUTPUT_TRANSFORM_180 :
case WL_OUTPUT_TRANSFORM_180 :
case WL_OUTPUT_TRANSFORM_FLIPPED_180 :
case WL_OUTPUT_TRANSFORM_FLIPPED_180 :
tr_cos = - 1 ;
tr_cos = - 1 ;
tr_sin = 0 ;
tr_sin = 0 ;
tr_x = buffer- > buffer - > width ;
tr_x = src_box. width ;
tr_y = buffer- > buffer - > height ;
tr_y = src_box. height ;
break ;
break ;
case WL_OUTPUT_TRANSFORM_270 :
case WL_OUTPUT_TRANSFORM_270 :
case WL_OUTPUT_TRANSFORM_FLIPPED_270 :
case WL_OUTPUT_TRANSFORM_FLIPPED_270 :
tr_cos = 0 ;
tr_cos = 0 ;
tr_sin = - 1 ;
tr_sin = - 1 ;
tr_ y = buffer - > buffer - > width ;
tr_ x = src_box . height ;
break ;
break ;
}
}
switch ( options - > transform ) {
// Pixman transforms are generally the opposite of what you expect because they
case WL_OUTPUT_TRANSFORM_FLIPPED :
// apply to the coordinate system rather than the image. The comments here
case WL_OUTPUT_TRANSFORM_FLIPPED_180 :
// refer to what happens to the image, so all the code between
tr_x = buffer - > buffer - > width - tr_x ;
// pixman_transform_init_identity() and pixman_image_set_transform() is probably
break ;
// best read backwards. Also this means translations are in the opposite
case WL_OUTPUT_TRANSFORM_FLIPPED_90 :
// direction, imagine them as moving the origin around rather than moving the
case WL_OUTPUT_TRANSFORM_FLIPPED_270 :
// image.
tr_x = buffer - > buffer - > height - tr_x ;
//
break ;
// Beware that this doesn't work quite the same as wp_viewporter: We apply crop
case WL_OUTPUT_TRANSFORM_NORMAL :
// before transform and scale, whereas it defines crop in post-transform-scale
case WL_OUTPUT_TRANSFORM_90 :
// coordinates. But this only applies to internal wlroots code - the viewporter
case WL_OUTPUT_TRANSFORM_180 :
// extension code makes sure that to clients everything works as it should.
case WL_OUTPUT_TRANSFORM_270 :
break ;
}
struct pixman_transform transform ;
struct pixman_transform transform ;
pixman_transform_init_identity ( & transform ) ;
pixman_transform_init_identity ( & transform ) ;
pixman_transform_rotate ( & transform , NULL ,
pixman_int_to_fixed ( tr_cos ) , pixman_int_to_fixed ( tr_sin ) ) ;
// Apply scaling to get to the dst_box size. Because the scaling is applied last
if ( options - > transform > = WL_OUTPUT_TRANSFORM_FLIPPED ) {
// it depends on the whether the rotation swapped width and height, which is why
// we use orig_box instead of dst_box.
pixman_transform_scale ( & transform , NULL ,
pixman_transform_scale ( & transform , NULL ,
pixman_int_to_fixed ( - 1 ) , pixman_int_to_fixed ( 1 ) ) ;
pixman_double_to_fixed ( src_box . width / ( double ) orig_box . width ) ,
}
pixman_double_to_fixed ( src_box . height / ( double ) orig_box . height ) ) ;
// pixman rotates about the origin, translate the result so that its new top-left
// pixman rotates about the origin which again leaves everything outside of the
// corner is back at the origin.
// viewport. Translate the result so that its new top-left corner is back at the
// origin.
pixman_transform_translate ( & transform , NULL ,
pixman_transform_translate ( & transform , NULL ,
pixman_int_to_fixed ( tr_x ) , pixman_int_to_fixed ( tr_y ) ) ;
- pixman_int_to_fixed ( tr_x ) , - pixman_int_to_fixed ( tr_y ) ) ;
// Apply the rotation
pixman_transform_rotate ( & transform , NULL ,
pixman_int_to_fixed ( tr_cos ) , pixman_int_to_fixed ( tr_sin ) ) ;
// Apply flip before rotation
if ( options - > transform > = WL_OUTPUT_TRANSFORM_FLIPPED ) {
// The flip leaves everything left of the Y axis which is outside the
// viewport. So translate everything back into the viewport.
pixman_transform_translate ( & transform , NULL ,
pixman_transform_translate ( & transform , NULL ,
- pixman_int_to_fixed ( orig_box . x ) , - pixman_int_to_fixed ( orig_box . y ) ) ;
- pixman_int_to_fixed ( src_box . width ) , pixman_int_to_fixed ( 0 ) ) ;
// Flip by applying a scale of -1 to the X axis
pixman_transform_scale ( & transform , NULL ,
pixman_transform_scale ( & transform , NULL ,
pixman_double_to_fixed ( src_box . width / ( double ) orig_box . width ) ,
pixman_int_to_fixed ( - 1 ) , pixman_int_to_fixed ( 1 ) ) ;
pixman_double_to_fixed ( src_box . height / ( double ) orig_box . height ) ) ;
}
// Apply the translation for source crop so the origin is now at the top-left of
// Apply the translation for source crop so the origin is now at the top-left of
// the region we're actually using. Do this last so all the other transforms
// the region we're actually using. Do this last so all the other transforms
@ -146,6 +155,8 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
pixman_transform_translate ( & transform , NULL ,
pixman_transform_translate ( & transform , NULL ,
pixman_int_to_fixed ( src_box . x ) , pixman_int_to_fixed ( src_box . y ) ) ;
pixman_int_to_fixed ( src_box . x ) , pixman_int_to_fixed ( src_box . y ) ) ;
pixman_image_set_transform ( texture - > image , & transform ) ;
switch ( options - > filter_mode ) {
switch ( options - > filter_mode ) {
case WLR_SCALE_FILTER_BILINEAR :
case WLR_SCALE_FILTER_BILINEAR :
pixman_image_set_filter ( texture - > image , PIXMAN_FILTER_BILINEAR , NULL , 0 ) ;
pixman_image_set_filter ( texture - > image , PIXMAN_FILTER_BILINEAR , NULL , 0 ) ;
@ -155,12 +166,17 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
break ;
break ;
}
}
pixman_image_set_transform ( texture - > image , & transform ) ;
// Now composite the result onto the pass buffer. We specify a source origin of 0,0
// because the x,y part of source crop is already done using the transform. The
// We've already applied the transforms for source crop and scaling so just
// width,height part of source crop is done here by the width and height we pass:
// composite over the whole output and let the transform deal with everything.
// because of the scaling, cropping at the end by dst_box.{width,height} is
// equivalent to if we cropped at the start by src_box.{width,height}.
pixman_image_composite32 ( op , texture - > image , mask , buffer - > image ,
pixman_image_composite32 ( op , texture - > image , mask , buffer - > image ,
0 , 0 , 0 , 0 , 0 , 0 , buffer - > buffer - > width , buffer - > buffer - > height ) ;
0 , 0 , // source x,y
0 , 0 , // mask x,y
dst_box . x , dst_box . y , // dest x,y
dst_box . width , dst_box . height // composite width,height
) ;
pixman_image_set_transform ( texture - > image , NULL ) ;
pixman_image_set_transform ( texture - > image , NULL ) ;
} else {
} else {