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