2 #include "xorg_renderer.h"
4 #include "xorg_exa_tgsi.h"
6 #include "cso_cache/cso_context.h"
7 #include "util/u_draw_quad.h"
8 #include "util/u_math.h"
9 #include "util/u_memory.h"
11 #include "pipe/p_inlines.h"
13 enum AxisOrientation
{
19 renderer_init_state(struct xorg_renderer
*r
)
21 struct pipe_depth_stencil_alpha_state dsa
;
23 /* set common initial clip state */
24 memset(&dsa
, 0, sizeof(struct pipe_depth_stencil_alpha_state
));
25 cso_set_depth_stencil_alpha(r
->cso
, &dsa
);
30 setup_vertex0(float vertex
[2][4], float x
, float y
,
35 vertex
[0][2] = 0.f
; /*z*/
36 vertex
[0][3] = 1.f
; /*w*/
38 vertex
[1][0] = color
[0]; /*r*/
39 vertex
[1][1] = color
[1]; /*g*/
40 vertex
[1][2] = color
[2]; /*b*/
41 vertex
[1][3] = color
[3]; /*a*/
45 setup_vertex1(float vertex
[2][4], float x
, float y
, float s
, float t
)
49 vertex
[0][2] = 0.f
; /*z*/
50 vertex
[0][3] = 1.f
; /*w*/
52 vertex
[1][0] = s
; /*s*/
53 vertex
[1][1] = t
; /*t*/
54 vertex
[1][2] = 0.f
; /*r*/
55 vertex
[1][3] = 1.f
; /*q*/
58 static struct pipe_buffer
*
59 setup_vertex_data1(struct xorg_renderer
*r
,
60 int srcX
, int srcY
, int dstX
, int dstY
,
61 int width
, int height
,
62 struct pipe_texture
*src
)
66 s0
= srcX
/ src
->width
[0];
67 s1
= srcX
+ width
/ src
->width
[0];
68 t0
= srcY
/ src
->height
[0];
69 t1
= srcY
+ height
/ src
->height
[0];
72 setup_vertex1(r
->vertices2
[0], dstX
, dstY
, s0
, t0
);
74 setup_vertex1(r
->vertices2
[1], dstX
+ width
, dstY
, s1
, t0
);
76 setup_vertex1(r
->vertices2
[2], dstX
+ width
, dstY
+ height
, s1
, t1
);
78 setup_vertex1(r
->vertices2
[3], dstX
, dstY
+ height
, s0
, t1
);
80 return pipe_user_buffer_create(r
->pipe
->screen
,
82 sizeof(r
->vertices2
));
85 static struct pipe_buffer
*
86 setup_vertex_data_tex(struct xorg_renderer
*r
,
87 float x0
, float y0
, float x1
, float y1
,
88 float s0
, float t0
, float s1
, float t1
,
92 setup_vertex1(r
->vertices2
[0], x0
, y0
, s0
, t0
);
94 setup_vertex1(r
->vertices2
[1], x1
, y0
, s1
, t0
);
96 setup_vertex1(r
->vertices2
[2], x1
, y1
, s1
, t1
);
98 setup_vertex1(r
->vertices2
[3], x0
, y1
, s0
, t1
);
100 return pipe_user_buffer_create(r
->pipe
->screen
,
102 sizeof(r
->vertices2
));
106 setup_vertex2(float vertex
[3][4], float x
, float y
,
107 float s0
, float t0
, float s1
, float t1
)
111 vertex
[0][2] = 0.f
; /*z*/
112 vertex
[0][3] = 1.f
; /*w*/
114 vertex
[1][0] = s0
; /*s*/
115 vertex
[1][1] = t0
; /*t*/
116 vertex
[1][2] = 0.f
; /*r*/
117 vertex
[1][3] = 1.f
; /*q*/
119 vertex
[2][0] = s1
; /*s*/
120 vertex
[2][1] = t1
; /*t*/
121 vertex
[2][2] = 0.f
; /*r*/
122 vertex
[2][3] = 1.f
; /*q*/
125 static struct pipe_buffer
*
126 setup_vertex_data2(struct xorg_renderer
*r
,
127 int srcX
, int srcY
, int maskX
, int maskY
,
128 int dstX
, int dstY
, int width
, int height
,
129 struct pipe_texture
*src
,
130 struct pipe_texture
*mask
)
132 float st0
[4], st1
[4];
134 st0
[0] = srcX
/ src
->width
[0];
135 st0
[1] = srcY
/ src
->height
[0];
136 st0
[2] = srcX
+ width
/ src
->width
[0];
137 st0
[3] = srcY
+ height
/ src
->height
[0];
139 st1
[0] = maskX
/ mask
->width
[0];
140 st1
[1] = maskY
/ mask
->height
[0];
141 st1
[2] = maskX
+ width
/ mask
->width
[0];
142 st1
[3] = maskY
+ height
/ mask
->height
[0];
145 setup_vertex2(r
->vertices3
[0], dstX
, dstY
,
146 st0
[0], st0
[1], st1
[0], st1
[1]);
148 setup_vertex2(r
->vertices3
[1], dstX
+ width
, dstY
,
149 st0
[2], st0
[1], st1
[2], st1
[1]);
151 setup_vertex2(r
->vertices3
[2], dstX
+ width
, dstY
+ height
,
152 st0
[2], st0
[3], st1
[2], st1
[3]);
154 setup_vertex2(r
->vertices3
[3], dstX
, dstY
+ height
,
155 st0
[0], st0
[3], st1
[0], st1
[3]);
157 return pipe_user_buffer_create(r
->pipe
->screen
,
159 sizeof(r
->vertices3
));
165 set_viewport(struct xorg_renderer
*r
, int width
, int height
,
166 enum AxisOrientation orientation
)
168 struct pipe_viewport_state viewport
;
169 float y_scale
= (orientation
== Y0_BOTTOM
) ? -2.f
: 2.f
;
171 viewport
.scale
[0] = width
/ 2.f
;
172 viewport
.scale
[1] = height
/ y_scale
;
173 viewport
.scale
[2] = 1.0;
174 viewport
.scale
[3] = 1.0;
175 viewport
.translate
[0] = width
/ 2.f
;
176 viewport
.translate
[1] = height
/ 2.f
;
177 viewport
.translate
[2] = 0.0;
178 viewport
.translate
[3] = 0.0;
180 cso_set_viewport(r
->cso
, &viewport
);
185 struct xorg_renderer
* renderer_create(struct pipe_context
*pipe
)
187 struct xorg_renderer
*renderer
= CALLOC_STRUCT(xorg_renderer
);
189 renderer
->pipe
= pipe
;
190 renderer
->cso
= cso_create_context(pipe
);
191 renderer
->shaders
= xorg_shaders_create(renderer
);
193 renderer_init_state(renderer
);
198 void renderer_destroy(struct xorg_renderer
*r
)
200 struct pipe_constant_buffer
*vsbuf
= &r
->vs_const_buffer
;
201 struct pipe_constant_buffer
*fsbuf
= &r
->fs_const_buffer
;
203 if (vsbuf
&& vsbuf
->buffer
)
204 pipe_buffer_reference(&vsbuf
->buffer
, NULL
);
206 if (fsbuf
&& fsbuf
->buffer
)
207 pipe_buffer_reference(&fsbuf
->buffer
, NULL
);
210 cso_release_all(r
->cso
);
211 cso_destroy_context(r
->cso
);
215 xorg_shaders_destroy(r
->shaders
);
219 void renderer_bind_framebuffer(struct xorg_renderer
*r
,
220 struct exa_pixmap_priv
*priv
)
223 struct pipe_framebuffer_state state
;
224 struct pipe_surface
*surface
= xorg_gpu_surface(r
->pipe
->screen
, priv
);
225 memset(&state
, 0, sizeof(struct pipe_framebuffer_state
));
227 state
.width
= priv
->tex
->width
[0];
228 state
.height
= priv
->tex
->height
[0];
231 state
.cbufs
[0] = surface
;
232 for (i
= 1; i
< PIPE_MAX_COLOR_BUFS
; ++i
)
235 /* currently we don't use depth/stencil */
238 cso_set_framebuffer(r
->cso
, &state
);
240 /* we do fire and forget for the framebuffer, this is the forget part */
241 pipe_surface_reference(&surface
, NULL
);
244 void renderer_bind_viewport(struct xorg_renderer
*r
,
245 struct exa_pixmap_priv
*dst
)
247 int width
= dst
->tex
->width
[0];
248 int height
= dst
->tex
->height
[0];
250 /*debug_printf("Bind viewport (%d, %d)\n", width, height);*/
252 set_viewport(r
, width
, height
, Y0_TOP
);
255 void renderer_bind_rasterizer(struct xorg_renderer
*r
)
257 struct pipe_rasterizer_state raster
;
259 /* XXX: move to renderer_init_state? */
260 memset(&raster
, 0, sizeof(struct pipe_rasterizer_state
));
261 raster
.gl_rasterization_rules
= 1;
262 cso_set_rasterizer(r
->cso
, &raster
);
265 void renderer_set_constants(struct xorg_renderer
*r
,
270 struct pipe_constant_buffer
*cbuf
=
271 (shader_type
== PIPE_SHADER_VERTEX
) ? &r
->vs_const_buffer
:
274 pipe_buffer_reference(&cbuf
->buffer
, NULL
);
275 cbuf
->buffer
= pipe_buffer_create(r
->pipe
->screen
, 16,
276 PIPE_BUFFER_USAGE_CONSTANT
,
280 pipe_buffer_write(r
->pipe
->screen
, cbuf
->buffer
,
281 0, param_bytes
, params
);
283 r
->pipe
->set_constant_buffer(r
->pipe
, shader_type
, 0, cbuf
);
287 setup_vs_constant_buffer(struct xorg_renderer
*r
,
288 int width
, int height
)
290 const int param_bytes
= 8 * sizeof(float);
291 float vs_consts
[8] = {
292 2.f
/width
, 2.f
/height
, 1, 1,
295 renderer_set_constants(r
, PIPE_SHADER_VERTEX
,
296 vs_consts
, param_bytes
);
300 setup_fs_constant_buffer(struct xorg_renderer
*r
)
302 const int param_bytes
= 4 * sizeof(float);
303 const float fs_consts
[8] = {
306 renderer_set_constants(r
, PIPE_SHADER_FRAGMENT
,
307 fs_consts
, param_bytes
);
310 static INLINE
void shift_rectx(float coords
[4],
317 coords
[2] = MIN2(coords
[2], bounds
[2]);
318 /* bound x/y + width/height */
319 if ((coords
[0] + coords
[2]) > (bounds
[0] + bounds
[2])) {
320 coords
[2] = (bounds
[0] + bounds
[2]) - coords
[0];
325 static INLINE
void shift_recty(float coords
[4],
332 coords
[3] = MIN2(coords
[3], bounds
[3]);
333 if ((coords
[1] + coords
[3]) > (bounds
[1] + bounds
[3])) {
334 coords
[3] = (bounds
[1] + bounds
[3]) - coords
[1];
339 static INLINE
void bound_rect(float coords
[4],
340 const float bounds
[4],
343 /* if outside the bounds */
344 if (coords
[0] > (bounds
[0] + bounds
[2]) ||
345 coords
[1] > (bounds
[1] + bounds
[3]) ||
346 (coords
[0] + coords
[2]) < bounds
[0] ||
347 (coords
[1] + coords
[3]) < bounds
[1]) {
358 if (coords
[0] < bounds
[0]) {
359 shift
[0] = bounds
[0] - coords
[0];
360 coords
[2] -= shift
[0];
361 coords
[0] = bounds
[0];
366 if (coords
[1] < bounds
[1]) {
367 shift
[1] = bounds
[1] - coords
[1];
368 coords
[3] -= shift
[1];
369 coords
[1] = bounds
[1];
373 shift
[2] = bounds
[2] - coords
[2];
374 shift
[3] = bounds
[3] - coords
[3];
375 /* bound width/height */
376 coords
[2] = MIN2(coords
[2], bounds
[2]);
377 coords
[3] = MIN2(coords
[3], bounds
[3]);
379 /* bound x/y + width/height */
380 if ((coords
[0] + coords
[2]) > (bounds
[0] + bounds
[2])) {
381 coords
[2] = (bounds
[0] + bounds
[2]) - coords
[0];
383 if ((coords
[1] + coords
[3]) > (bounds
[1] + bounds
[3])) {
384 coords
[3] = (bounds
[1] + bounds
[3]) - coords
[1];
387 /* if outside the bounds */
388 if ((coords
[0] + coords
[2]) < bounds
[0] ||
389 (coords
[1] + coords
[3]) < bounds
[1]) {
398 static INLINE
void sync_size(float *src_loc
, float *dst_loc
)
400 src_loc
[2] = MIN2(src_loc
[2], dst_loc
[2]);
401 src_loc
[3] = MIN2(src_loc
[3], dst_loc
[3]);
402 dst_loc
[2] = src_loc
[2];
403 dst_loc
[3] = src_loc
[3];
406 static void renderer_copy_texture(struct xorg_renderer
*r
,
407 struct pipe_texture
*src
,
408 float sx1
, float sy1
,
409 float sx2
, float sy2
,
410 struct pipe_texture
*dst
,
411 float dx1
, float dy1
,
412 float dx2
, float dy2
)
414 struct pipe_context
*pipe
= r
->pipe
;
415 struct pipe_screen
*screen
= pipe
->screen
;
416 struct pipe_buffer
*buf
;
417 struct pipe_surface
*dst_surf
= screen
->get_tex_surface(
418 screen
, dst
, 0, 0, 0,
419 PIPE_BUFFER_USAGE_GPU_WRITE
);
420 struct pipe_framebuffer_state fb
;
421 float s0
, t0
, s1
, t1
;
422 struct xorg_shader shader
;
424 assert(src
->width
[0] != 0);
425 assert(src
->height
[0] != 0);
426 assert(dst
->width
[0] != 0);
427 assert(dst
->height
[0] != 0);
430 s0
= sx1
/ src
->width
[0];
431 s1
= sx2
/ src
->width
[0];
432 t0
= sy1
/ src
->height
[0];
433 t1
= sy2
/ src
->height
[0];
442 debug_printf("copy texture src=[%f, %f, %f, %f], dst=[%f, %f, %f, %f], tex=[%f, %f, %f, %f]\n",
443 sx1
, sy1
, sx2
, sy2
, dx1
, dy1
, dx2
, dy2
,
447 assert(screen
->is_format_supported(screen
, dst_surf
->format
,
449 PIPE_TEXTURE_USAGE_RENDER_TARGET
,
452 /* save state (restored below) */
453 cso_save_blend(r
->cso
);
454 cso_save_samplers(r
->cso
);
455 cso_save_sampler_textures(r
->cso
);
456 cso_save_framebuffer(r
->cso
);
457 cso_save_fragment_shader(r
->cso
);
458 cso_save_vertex_shader(r
->cso
);
460 cso_save_viewport(r
->cso
);
463 /* set misc state we care about */
465 struct pipe_blend_state blend
;
466 memset(&blend
, 0, sizeof(blend
));
467 blend
.rgb_src_factor
= PIPE_BLENDFACTOR_ONE
;
468 blend
.alpha_src_factor
= PIPE_BLENDFACTOR_ONE
;
469 blend
.rgb_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
470 blend
.alpha_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
471 blend
.colormask
= PIPE_MASK_RGBA
;
472 cso_set_blend(r
->cso
, &blend
);
477 struct pipe_sampler_state sampler
;
478 memset(&sampler
, 0, sizeof(sampler
));
479 sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
480 sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
481 sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
482 sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
;
483 sampler
.min_img_filter
= PIPE_TEX_FILTER_NEAREST
;
484 sampler
.mag_img_filter
= PIPE_TEX_FILTER_NEAREST
;
485 sampler
.normalized_coords
= 1;
486 cso_single_sampler(r
->cso
, 0, &sampler
);
487 cso_single_sampler_done(r
->cso
);
490 set_viewport(r
, dst_surf
->width
, dst_surf
->height
, Y0_TOP
);
493 cso_set_sampler_textures(r
->cso
, 1, &src
);
495 renderer_bind_rasterizer(r
);
498 shader
= xorg_shaders_get(r
->shaders
,
501 cso_set_vertex_shader_handle(r
->cso
, shader
.vs
);
502 cso_set_fragment_shader_handle(r
->cso
, shader
.fs
);
505 memset(&fb
, 0, sizeof(fb
));
506 fb
.width
= dst_surf
->width
;
507 fb
.height
= dst_surf
->height
;
509 fb
.cbufs
[0] = dst_surf
;
512 for (i
= 1; i
< PIPE_MAX_COLOR_BUFS
; ++i
)
515 cso_set_framebuffer(r
->cso
, &fb
);
516 setup_vs_constant_buffer(r
, fb
.width
, fb
.height
);
517 setup_fs_constant_buffer(r
);
520 buf
= setup_vertex_data_tex(r
,
527 util_draw_vertex_buffer(r
->pipe
, buf
, 0,
528 PIPE_PRIM_TRIANGLE_FAN
,
530 2); /* attribs/vert */
532 pipe_buffer_reference(&buf
, NULL
);
535 /* restore state we changed */
536 cso_restore_blend(r
->cso
);
537 cso_restore_samplers(r
->cso
);
538 cso_restore_sampler_textures(r
->cso
);
539 cso_restore_framebuffer(r
->cso
);
540 cso_restore_vertex_shader(r
->cso
);
541 cso_restore_fragment_shader(r
->cso
);
542 cso_restore_viewport(r
->cso
);
544 pipe_surface_reference(&dst_surf
, NULL
);
547 static struct pipe_texture
*
548 create_sampler_texture(struct xorg_renderer
*r
,
549 struct pipe_texture
*src
)
551 enum pipe_format format
;
552 struct pipe_context
*pipe
= r
->pipe
;
553 struct pipe_screen
*screen
= pipe
->screen
;
554 struct pipe_texture
*pt
;
555 struct pipe_texture templ
;
557 pipe
->flush(pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
559 /* the coming in texture should already have that invariance */
560 debug_assert(screen
->is_format_supported(screen
, src
->format
,
562 PIPE_TEXTURE_USAGE_SAMPLER
, 0));
564 format
= src
->format
;
566 memset(&templ
, 0, sizeof(templ
));
567 templ
.target
= PIPE_TEXTURE_2D
;
568 templ
.format
= format
;
569 templ
.last_level
= 0;
570 templ
.width
[0] = src
->width
[0];
571 templ
.height
[0] = src
->height
[0];
573 pf_get_block(format
, &templ
.block
);
574 templ
.tex_usage
= PIPE_TEXTURE_USAGE_SAMPLER
;
576 pt
= screen
->texture_create(screen
, &templ
);
578 debug_assert(!pt
|| pipe_is_referenced(&pt
->reference
));
584 /* copy source framebuffer surface into texture */
585 struct pipe_surface
*ps_read
= screen
->get_tex_surface(
586 screen
, src
, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ
);
587 struct pipe_surface
*ps_tex
= screen
->get_tex_surface(
588 screen
, pt
, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE
);
589 pipe
->surface_copy(pipe
,
593 0, 0, src
->width
[0], src
->height
[0]);
594 pipe_surface_reference(&ps_read
, NULL
);
595 pipe_surface_reference(&ps_tex
, NULL
);
602 void renderer_copy_pixmap(struct xorg_renderer
*r
,
603 struct exa_pixmap_priv
*dst_priv
, int dx
, int dy
,
604 struct exa_pixmap_priv
*src_priv
, int sx
, int sy
,
605 int width
, int height
)
607 float dst_loc
[4], src_loc
[4];
608 float dst_bounds
[4], src_bounds
[4];
609 float src_shift
[4], dst_shift
[4], shift
[4];
610 struct pipe_texture
*dst
= dst_priv
->tex
;
611 struct pipe_texture
*src
= src_priv
->tex
;
613 if (r
->pipe
->is_texture_referenced(r
->pipe
, src
, 0, 0) &
614 PIPE_REFERENCED_FOR_WRITE
)
615 r
->pipe
->flush(r
->pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
623 dst_bounds
[2] = dst
->width
[0];
624 dst_bounds
[3] = dst
->height
[0];
632 src_bounds
[2] = src
->width
[0];
633 src_bounds
[3] = src
->height
[0];
635 bound_rect(src_loc
, src_bounds
, src_shift
);
636 bound_rect(dst_loc
, dst_bounds
, dst_shift
);
637 shift
[0] = src_shift
[0] - dst_shift
[0];
638 shift
[1] = src_shift
[1] - dst_shift
[1];
641 shift_rectx(src_loc
, src_bounds
, -shift
[0]);
643 shift_rectx(dst_loc
, dst_bounds
, shift
[0]);
646 shift_recty(src_loc
, src_bounds
, -shift
[1]);
648 shift_recty(dst_loc
, dst_bounds
, shift
[1]);
650 sync_size(src_loc
, dst_loc
);
652 if (src_loc
[2] >= 0 && src_loc
[3] >= 0 &&
653 dst_loc
[2] >= 0 && dst_loc
[3] >= 0) {
654 struct pipe_texture
*temp_src
= src
;
657 temp_src
= create_sampler_texture(r
, src
);
659 renderer_copy_texture(r
,
663 src_loc
[0] + src_loc
[2],
664 src_loc
[1] + src_loc
[3],
668 dst_loc
[0] + dst_loc
[2],
669 dst_loc
[1] + dst_loc
[3]);
672 pipe_texture_reference(&temp_src
, NULL
);
676 void renderer_draw_solid_rect(struct xorg_renderer
*r
,
681 struct pipe_context
*pipe
= r
->pipe
;
682 struct pipe_buffer
*buf
= 0;
685 setup_vertex0(r
->vertices2
[0], x0
, y0
, color
);
687 setup_vertex0(r
->vertices2
[1], x1
, y0
, color
);
689 setup_vertex0(r
->vertices2
[2], x1
, y1
, color
);
691 setup_vertex0(r
->vertices2
[3], x0
, y1
, color
);
693 buf
= pipe_user_buffer_create(pipe
->screen
,
695 sizeof(r
->vertices2
));
699 util_draw_vertex_buffer(pipe
, buf
, 0,
700 PIPE_PRIM_TRIANGLE_FAN
,
702 2); /* attribs/vert */
704 pipe_buffer_reference(&buf
, NULL
);
708 void renderer_draw_textures(struct xorg_renderer
*r
,
710 int width
, int height
,
711 struct pipe_texture
**textures
,
714 struct pipe_context
*pipe
= r
->pipe
;
715 struct pipe_buffer
*buf
= 0;
717 switch(num_textures
) {
719 buf
= setup_vertex_data1(r
,
720 pos
[0], pos
[1], /* src */
721 pos
[4], pos
[5], /* dst */
726 buf
= setup_vertex_data2(r
,
727 pos
[0], pos
[1], /* src */
728 pos
[2], pos
[3], /* mask */
729 pos
[4], pos
[5], /* dst */
731 textures
[0], textures
[1]);
734 debug_assert(!"Unsupported number of textures");
739 int num_attribs
= 1; /*pos*/
740 num_attribs
+= num_textures
;
742 util_draw_vertex_buffer(pipe
, buf
, 0,
743 PIPE_PRIM_TRIANGLE_FAN
,
745 num_attribs
); /* attribs/vert */
747 pipe_buffer_reference(&buf
, NULL
);