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"
10 #include "util/u_rect.h"
12 #include "pipe/p_inlines.h"
14 enum AxisOrientation
{
20 renderer_init_state(struct xorg_renderer
*r
)
22 struct pipe_depth_stencil_alpha_state dsa
;
24 /* set common initial clip state */
25 memset(&dsa
, 0, sizeof(struct pipe_depth_stencil_alpha_state
));
26 cso_set_depth_stencil_alpha(r
->cso
, &dsa
);
31 setup_vertex0(float vertex
[2][4], float x
, float y
,
36 vertex
[0][2] = 0.f
; /*z*/
37 vertex
[0][3] = 1.f
; /*w*/
39 vertex
[1][0] = color
[0]; /*r*/
40 vertex
[1][1] = color
[1]; /*g*/
41 vertex
[1][2] = color
[2]; /*b*/
42 vertex
[1][3] = color
[3]; /*a*/
46 setup_vertex1(float vertex
[2][4], float x
, float y
, float s
, float t
)
50 vertex
[0][2] = 0.f
; /*z*/
51 vertex
[0][3] = 1.f
; /*w*/
53 vertex
[1][0] = s
; /*s*/
54 vertex
[1][1] = t
; /*t*/
55 vertex
[1][2] = 0.f
; /*r*/
56 vertex
[1][3] = 1.f
; /*q*/
59 static struct pipe_buffer
*
60 setup_vertex_data1(struct xorg_renderer
*r
,
61 int srcX
, int srcY
, int dstX
, int dstY
,
62 int width
, int height
,
63 struct pipe_texture
*src
)
67 s0
= srcX
/ src
->width
[0];
68 s1
= srcX
+ width
/ src
->width
[0];
69 t0
= srcY
/ src
->height
[0];
70 t1
= srcY
+ height
/ src
->height
[0];
73 setup_vertex1(r
->vertices2
[0], dstX
, dstY
, s0
, t0
);
75 setup_vertex1(r
->vertices2
[1], dstX
+ width
, dstY
, s1
, t0
);
77 setup_vertex1(r
->vertices2
[2], dstX
+ width
, dstY
+ height
, s1
, t1
);
79 setup_vertex1(r
->vertices2
[3], dstX
, dstY
+ height
, s0
, t1
);
81 return pipe_user_buffer_create(r
->pipe
->screen
,
83 sizeof(r
->vertices2
));
86 static struct pipe_buffer
*
87 setup_vertex_data_tex(struct xorg_renderer
*r
,
88 float x0
, float y0
, float x1
, float y1
,
89 float s0
, float t0
, float s1
, float t1
,
93 setup_vertex1(r
->vertices2
[0], x0
, y0
, s0
, t0
);
95 setup_vertex1(r
->vertices2
[1], x1
, y0
, s1
, t0
);
97 setup_vertex1(r
->vertices2
[2], x1
, y1
, s1
, t1
);
99 setup_vertex1(r
->vertices2
[3], x0
, y1
, s0
, t1
);
101 return pipe_user_buffer_create(r
->pipe
->screen
,
103 sizeof(r
->vertices2
));
107 setup_vertex2(float vertex
[3][4], float x
, float y
,
108 float s0
, float t0
, float s1
, float t1
)
112 vertex
[0][2] = 0.f
; /*z*/
113 vertex
[0][3] = 1.f
; /*w*/
115 vertex
[1][0] = s0
; /*s*/
116 vertex
[1][1] = t0
; /*t*/
117 vertex
[1][2] = 0.f
; /*r*/
118 vertex
[1][3] = 1.f
; /*q*/
120 vertex
[2][0] = s1
; /*s*/
121 vertex
[2][1] = t1
; /*t*/
122 vertex
[2][2] = 0.f
; /*r*/
123 vertex
[2][3] = 1.f
; /*q*/
126 static struct pipe_buffer
*
127 setup_vertex_data2(struct xorg_renderer
*r
,
128 int srcX
, int srcY
, int maskX
, int maskY
,
129 int dstX
, int dstY
, int width
, int height
,
130 struct pipe_texture
*src
,
131 struct pipe_texture
*mask
)
133 float st0
[4], st1
[4];
135 st0
[0] = srcX
/ src
->width
[0];
136 st0
[1] = srcY
/ src
->height
[0];
137 st0
[2] = srcX
+ width
/ src
->width
[0];
138 st0
[3] = srcY
+ height
/ src
->height
[0];
140 st1
[0] = maskX
/ mask
->width
[0];
141 st1
[1] = maskY
/ mask
->height
[0];
142 st1
[2] = maskX
+ width
/ mask
->width
[0];
143 st1
[3] = maskY
+ height
/ mask
->height
[0];
146 setup_vertex2(r
->vertices3
[0], dstX
, dstY
,
147 st0
[0], st0
[1], st1
[0], st1
[1]);
149 setup_vertex2(r
->vertices3
[1], dstX
+ width
, dstY
,
150 st0
[2], st0
[1], st1
[2], st1
[1]);
152 setup_vertex2(r
->vertices3
[2], dstX
+ width
, dstY
+ height
,
153 st0
[2], st0
[3], st1
[2], st1
[3]);
155 setup_vertex2(r
->vertices3
[3], dstX
, dstY
+ height
,
156 st0
[0], st0
[3], st1
[0], st1
[3]);
158 return pipe_user_buffer_create(r
->pipe
->screen
,
160 sizeof(r
->vertices3
));
166 set_viewport(struct xorg_renderer
*r
, int width
, int height
,
167 enum AxisOrientation orientation
)
169 struct pipe_viewport_state viewport
;
170 float y_scale
= (orientation
== Y0_BOTTOM
) ? -2.f
: 2.f
;
172 viewport
.scale
[0] = width
/ 2.f
;
173 viewport
.scale
[1] = height
/ y_scale
;
174 viewport
.scale
[2] = 1.0;
175 viewport
.scale
[3] = 1.0;
176 viewport
.translate
[0] = width
/ 2.f
;
177 viewport
.translate
[1] = height
/ 2.f
;
178 viewport
.translate
[2] = 0.0;
179 viewport
.translate
[3] = 0.0;
181 cso_set_viewport(r
->cso
, &viewport
);
186 struct xorg_renderer
* renderer_create(struct pipe_context
*pipe
)
188 struct xorg_renderer
*renderer
= CALLOC_STRUCT(xorg_renderer
);
190 renderer
->pipe
= pipe
;
191 renderer
->cso
= cso_create_context(pipe
);
192 renderer
->shaders
= xorg_shaders_create(renderer
);
194 renderer_init_state(renderer
);
199 void renderer_destroy(struct xorg_renderer
*r
)
201 struct pipe_constant_buffer
*vsbuf
= &r
->vs_const_buffer
;
202 struct pipe_constant_buffer
*fsbuf
= &r
->fs_const_buffer
;
204 if (vsbuf
&& vsbuf
->buffer
)
205 pipe_buffer_reference(&vsbuf
->buffer
, NULL
);
207 if (fsbuf
&& fsbuf
->buffer
)
208 pipe_buffer_reference(&fsbuf
->buffer
, NULL
);
211 cso_release_all(r
->cso
);
212 cso_destroy_context(r
->cso
);
216 xorg_shaders_destroy(r
->shaders
);
220 void renderer_bind_framebuffer(struct xorg_renderer
*r
,
221 struct exa_pixmap_priv
*priv
)
224 struct pipe_framebuffer_state state
;
225 struct pipe_surface
*surface
= xorg_gpu_surface(r
->pipe
->screen
, priv
);
226 memset(&state
, 0, sizeof(struct pipe_framebuffer_state
));
228 state
.width
= priv
->tex
->width
[0];
229 state
.height
= priv
->tex
->height
[0];
232 state
.cbufs
[0] = surface
;
233 for (i
= 1; i
< PIPE_MAX_COLOR_BUFS
; ++i
)
236 /* currently we don't use depth/stencil */
239 cso_set_framebuffer(r
->cso
, &state
);
241 /* we do fire and forget for the framebuffer, this is the forget part */
242 pipe_surface_reference(&surface
, NULL
);
245 void renderer_bind_viewport(struct xorg_renderer
*r
,
246 struct exa_pixmap_priv
*dst
)
248 int width
= dst
->tex
->width
[0];
249 int height
= dst
->tex
->height
[0];
251 /*debug_printf("Bind viewport (%d, %d)\n", width, height);*/
253 set_viewport(r
, width
, height
, Y0_TOP
);
256 void renderer_bind_rasterizer(struct xorg_renderer
*r
)
258 struct pipe_rasterizer_state raster
;
260 /* XXX: move to renderer_init_state? */
261 memset(&raster
, 0, sizeof(struct pipe_rasterizer_state
));
262 raster
.gl_rasterization_rules
= 1;
263 cso_set_rasterizer(r
->cso
, &raster
);
266 void renderer_set_constants(struct xorg_renderer
*r
,
271 struct pipe_constant_buffer
*cbuf
=
272 (shader_type
== PIPE_SHADER_VERTEX
) ? &r
->vs_const_buffer
:
275 pipe_buffer_reference(&cbuf
->buffer
, NULL
);
276 cbuf
->buffer
= pipe_buffer_create(r
->pipe
->screen
, 16,
277 PIPE_BUFFER_USAGE_CONSTANT
,
281 pipe_buffer_write(r
->pipe
->screen
, cbuf
->buffer
,
282 0, param_bytes
, params
);
284 r
->pipe
->set_constant_buffer(r
->pipe
, shader_type
, 0, cbuf
);
288 setup_vs_constant_buffer(struct xorg_renderer
*r
,
289 int width
, int height
)
291 const int param_bytes
= 8 * sizeof(float);
292 float vs_consts
[8] = {
293 2.f
/width
, 2.f
/height
, 1, 1,
296 renderer_set_constants(r
, PIPE_SHADER_VERTEX
,
297 vs_consts
, param_bytes
);
301 setup_fs_constant_buffer(struct xorg_renderer
*r
)
303 const int param_bytes
= 4 * sizeof(float);
304 const float fs_consts
[8] = {
307 renderer_set_constants(r
, PIPE_SHADER_FRAGMENT
,
308 fs_consts
, param_bytes
);
311 static INLINE
void shift_rectx(float coords
[4],
318 coords
[2] = MIN2(coords
[2], bounds
[2]);
319 /* bound x/y + width/height */
320 if ((coords
[0] + coords
[2]) > (bounds
[0] + bounds
[2])) {
321 coords
[2] = (bounds
[0] + bounds
[2]) - coords
[0];
326 static INLINE
void shift_recty(float coords
[4],
333 coords
[3] = MIN2(coords
[3], bounds
[3]);
334 if ((coords
[1] + coords
[3]) > (bounds
[1] + bounds
[3])) {
335 coords
[3] = (bounds
[1] + bounds
[3]) - coords
[1];
340 static INLINE
void bound_rect(float coords
[4],
341 const float bounds
[4],
344 /* if outside the bounds */
345 if (coords
[0] > (bounds
[0] + bounds
[2]) ||
346 coords
[1] > (bounds
[1] + bounds
[3]) ||
347 (coords
[0] + coords
[2]) < bounds
[0] ||
348 (coords
[1] + coords
[3]) < bounds
[1]) {
359 if (coords
[0] < bounds
[0]) {
360 shift
[0] = bounds
[0] - coords
[0];
361 coords
[2] -= shift
[0];
362 coords
[0] = bounds
[0];
367 if (coords
[1] < bounds
[1]) {
368 shift
[1] = bounds
[1] - coords
[1];
369 coords
[3] -= shift
[1];
370 coords
[1] = bounds
[1];
374 shift
[2] = bounds
[2] - coords
[2];
375 shift
[3] = bounds
[3] - coords
[3];
376 /* bound width/height */
377 coords
[2] = MIN2(coords
[2], bounds
[2]);
378 coords
[3] = MIN2(coords
[3], bounds
[3]);
380 /* bound x/y + width/height */
381 if ((coords
[0] + coords
[2]) > (bounds
[0] + bounds
[2])) {
382 coords
[2] = (bounds
[0] + bounds
[2]) - coords
[0];
384 if ((coords
[1] + coords
[3]) > (bounds
[1] + bounds
[3])) {
385 coords
[3] = (bounds
[1] + bounds
[3]) - coords
[1];
388 /* if outside the bounds */
389 if ((coords
[0] + coords
[2]) < bounds
[0] ||
390 (coords
[1] + coords
[3]) < bounds
[1]) {
399 static INLINE
void sync_size(float *src_loc
, float *dst_loc
)
401 src_loc
[2] = MIN2(src_loc
[2], dst_loc
[2]);
402 src_loc
[3] = MIN2(src_loc
[3], dst_loc
[3]);
403 dst_loc
[2] = src_loc
[2];
404 dst_loc
[3] = src_loc
[3];
407 static void renderer_copy_texture(struct xorg_renderer
*r
,
408 struct pipe_texture
*src
,
409 float sx1
, float sy1
,
410 float sx2
, float sy2
,
411 struct pipe_texture
*dst
,
412 float dx1
, float dy1
,
413 float dx2
, float dy2
)
415 struct pipe_context
*pipe
= r
->pipe
;
416 struct pipe_screen
*screen
= pipe
->screen
;
417 struct pipe_buffer
*buf
;
418 struct pipe_surface
*dst_surf
= screen
->get_tex_surface(
419 screen
, dst
, 0, 0, 0,
420 PIPE_BUFFER_USAGE_GPU_WRITE
);
421 struct pipe_framebuffer_state fb
;
422 float s0
, t0
, s1
, t1
;
423 struct xorg_shader shader
;
425 assert(src
->width
[0] != 0);
426 assert(src
->height
[0] != 0);
427 assert(dst
->width
[0] != 0);
428 assert(dst
->height
[0] != 0);
431 s0
= sx1
/ src
->width
[0];
432 s1
= sx2
/ src
->width
[0];
433 t0
= sy1
/ src
->height
[0];
434 t1
= sy2
/ src
->height
[0];
443 debug_printf("copy texture src=[%f, %f, %f, %f], dst=[%f, %f, %f, %f], tex=[%f, %f, %f, %f]\n",
444 sx1
, sy1
, sx2
, sy2
, dx1
, dy1
, dx2
, dy2
,
448 assert(screen
->is_format_supported(screen
, dst_surf
->format
,
450 PIPE_TEXTURE_USAGE_RENDER_TARGET
,
453 /* save state (restored below) */
454 cso_save_blend(r
->cso
);
455 cso_save_samplers(r
->cso
);
456 cso_save_sampler_textures(r
->cso
);
457 cso_save_framebuffer(r
->cso
);
458 cso_save_fragment_shader(r
->cso
);
459 cso_save_vertex_shader(r
->cso
);
461 cso_save_viewport(r
->cso
);
464 /* set misc state we care about */
466 struct pipe_blend_state blend
;
467 memset(&blend
, 0, sizeof(blend
));
468 blend
.rgb_src_factor
= PIPE_BLENDFACTOR_ONE
;
469 blend
.alpha_src_factor
= PIPE_BLENDFACTOR_ONE
;
470 blend
.rgb_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
471 blend
.alpha_dst_factor
= PIPE_BLENDFACTOR_ZERO
;
472 blend
.colormask
= PIPE_MASK_RGBA
;
473 cso_set_blend(r
->cso
, &blend
);
478 struct pipe_sampler_state sampler
;
479 memset(&sampler
, 0, sizeof(sampler
));
480 sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
481 sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
482 sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
483 sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
;
484 sampler
.min_img_filter
= PIPE_TEX_FILTER_NEAREST
;
485 sampler
.mag_img_filter
= PIPE_TEX_FILTER_NEAREST
;
486 sampler
.normalized_coords
= 1;
487 cso_single_sampler(r
->cso
, 0, &sampler
);
488 cso_single_sampler_done(r
->cso
);
491 set_viewport(r
, dst_surf
->width
, dst_surf
->height
, Y0_TOP
);
494 cso_set_sampler_textures(r
->cso
, 1, &src
);
496 renderer_bind_rasterizer(r
);
499 shader
= xorg_shaders_get(r
->shaders
,
502 cso_set_vertex_shader_handle(r
->cso
, shader
.vs
);
503 cso_set_fragment_shader_handle(r
->cso
, shader
.fs
);
506 memset(&fb
, 0, sizeof(fb
));
507 fb
.width
= dst_surf
->width
;
508 fb
.height
= dst_surf
->height
;
510 fb
.cbufs
[0] = dst_surf
;
513 for (i
= 1; i
< PIPE_MAX_COLOR_BUFS
; ++i
)
516 cso_set_framebuffer(r
->cso
, &fb
);
517 setup_vs_constant_buffer(r
, fb
.width
, fb
.height
);
518 setup_fs_constant_buffer(r
);
521 buf
= setup_vertex_data_tex(r
,
528 util_draw_vertex_buffer(r
->pipe
, buf
, 0,
529 PIPE_PRIM_TRIANGLE_FAN
,
531 2); /* attribs/vert */
533 pipe_buffer_reference(&buf
, NULL
);
536 /* restore state we changed */
537 cso_restore_blend(r
->cso
);
538 cso_restore_samplers(r
->cso
);
539 cso_restore_sampler_textures(r
->cso
);
540 cso_restore_framebuffer(r
->cso
);
541 cso_restore_vertex_shader(r
->cso
);
542 cso_restore_fragment_shader(r
->cso
);
543 cso_restore_viewport(r
->cso
);
545 pipe_surface_reference(&dst_surf
, NULL
);
548 static struct pipe_texture
*
549 create_sampler_texture(struct xorg_renderer
*r
,
550 struct pipe_texture
*src
)
552 enum pipe_format format
;
553 struct pipe_context
*pipe
= r
->pipe
;
554 struct pipe_screen
*screen
= pipe
->screen
;
555 struct pipe_texture
*pt
;
556 struct pipe_texture templ
;
558 pipe
->flush(pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
560 /* the coming in texture should already have that invariance */
561 debug_assert(screen
->is_format_supported(screen
, src
->format
,
563 PIPE_TEXTURE_USAGE_SAMPLER
, 0));
565 format
= src
->format
;
567 memset(&templ
, 0, sizeof(templ
));
568 templ
.target
= PIPE_TEXTURE_2D
;
569 templ
.format
= format
;
570 templ
.last_level
= 0;
571 templ
.width
[0] = src
->width
[0];
572 templ
.height
[0] = src
->height
[0];
574 pf_get_block(format
, &templ
.block
);
575 templ
.tex_usage
= PIPE_TEXTURE_USAGE_SAMPLER
;
577 pt
= screen
->texture_create(screen
, &templ
);
579 debug_assert(!pt
|| pipe_is_referenced(&pt
->reference
));
585 /* copy source framebuffer surface into texture */
586 struct pipe_surface
*ps_read
= screen
->get_tex_surface(
587 screen
, src
, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ
);
588 struct pipe_surface
*ps_tex
= screen
->get_tex_surface(
589 screen
, pt
, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE
);
590 if (pipe
->surface_copy
) {
591 pipe
->surface_copy(pipe
,
595 0, 0, src
->width
[0], src
->height
[0]);
597 util_surface_copy(pipe
, FALSE
,
601 0, 0, src
->width
[0], src
->height
[0]);
603 pipe_surface_reference(&ps_read
, NULL
);
604 pipe_surface_reference(&ps_tex
, NULL
);
611 void renderer_copy_pixmap(struct xorg_renderer
*r
,
612 struct exa_pixmap_priv
*dst_priv
, int dx
, int dy
,
613 struct exa_pixmap_priv
*src_priv
, int sx
, int sy
,
614 int width
, int height
)
616 float dst_loc
[4], src_loc
[4];
617 float dst_bounds
[4], src_bounds
[4];
618 float src_shift
[4], dst_shift
[4], shift
[4];
619 struct pipe_texture
*dst
= dst_priv
->tex
;
620 struct pipe_texture
*src
= src_priv
->tex
;
622 if (r
->pipe
->is_texture_referenced(r
->pipe
, src
, 0, 0) &
623 PIPE_REFERENCED_FOR_WRITE
)
624 r
->pipe
->flush(r
->pipe
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
632 dst_bounds
[2] = dst
->width
[0];
633 dst_bounds
[3] = dst
->height
[0];
641 src_bounds
[2] = src
->width
[0];
642 src_bounds
[3] = src
->height
[0];
644 bound_rect(src_loc
, src_bounds
, src_shift
);
645 bound_rect(dst_loc
, dst_bounds
, dst_shift
);
646 shift
[0] = src_shift
[0] - dst_shift
[0];
647 shift
[1] = src_shift
[1] - dst_shift
[1];
650 shift_rectx(src_loc
, src_bounds
, -shift
[0]);
652 shift_rectx(dst_loc
, dst_bounds
, shift
[0]);
655 shift_recty(src_loc
, src_bounds
, -shift
[1]);
657 shift_recty(dst_loc
, dst_bounds
, shift
[1]);
659 sync_size(src_loc
, dst_loc
);
661 if (src_loc
[2] >= 0 && src_loc
[3] >= 0 &&
662 dst_loc
[2] >= 0 && dst_loc
[3] >= 0) {
663 struct pipe_texture
*temp_src
= src
;
666 temp_src
= create_sampler_texture(r
, src
);
668 renderer_copy_texture(r
,
672 src_loc
[0] + src_loc
[2],
673 src_loc
[1] + src_loc
[3],
677 dst_loc
[0] + dst_loc
[2],
678 dst_loc
[1] + dst_loc
[3]);
681 pipe_texture_reference(&temp_src
, NULL
);
685 void renderer_draw_solid_rect(struct xorg_renderer
*r
,
690 struct pipe_context
*pipe
= r
->pipe
;
691 struct pipe_buffer
*buf
= 0;
694 debug_printf("solid rect[(%d, %d), (%d, %d)], rgba[%f, %f, %f, %f]\n",
695 x0, y0, x1, y1, color[0], color[1], color[2], color[3]);*/
697 setup_vertex0(r
->vertices2
[0], x0
, y0
, color
);
699 setup_vertex0(r
->vertices2
[1], x1
, y0
, color
);
701 setup_vertex0(r
->vertices2
[2], x1
, y1
, color
);
703 setup_vertex0(r
->vertices2
[3], x0
, y1
, color
);
705 buf
= pipe_user_buffer_create(pipe
->screen
,
707 sizeof(r
->vertices2
));
711 util_draw_vertex_buffer(pipe
, buf
, 0,
712 PIPE_PRIM_TRIANGLE_FAN
,
714 2); /* attribs/vert */
716 pipe_buffer_reference(&buf
, NULL
);
720 void renderer_draw_textures(struct xorg_renderer
*r
,
722 int width
, int height
,
723 struct pipe_texture
**textures
,
726 struct pipe_context
*pipe
= r
->pipe
;
727 struct pipe_buffer
*buf
= 0;
729 switch(num_textures
) {
731 buf
= setup_vertex_data1(r
,
732 pos
[0], pos
[1], /* src */
733 pos
[4], pos
[5], /* dst */
738 buf
= setup_vertex_data2(r
,
739 pos
[0], pos
[1], /* src */
740 pos
[2], pos
[3], /* mask */
741 pos
[4], pos
[5], /* dst */
743 textures
[0], textures
[1]);
746 debug_assert(!"Unsupported number of textures");
751 int num_attribs
= 1; /*pos*/
752 num_attribs
+= num_textures
;
754 util_draw_vertex_buffer(pipe
, buf
, 0,
755 PIPE_PRIM_TRIANGLE_FAN
,
757 num_attribs
); /* attribs/vert */
759 pipe_buffer_reference(&buf
, NULL
);