st/xorg: implement basic src/mask transformations
[mesa.git] / src / gallium / state_trackers / xorg / xorg_composite.c
1 #include "xorg_composite.h"
2
3 #include "xorg_renderer.h"
4 #include "xorg_exa_tgsi.h"
5
6 #include "cso_cache/cso_context.h"
7 #include "util/u_draw_quad.h"
8 #include "util/u_math.h"
9
10 #include "pipe/p_inlines.h"
11
12 /*XXX also in Xrender.h but the including it here breaks compilition */
13 #define XFixedToDouble(f) (((double) (f)) / 65536.)
14
15 struct xorg_composite_blend {
16 int op:8;
17
18 unsigned rgb_src_factor:5; /**< PIPE_BLENDFACTOR_x */
19 unsigned alpha_src_factor:5; /**< PIPE_BLENDFACTOR_x */
20
21 unsigned rgb_dst_factor:5; /**< PIPE_BLENDFACTOR_x */
22 unsigned alpha_dst_factor:5; /**< PIPE_BLENDFACTOR_x */
23 };
24
25 #define BLEND_OP_OVER 3
26 static const struct xorg_composite_blend xorg_blends[] = {
27 { PictOpClear,
28 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO,
29 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
30
31 { PictOpSrc,
32 PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE,
33 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO },
34
35 { PictOpDst,
36 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO,
37 PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE },
38
39 { PictOpOver,
40 PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE,
41 PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
42
43 { PictOpOverReverse,
44 PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
45 PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
46
47 { PictOpIn,
48 PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
49 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
50
51 { PictOpInReverse,
52 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE,
53 PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE },
54
55 { PictOpOut,
56 PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
57 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
58
59 { PictOpOutReverse,
60 PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE,
61 PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
62
63 { PictOpAtop,
64 PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
65 PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
66
67 { PictOpAtopReverse,
68 PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
69 PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA },
70
71 { PictOpXor,
72 PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE,
73 PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_ONE },
74
75 { PictOpAdd,
76 PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE,
77 PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE },
78 };
79
80
81 static INLINE void
82 pixel_to_float4(Pixel pixel, float *color)
83 {
84 CARD32 r, g, b, a;
85
86 a = (pixel >> 24) & 0xff;
87 r = (pixel >> 16) & 0xff;
88 g = (pixel >> 8) & 0xff;
89 b = (pixel >> 0) & 0xff;
90 color[0] = ((float)r) / 255.;
91 color[1] = ((float)g) / 255.;
92 color[2] = ((float)b) / 255.;
93 color[3] = ((float)a) / 255.;
94 }
95
96 struct acceleration_info {
97 int op : 16;
98 int with_mask : 1;
99 int component_alpha : 1;
100 };
101 static const struct acceleration_info accelerated_ops[] = {
102 {PictOpClear, 1, 0},
103 {PictOpSrc, 1, 0},
104 {PictOpDst, 1, 0},
105 {PictOpOver, 1, 0},
106 {PictOpOverReverse, 1, 0},
107 {PictOpIn, 1, 0},
108 {PictOpInReverse, 1, 0},
109 {PictOpOut, 1, 0},
110 {PictOpOutReverse, 1, 0},
111 {PictOpAtop, 1, 0},
112 {PictOpAtopReverse, 1, 0},
113 {PictOpXor, 1, 0},
114 {PictOpAdd, 1, 0},
115 {PictOpSaturate, 1, 0},
116 };
117
118 static struct xorg_composite_blend
119 blend_for_op(int op)
120 {
121 const int num_blends =
122 sizeof(xorg_blends)/sizeof(struct xorg_composite_blend);
123 int i;
124
125 for (i = 0; i < num_blends; ++i) {
126 if (xorg_blends[i].op == op)
127 return xorg_blends[i];
128 }
129 return xorg_blends[BLEND_OP_OVER];
130 }
131
132 static INLINE int
133 render_repeat_to_gallium(int mode)
134 {
135 switch(mode) {
136 case RepeatNone:
137 return PIPE_TEX_WRAP_CLAMP;
138 case RepeatNormal:
139 return PIPE_TEX_WRAP_REPEAT;
140 case RepeatReflect:
141 return PIPE_TEX_WRAP_MIRROR_REPEAT;
142 case RepeatPad:
143 return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
144 default:
145 debug_printf("Unsupported repeat mode\n");
146 }
147 return PIPE_TEX_WRAP_REPEAT;
148 }
149
150 static INLINE boolean
151 render_filter_to_gallium(int xrender_filter, int *out_filter)
152 {
153
154 switch (xrender_filter) {
155 case PictFilterNearest:
156 *out_filter = PIPE_TEX_FILTER_NEAREST;
157 break;
158 case PictFilterBilinear:
159 *out_filter = PIPE_TEX_FILTER_LINEAR;
160 break;
161 case PictFilterFast:
162 *out_filter = PIPE_TEX_FILTER_NEAREST;
163 break;
164 case PictFilterGood:
165 *out_filter = PIPE_TEX_FILTER_LINEAR;
166 break;
167 case PictFilterBest:
168 *out_filter = PIPE_TEX_FILTER_LINEAR;
169 break;
170 default:
171 debug_printf("Unkown xrender filter");
172 *out_filter = PIPE_TEX_FILTER_NEAREST;
173 return FALSE;
174 }
175
176 return TRUE;
177 }
178
179 static boolean is_filter_accelerated(PicturePtr pic)
180 {
181 int filter;
182 if (pic && !render_filter_to_gallium(pic->filter, &filter))
183 return FALSE;
184 return TRUE;
185 }
186
187 boolean xorg_composite_accelerated(int op,
188 PicturePtr pSrcPicture,
189 PicturePtr pMaskPicture,
190 PicturePtr pDstPicture)
191 {
192 ScreenPtr pScreen = pDstPicture->pDrawable->pScreen;
193 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
194 modesettingPtr ms = modesettingPTR(pScrn);
195 unsigned i;
196 unsigned accel_ops_count =
197 sizeof(accelerated_ops)/sizeof(struct acceleration_info);
198
199 if (!is_filter_accelerated(pSrcPicture) ||
200 !is_filter_accelerated(pMaskPicture)) {
201 XORG_FALLBACK("Unsupported Xrender filter");
202 }
203
204 if (pSrcPicture->pSourcePict) {
205 if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill)
206 XORG_FALLBACK("gradients not enabled (haven't been well tested)");
207 }
208
209 for (i = 0; i < accel_ops_count; ++i) {
210 if (op == accelerated_ops[i].op) {
211 /* Check for component alpha */
212 if (pMaskPicture &&
213 (pMaskPicture->componentAlpha ||
214 (!accelerated_ops[i].with_mask)))
215 XORG_FALLBACK("component alpha unsupported (PictOpOver=%s(%d)",
216 (accelerated_ops[i].op == PictOpOver) ? "yes" : "no",
217 accelerated_ops[i].op);
218 return TRUE;
219 }
220 }
221 XORG_FALLBACK("unsupported operation");
222 }
223
224 static void
225 bind_blend_state(struct exa_context *exa, int op,
226 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
227 {
228 struct xorg_composite_blend blend_opt;
229 struct pipe_blend_state blend;
230
231 blend_opt = blend_for_op(op);
232
233 memset(&blend, 0, sizeof(struct pipe_blend_state));
234 blend.blend_enable = 1;
235 blend.colormask |= PIPE_MASK_RGBA;
236
237 blend.rgb_src_factor = blend_opt.rgb_src_factor;
238 blend.alpha_src_factor = blend_opt.alpha_src_factor;
239 blend.rgb_dst_factor = blend_opt.rgb_dst_factor;
240 blend.alpha_dst_factor = blend_opt.alpha_dst_factor;
241
242 cso_set_blend(exa->renderer->cso, &blend);
243 }
244
245
246 static void
247 bind_shaders(struct exa_context *exa, int op,
248 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
249 {
250 unsigned vs_traits = 0, fs_traits = 0;
251 struct xorg_shader shader;
252
253 exa->has_solid_color = FALSE;
254
255 if (pSrcPicture) {
256 if (pSrcPicture->pSourcePict) {
257 if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
258 fs_traits |= FS_SOLID_FILL;
259 vs_traits |= VS_SOLID_FILL;
260 debug_assert(pSrcPicture->format == PICT_a8r8g8b8);
261 pixel_to_float4(pSrcPicture->pSourcePict->solidFill.color,
262 exa->solid_color);
263 exa->has_solid_color = TRUE;
264 } else {
265 debug_assert("!gradients not supported");
266 }
267 } else {
268 fs_traits |= FS_COMPOSITE;
269 vs_traits |= VS_COMPOSITE;
270 }
271 }
272
273 if (pMaskPicture) {
274 vs_traits |= VS_MASK;
275 fs_traits |= FS_MASK;
276 }
277
278 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
279 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
280 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
281 }
282
283 static void
284 bind_samplers(struct exa_context *exa, int op,
285 PicturePtr pSrcPicture, PicturePtr pMaskPicture,
286 PicturePtr pDstPicture,
287 struct exa_pixmap_priv *pSrc,
288 struct exa_pixmap_priv *pMask,
289 struct exa_pixmap_priv *pDst)
290 {
291 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
292 struct pipe_sampler_state src_sampler, mask_sampler;
293
294 exa->num_bound_samplers = 0;
295
296 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
297 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
298
299 if ((pSrc && exa->pipe->is_texture_referenced(exa->pipe, pSrc->tex, 0, 0) &
300 PIPE_REFERENCED_FOR_WRITE) ||
301 (pMask && exa->pipe->is_texture_referenced(exa->pipe, pMask->tex, 0, 0) &
302 PIPE_REFERENCED_FOR_WRITE))
303 exa->pipe->flush(exa->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
304
305 if (pSrcPicture && pSrc) {
306 unsigned src_wrap = render_repeat_to_gallium(
307 pSrcPicture->repeatType);
308 int filter;
309
310 render_filter_to_gallium(pSrcPicture->filter, &filter);
311
312 src_sampler.wrap_s = src_wrap;
313 src_sampler.wrap_t = src_wrap;
314 src_sampler.min_img_filter = filter;
315 src_sampler.mag_img_filter = filter;
316 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
317 src_sampler.normalized_coords = 1;
318 samplers[0] = &src_sampler;
319 exa->bound_textures[0] = pSrc->tex;
320 ++exa->num_bound_samplers;
321 }
322
323 if (pMaskPicture && pMask) {
324 unsigned mask_wrap = render_repeat_to_gallium(
325 pMaskPicture->repeatType);
326 int filter;
327
328 render_filter_to_gallium(pMaskPicture->filter, &filter);
329
330 mask_sampler.wrap_s = mask_wrap;
331 mask_sampler.wrap_t = mask_wrap;
332 mask_sampler.min_img_filter = filter;
333 mask_sampler.mag_img_filter = filter;
334 src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
335 mask_sampler.normalized_coords = 1;
336 samplers[1] = &mask_sampler;
337 exa->bound_textures[1] = pMask->tex;
338 ++exa->num_bound_samplers;
339 }
340
341 cso_set_samplers(exa->renderer->cso, exa->num_bound_samplers,
342 (const struct pipe_sampler_state **)samplers);
343 cso_set_sampler_textures(exa->renderer->cso, exa->num_bound_samplers,
344 exa->bound_textures);
345 }
346
347 static void
348 setup_vs_constant_buffer(struct exa_context *exa,
349 int width, int height)
350 {
351 const int param_bytes = 8 * sizeof(float);
352 float vs_consts[8] = {
353 2.f/width, 2.f/height, 1, 1,
354 -1, -1, 0, 0
355 };
356 renderer_set_constants(exa->renderer, PIPE_SHADER_VERTEX,
357 vs_consts, param_bytes);
358 }
359
360
361 static void
362 setup_fs_constant_buffer(struct exa_context *exa)
363 {
364 const int param_bytes = 4 * sizeof(float);
365 const float fs_consts[8] = {
366 0, 0, 0, 1,
367 };
368 renderer_set_constants(exa->renderer, PIPE_SHADER_FRAGMENT,
369 fs_consts, param_bytes);
370 }
371
372 static void
373 setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst)
374 {
375 int width = pDst->tex->width[0];
376 int height = pDst->tex->height[0];
377
378 setup_vs_constant_buffer(exa, width, height);
379 setup_fs_constant_buffer(exa);
380 }
381
382 static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix)
383 {
384 if (!trans)
385 return FALSE;
386
387 matrix[0] = XFixedToDouble(trans->matrix[0][0]);
388 matrix[1] = XFixedToDouble(trans->matrix[0][1]);
389 matrix[2] = XFixedToDouble(trans->matrix[0][2]);
390
391 matrix[3] = XFixedToDouble(trans->matrix[1][0]);
392 matrix[4] = XFixedToDouble(trans->matrix[1][1]);
393 matrix[5] = XFixedToDouble(trans->matrix[1][2]);
394
395 matrix[6] = XFixedToDouble(trans->matrix[2][0]);
396 matrix[7] = XFixedToDouble(trans->matrix[2][1]);
397 matrix[8] = XFixedToDouble(trans->matrix[2][2]);
398
399 return TRUE;
400 }
401
402 static void
403 setup_transforms(struct exa_context *exa,
404 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
405 {
406 PictTransform *src_t = NULL;
407 PictTransform *mask_t = NULL;
408
409 if (pSrcPicture)
410 src_t = pSrcPicture->transform;
411 if (pMaskPicture)
412 mask_t = pMaskPicture->transform;
413
414 exa->transform.has_src =
415 matrix_from_pict_transform(src_t, exa->transform.src);
416 exa->transform.has_mask =
417 matrix_from_pict_transform(mask_t, exa->transform.mask);
418 }
419
420 boolean xorg_composite_bind_state(struct exa_context *exa,
421 int op,
422 PicturePtr pSrcPicture,
423 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 renderer_bind_framebuffer(exa->renderer, pDst);
430 renderer_bind_viewport(exa->renderer, pDst);
431 bind_blend_state(exa, op, pSrcPicture, pMaskPicture);
432 renderer_bind_rasterizer(exa->renderer);
433 bind_shaders(exa, op, pSrcPicture, pMaskPicture);
434 bind_samplers(exa, op, pSrcPicture, pMaskPicture,
435 pDstPicture, pSrc, pMask, pDst);
436 setup_constant_buffers(exa, pDst);
437
438 setup_transforms(exa, pSrcPicture, pMaskPicture);
439
440 return TRUE;
441 }
442
443 void xorg_composite(struct exa_context *exa,
444 struct exa_pixmap_priv *dst,
445 int srcX, int srcY, int maskX, int maskY,
446 int dstX, int dstY, int width, int height)
447 {
448 if (exa->num_bound_samplers == 0 ) { /* solid fill */
449 renderer_draw_solid_rect(exa->renderer,
450 dstX, dstY, dstX + width, dstY + height,
451 exa->solid_color);
452 } else {
453 int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY};
454 float *src_matrix = NULL;
455 float *mask_matrix = NULL;
456
457 if (exa->transform.has_src)
458 src_matrix = exa->transform.src;
459 if (exa->transform.has_mask)
460 mask_matrix = exa->transform.mask;
461
462 renderer_draw_textures(exa->renderer,
463 pos, width, height,
464 exa->bound_textures,
465 exa->num_bound_samplers,
466 src_matrix, mask_matrix);
467 }
468 }
469
470 boolean xorg_solid_bind_state(struct exa_context *exa,
471 struct exa_pixmap_priv *pixmap,
472 Pixel fg)
473 {
474 unsigned vs_traits, fs_traits;
475 struct xorg_shader shader;
476
477 pixel_to_float4(fg, exa->solid_color);
478 exa->has_solid_color = TRUE;
479
480 #if 0
481 debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n",
482 (fg >> 24) & 0xff, (fg >> 16) & 0xff,
483 (fg >> 8) & 0xff, (fg >> 0) & 0xff,
484 exa->solid_color[0], exa->solid_color[1],
485 exa->solid_color[2], exa->solid_color[3]);
486 #endif
487
488 vs_traits = VS_SOLID_FILL;
489 fs_traits = FS_SOLID_FILL;
490
491 renderer_bind_framebuffer(exa->renderer, pixmap);
492 renderer_bind_viewport(exa->renderer, pixmap);
493 renderer_bind_rasterizer(exa->renderer);
494 bind_blend_state(exa, PictOpSrc, NULL, NULL);
495 setup_constant_buffers(exa, pixmap);
496
497 shader = xorg_shaders_get(exa->renderer->shaders, vs_traits, fs_traits);
498 cso_set_vertex_shader_handle(exa->renderer->cso, shader.vs);
499 cso_set_fragment_shader_handle(exa->renderer->cso, shader.fs);
500
501 return TRUE;
502 }
503
504 void xorg_solid(struct exa_context *exa,
505 struct exa_pixmap_priv *pixmap,
506 int x0, int y0, int x1, int y1)
507 {
508 renderer_draw_solid_rect(exa->renderer,
509 x0, y0, x1, y1, exa->solid_color);
510 }
511