c708ac317029443f1faf269d15ca6eece1121a23
[mesa.git] / src / gallium / state_trackers / xorg / xorg_composite.c
1 #include "xorg_composite.h"
2
3 #include "xorg_exa_tgsi.h"
4
5 #include "cso_cache/cso_context.h"
6 #include "util/u_draw_quad.h"
7
8 #include "pipe/p_inlines.h"
9
10 struct xorg_composite_blend {
11 int op:8;
12
13 unsigned rgb_src_factor:5; /**< PIPE_BLENDFACTOR_x */
14 unsigned rgb_dst_factor:5; /**< PIPE_BLENDFACTOR_x */
15
16 unsigned alpha_src_factor:5; /**< PIPE_BLENDFACTOR_x */
17 unsigned alpha_dst_factor:5; /**< PIPE_BLENDFACTOR_x */
18 };
19
20 #define BLEND_OP_OVER 3
21 static const struct xorg_composite_blend xorg_blends[] = {
22 { PictOpClear,
23 PIPE_BLENDFACTOR_CONST_COLOR, PIPE_BLENDFACTOR_CONST_ALPHA,
24 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
25
26 { PictOpSrc,
27 PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE,
28 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
29
30 { PictOpDst,
31 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO,
32 PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE },
33
34 { PictOpOver,
35 PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE,
36 PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
37
38 { PictOpOverReverse,
39 PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE,
40 PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
41 };
42
43 static INLINE void
44 pixel_to_float4(PictFormatPtr format,
45 CARD32 pixel, float *color)
46 {
47 CARD32 r, g, b, a;
48
49 debug_assert(format->type == PictTypeDirect);
50
51 r = (pixel >> format->direct.red) & format->direct.redMask;
52 g = (pixel >> format->direct.green) & format->direct.greenMask;
53 b = (pixel >> format->direct.blue) & format->direct.blueMask;
54 a = (pixel >> format->direct.alpha) & format->direct.alphaMask;
55 color[0] = ((float)r) / ((float)format->direct.redMask);
56 color[1] = ((float)g) / ((float)format->direct.greenMask);
57 color[2] = ((float)b) / ((float)format->direct.blueMask);
58 color[3] = ((float)a) / ((float)format->direct.alphaMask);
59 }
60
61 struct acceleration_info {
62 int op : 16;
63 int with_mask : 1;
64 int component_alpha : 1;
65 };
66 static const struct acceleration_info accelerated_ops[] = {
67 {PictOpClear, 1, 0},
68 {PictOpSrc, 1, 0},
69 {PictOpDst, 1, 0},
70 {PictOpOver, 1, 0},
71 {PictOpOverReverse, 1, 0},
72 {PictOpIn, 1, 0},
73 {PictOpInReverse, 1, 0},
74 {PictOpOut, 1, 0},
75 {PictOpOutReverse, 1, 0},
76 {PictOpAtop, 1, 0},
77 {PictOpAtopReverse, 1, 0},
78 {PictOpXor, 1, 0},
79 {PictOpAdd, 1, 0},
80 {PictOpSaturate, 1, 0},
81 };
82
83 static struct xorg_composite_blend
84 blend_for_op(int op)
85 {
86 const int num_blends =
87 sizeof(xorg_blends)/sizeof(struct xorg_composite_blend);
88 int i;
89
90 for (i = 0; i < num_blends; ++i) {
91 if (xorg_blends[i].op == op)
92 return xorg_blends[i];
93 }
94 return xorg_blends[BLEND_OP_OVER];
95 }
96
97 static INLINE int
98 render_repeat_to_gallium(int mode)
99 {
100 switch(mode) {
101 case RepeatNone:
102 return PIPE_TEX_WRAP_CLAMP;
103 case RepeatNormal:
104 return PIPE_TEX_WRAP_REPEAT;
105 case RepeatReflect:
106 return PIPE_TEX_WRAP_MIRROR_REPEAT;
107 case RepeatPad:
108 return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
109 default:
110 debug_printf("Unsupported repeat mode\n");
111 }
112 return PIPE_TEX_WRAP_REPEAT;
113 }
114
115
116 static INLINE void
117 setup_vertex0(float vertex[2][4], float x, float y,
118 float color[4])
119 {
120 vertex[0][0] = x;
121 vertex[0][1] = y;
122 vertex[0][2] = 0.f; /*z*/
123 vertex[0][3] = 1.f; /*w*/
124
125 vertex[1][0] = color[0]; /*r*/
126 vertex[1][1] = color[1]; /*g*/
127 vertex[1][2] = color[2]; /*b*/
128 vertex[1][3] = color[3]; /*a*/
129 }
130
131 static struct pipe_buffer *
132 setup_vertex_data0(struct exa_context *ctx,
133 int srcX, int srcY, int maskX, int maskY,
134 int dstX, int dstY, int width, int height)
135 {
136 float vertices[4][2][4];
137
138 /* 1st vertex */
139 setup_vertex0(vertices[0], dstX, dstY,
140 ctx->solid_color);
141 /* 2nd vertex */
142 setup_vertex0(vertices[1], dstX + width, dstY,
143 ctx->solid_color);
144 /* 3rd vertex */
145 setup_vertex0(vertices[2], dstX + width, dstY + height,
146 ctx->solid_color);
147 /* 4th vertex */
148 setup_vertex0(vertices[3], dstX, dstY + height,
149 ctx->solid_color);
150
151 return pipe_user_buffer_create(ctx->ctx->screen,
152 vertices,
153 sizeof(vertices));
154 }
155
156 static INLINE void
157 setup_vertex1(float vertex[2][4], float x, float y, float s, float t)
158 {
159 vertex[0][0] = x;
160 vertex[0][1] = y;
161 vertex[0][2] = 0.f; /*z*/
162 vertex[0][3] = 1.f; /*w*/
163
164 vertex[1][0] = s; /*s*/
165 vertex[1][1] = t; /*t*/
166 vertex[1][2] = 0.f; /*r*/
167 vertex[1][3] = 1.f; /*q*/
168 }
169
170 static struct pipe_buffer *
171 setup_vertex_data1(struct exa_context *ctx,
172 int srcX, int srcY, int maskX, int maskY,
173 int dstX, int dstY, int width, int height)
174 {
175 float vertices[4][2][4];
176 float s0, t0, s1, t1;
177 struct pipe_texture *src = ctx->bound_textures[0];
178
179 s0 = srcX / src->width[0];
180 s1 = srcX + width / src->width[0];
181 t0 = srcY / src->height[0];
182 t1 = srcY + height / src->height[0];
183
184 /* 1st vertex */
185 setup_vertex1(vertices[0], dstX, dstY,
186 s0, t0);
187 /* 2nd vertex */
188 setup_vertex1(vertices[1], dstX + width, dstY,
189 s1, t0);
190 /* 3rd vertex */
191 setup_vertex1(vertices[2], dstX + width, dstY + height,
192 s1, t1);
193 /* 4th vertex */
194 setup_vertex1(vertices[3], dstX, dstY + height,
195 s0, t1);
196
197 return pipe_user_buffer_create(ctx->ctx->screen,
198 vertices,
199 sizeof(vertices));
200 }
201
202
203 static INLINE void
204 setup_vertex2(float vertex[3][4], float x, float y,
205 float s0, float t0, float s1, float t1)
206 {
207 vertex[0][0] = x;
208 vertex[0][1] = y;
209 vertex[0][2] = 0.f; /*z*/
210 vertex[0][3] = 1.f; /*w*/
211
212 vertex[1][0] = s0; /*s*/
213 vertex[1][1] = t0; /*t*/
214 vertex[1][2] = 0.f; /*r*/
215 vertex[1][3] = 1.f; /*q*/
216
217 vertex[2][0] = s1; /*s*/
218 vertex[2][1] = t1; /*t*/
219 vertex[2][2] = 0.f; /*r*/
220 vertex[2][3] = 1.f; /*q*/
221 }
222
223 static struct pipe_buffer *
224 setup_vertex_data2(struct exa_context *ctx,
225 int srcX, int srcY, int maskX, int maskY,
226 int dstX, int dstY, int width, int height)
227 {
228 float vertices[4][3][4];
229 float st0[4], st1[4];
230 struct pipe_texture *src = ctx->bound_textures[0];
231 struct pipe_texture *mask = ctx->bound_textures[0];
232
233 st0[0] = srcX / src->width[0];
234 st0[1] = srcY / src->height[0];
235 st0[2] = srcX + width / src->width[0];
236 st0[3] = srcY + height / src->height[0];
237
238 st1[0] = maskX / mask->width[0];
239 st1[1] = maskY / mask->height[0];
240 st1[2] = maskX + width / mask->width[0];
241 st1[3] = maskY + height / mask->height[0];
242
243 /* 1st vertex */
244 setup_vertex2(vertices[0], dstX, dstY,
245 st0[0], st0[1], st1[0], st1[1]);
246 /* 2nd vertex */
247 setup_vertex2(vertices[1], dstX + width, dstY,
248 st0[2], st0[1], st1[2], st1[1]);
249 /* 3rd vertex */
250 setup_vertex2(vertices[2], dstX + width, dstY + height,
251 st0[2], st0[3], st1[2], st1[3]);
252 /* 4th vertex */
253 setup_vertex2(vertices[3], dstX, dstY + height,
254 st0[0], st0[3], st1[0], st1[3]);
255
256 return pipe_user_buffer_create(ctx->ctx->screen,
257 vertices,
258 sizeof(vertices));
259 }
260
261 boolean xorg_composite_accelerated(int op,
262 PicturePtr pSrcPicture,
263 PicturePtr pMaskPicture,
264 PicturePtr pDstPicture)
265 {
266 unsigned i;
267 unsigned accel_ops_count =
268 sizeof(accelerated_ops)/sizeof(struct acceleration_info);
269
270
271 /*FIXME: currently accel is disabled */
272 return FALSE;
273
274 if (pSrcPicture) {
275 /* component alpha not supported */
276 if (pSrcPicture->componentAlpha)
277 return FALSE;
278 /* fills not supported */
279 if (pSrcPicture->pSourcePict)
280 return FALSE;
281 }
282
283 for (i = 0; i < accel_ops_count; ++i) {
284 if (op == accelerated_ops[i].op) {
285 if (pMaskPicture && !accelerated_ops[i].with_mask)
286 return FALSE;
287 return TRUE;
288 }
289 }
290 return FALSE;
291 }
292
293 static void
294 bind_framebuffer_state(struct exa_context *exa, PicturePtr pDstPicture,
295 struct exa_pixmap_priv *pDst)
296 {
297 unsigned i;
298 struct pipe_framebuffer_state state;
299 struct pipe_surface *surface = exa_gpu_surface(exa, pDst);
300 memset(&state, 0, sizeof(struct pipe_framebuffer_state));
301
302 state.width = pDstPicture->pDrawable->width;
303 state.height = pDstPicture->pDrawable->height;
304
305 state.nr_cbufs = 1;
306 state.cbufs[0] = surface;
307 for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
308 state.cbufs[i] = 0;
309
310 /* currently we don't use depth/stencil */
311 state.zsbuf = 0;
312
313 cso_set_framebuffer(exa->cso, &state);
314 }
315
316 enum AxisOrientation {
317 Y0_BOTTOM,
318 Y0_TOP
319 };
320
321 static void
322 set_viewport(struct exa_context *exa, int width, int height,
323 enum AxisOrientation orientation)
324 {
325 struct pipe_viewport_state viewport;
326 float y_scale = (orientation == Y0_BOTTOM) ? -2.f : 2.f;
327
328 viewport.scale[0] = width / 2.f;
329 viewport.scale[1] = height / y_scale;
330 viewport.scale[2] = 1.0;
331 viewport.scale[3] = 1.0;
332 viewport.translate[0] = width / 2.f;
333 viewport.translate[1] = height / 2.f;
334 viewport.translate[2] = 0.0;
335 viewport.translate[3] = 0.0;
336
337 cso_set_viewport(exa->cso, &viewport);
338 }
339
340 static void
341 bind_viewport_state(struct exa_context *exa, PicturePtr pDstPicture)
342 {
343 int width = pDstPicture->pDrawable->width;
344 int height = pDstPicture->pDrawable->height;
345
346 set_viewport(exa, width, height, Y0_TOP);
347 }
348
349 static void
350 bind_blend_state(struct exa_context *exa, int op,
351 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
352 {
353 boolean component_alpha = pSrcPicture->componentAlpha;
354 struct xorg_composite_blend blend_opt;
355 struct pipe_blend_state blend;
356
357 if (component_alpha) {
358 op = PictOpOver;
359 }
360 blend_opt = blend_for_op(op);
361
362 memset(&blend, 0, sizeof(struct pipe_blend_state));
363 blend.blend_enable = 1;
364 blend.colormask |= PIPE_MASK_R;
365 blend.colormask |= PIPE_MASK_G;
366 blend.colormask |= PIPE_MASK_B;
367 blend.colormask |= PIPE_MASK_A;
368
369 blend.rgb_src_factor = blend_opt.rgb_src_factor;
370 blend.alpha_src_factor = blend_opt.alpha_src_factor;
371 blend.rgb_dst_factor = blend_opt.rgb_dst_factor;
372 blend.alpha_dst_factor = blend_opt.alpha_dst_factor;
373
374 cso_set_blend(exa->cso, &blend);
375 }
376
377 static void
378 bind_rasterizer_state(struct exa_context *exa)
379 {
380 struct pipe_rasterizer_state raster;
381 memset(&raster, 0, sizeof(struct pipe_rasterizer_state));
382 raster.gl_rasterization_rules = 1;
383 cso_set_rasterizer(exa->cso, &raster);
384 }
385
386 static void
387 bind_shaders(struct exa_context *exa, int op,
388 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
389 {
390 unsigned vs_traits = 0, fs_traits = 0;
391 struct xorg_shader shader;
392
393 if (pSrcPicture) {
394 if (pSrcPicture->pSourcePict) {
395 if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
396 fs_traits |= FS_SOLID_FILL;
397 vs_traits |= VS_SOLID_FILL;
398 pixel_to_float4(pSrcPicture->pFormat,
399 pSrcPicture->pSourcePict->solidFill.color,
400 exa->solid_color);
401 } else {
402 debug_assert("!gradients not supported");
403 }
404 } else {
405 fs_traits |= FS_COMPOSITE;
406 vs_traits |= VS_COMPOSITE;
407 }
408 }
409
410 if (pMaskPicture) {
411 vs_traits |= VS_MASK;
412 fs_traits |= FS_MASK;
413 }
414
415 shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits);
416 cso_set_vertex_shader_handle(exa->cso, shader.vs);
417 cso_set_fragment_shader_handle(exa->cso, shader.fs);
418 }
419
420
421 static void
422 bind_samplers(struct exa_context *exa, int op,
423 PicturePtr pSrcPicture, PicturePtr pMaskPicture,
424 PicturePtr pDstPicture,
425 struct exa_pixmap_priv *pSrc,
426 struct exa_pixmap_priv *pMask,
427 struct exa_pixmap_priv *pDst)
428 {
429 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
430 struct pipe_sampler_state src_sampler, mask_sampler;
431
432 exa->num_bound_samplers = 0;
433
434 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
435 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
436
437 if (pSrcPicture && pSrc) {
438 unsigned src_wrap = render_repeat_to_gallium(
439 pSrcPicture->repeatType);
440 src_sampler.wrap_s = src_wrap;
441 src_sampler.wrap_t = src_wrap;
442 src_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
443 src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
444 src_sampler.normalized_coords = 1;
445 samplers[0] = &src_sampler;
446 exa->bound_textures[0] = pSrc->tex;
447 ++exa->num_bound_samplers;
448 }
449
450 if (pMaskPicture && pMask) {
451 unsigned mask_wrap = render_repeat_to_gallium(
452 pMaskPicture->repeatType);
453 mask_sampler.wrap_s = mask_wrap;
454 mask_sampler.wrap_t = mask_wrap;
455 mask_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
456 mask_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
457 mask_sampler.normalized_coords = 1;
458 samplers[1] = &mask_sampler;
459 exa->bound_textures[1] = pMask->tex;
460 ++exa->num_bound_samplers;
461 }
462
463 cso_set_samplers(exa->cso, exa->num_bound_samplers,
464 (const struct pipe_sampler_state **)samplers);
465 cso_set_sampler_textures(exa->cso, exa->num_bound_samplers,
466 exa->bound_textures);
467 }
468
469 static void
470 setup_vs_constant_buffer(struct exa_context *exa,
471 int width, int height)
472 {
473 const int param_bytes = 8 * sizeof(float);
474 float vs_consts[8] = {
475 2.f/width, 2.f/height, 1, 1,
476 -1, -1, 0, 0
477 };
478 struct pipe_constant_buffer *cbuf = &exa->vs_const_buffer;
479
480 pipe_buffer_reference(&cbuf->buffer, NULL);
481 cbuf->buffer = pipe_buffer_create(exa->ctx->screen, 16,
482 PIPE_BUFFER_USAGE_CONSTANT,
483 param_bytes);
484
485 if (cbuf->buffer) {
486 pipe_buffer_write(exa->ctx->screen, cbuf->buffer,
487 0, param_bytes, vs_consts);
488 }
489 exa->ctx->set_constant_buffer(exa->ctx, PIPE_SHADER_VERTEX, 0, cbuf);
490 }
491
492
493 static void
494 setup_fs_constant_buffer(struct exa_context *exa)
495 {
496 const int param_bytes = 4 * sizeof(float);
497 float fs_consts[8] = {
498 0, 0, 0, 1,
499 };
500 struct pipe_constant_buffer *cbuf = &exa->fs_const_buffer;
501
502 pipe_buffer_reference(&cbuf->buffer, NULL);
503 cbuf->buffer = pipe_buffer_create(exa->ctx->screen, 16,
504 PIPE_BUFFER_USAGE_CONSTANT,
505 param_bytes);
506
507 if (cbuf->buffer) {
508 pipe_buffer_write(exa->ctx->screen, cbuf->buffer,
509 0, param_bytes, fs_consts);
510 }
511 exa->ctx->set_constant_buffer(exa->ctx, PIPE_SHADER_FRAGMENT, 0, cbuf);
512 }
513
514 static void
515 setup_constant_buffers(struct exa_context *exa, PicturePtr pDstPicture)
516 {
517 int width = pDstPicture->pDrawable->width;
518 int height = pDstPicture->pDrawable->height;
519
520 setup_vs_constant_buffer(exa, width, height);
521 setup_fs_constant_buffer(exa);
522 }
523
524 boolean xorg_composite_bind_state(struct exa_context *exa,
525 int op,
526 PicturePtr pSrcPicture,
527 PicturePtr pMaskPicture,
528 PicturePtr pDstPicture,
529 struct exa_pixmap_priv *pSrc,
530 struct exa_pixmap_priv *pMask,
531 struct exa_pixmap_priv *pDst)
532 {
533 bind_framebuffer_state(exa, pDstPicture, pDst);
534 bind_viewport_state(exa, pDstPicture);
535 bind_blend_state(exa, op, pSrcPicture, pMaskPicture);
536 bind_rasterizer_state(exa);
537 bind_shaders(exa, op, pSrcPicture, pMaskPicture);
538 bind_samplers(exa, op, pSrcPicture, pMaskPicture,
539 pDstPicture, pSrc, pMask, pDst);
540
541 setup_constant_buffers(exa, pDstPicture);
542
543 return FALSE;
544 }
545
546 void xorg_composite(struct exa_context *exa,
547 struct exa_pixmap_priv *dst,
548 int srcX, int srcY, int maskX, int maskY,
549 int dstX, int dstY, int width, int height)
550 {
551 struct pipe_context *pipe = exa->ctx;
552 struct pipe_buffer *buf = 0;
553
554 if (exa->num_bound_samplers == 0 ) { /* solid fill */
555 buf = setup_vertex_data0(exa,
556 srcX, srcY, maskX, maskY,
557 dstX, dstY, width, height);
558 } else if (exa->num_bound_samplers == 1 ) /* src */
559 buf = setup_vertex_data1(exa,
560 srcX, srcY, maskX, maskY,
561 dstX, dstY, width, height);
562 else if (exa->num_bound_samplers == 2) /* src + mask */
563 buf = setup_vertex_data2(exa,
564 srcX, srcY, maskX, maskY,
565 dstX, dstY, width, height);
566 else if (exa->num_bound_samplers == 3) { /* src + mask + dst */
567 debug_assert(!"src/mask/dst not handled right now");
568 #if 0
569 buf = setup_vertex_data2(exa,
570 srcX, srcY, maskX, maskY,
571 dstX, dstY, width, height);
572 #endif
573 }
574
575 if (buf) {
576 util_draw_vertex_buffer(pipe, buf, 0,
577 PIPE_PRIM_TRIANGLE_FAN,
578 4, /* verts */
579 1 + exa->num_bound_samplers); /* attribs/vert */
580
581 pipe_buffer_reference(&buf, NULL);
582 }
583 }
584