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