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