st/xorg: flip the coordinate system
[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
98 static INLINE void
99 setup_vertex0(float vertex[2][4], float x, float y,
100 float color[4])
101 {
102 vertex[0][0] = x;
103 vertex[0][1] = y;
104 vertex[0][2] = 0.f; /*z*/
105 vertex[0][3] = 1.f; /*w*/
106
107 vertex[1][0] = color[0]; /*r*/
108 vertex[1][1] = color[1]; /*g*/
109 vertex[1][2] = color[2]; /*b*/
110 vertex[1][3] = color[3]; /*a*/
111 }
112
113 static struct pipe_buffer *
114 setup_vertex_data0(struct exa_context *ctx,
115 int srcX, int srcY, int maskX, int maskY,
116 int dstX, int dstY, int width, int height)
117 {
118 float vertices[4][2][4];
119
120 /* 1st vertex */
121 setup_vertex0(vertices[0], dstX, dstY,
122 ctx->solid_color);
123 /* 2nd vertex */
124 setup_vertex0(vertices[1], dstX + width, dstY,
125 ctx->solid_color);
126 /* 3rd vertex */
127 setup_vertex0(vertices[2], dstX + width, dstY + height,
128 ctx->solid_color);
129 /* 4th vertex */
130 setup_vertex0(vertices[3], dstX, dstY + height,
131 ctx->solid_color);
132
133 return pipe_user_buffer_create(ctx->ctx->screen,
134 vertices,
135 sizeof(vertices));
136 }
137
138 static INLINE void
139 setup_vertex1(float vertex[2][4], float x, float y, float s, float t)
140 {
141 vertex[0][0] = x;
142 vertex[0][1] = y;
143 vertex[0][2] = 0.f; /*z*/
144 vertex[0][3] = 1.f; /*w*/
145
146 vertex[1][0] = s; /*s*/
147 vertex[1][1] = t; /*t*/
148 vertex[1][2] = 0.f; /*r*/
149 vertex[1][3] = 1.f; /*q*/
150 }
151
152 static struct pipe_buffer *
153 setup_vertex_data1(struct exa_context *ctx,
154 int srcX, int srcY, int maskX, int maskY,
155 int dstX, int dstY, int width, int height)
156 {
157 float vertices[4][2][4];
158 float s0, t0, s1, t1;
159 struct pipe_texture *src = ctx->bound_textures[0];
160
161 s0 = srcX / src->width[0];
162 s1 = srcX + width / src->width[0];
163 t0 = srcY / src->height[0];
164 t1 = srcY + height / src->height[0];
165
166 /* 1st vertex */
167 setup_vertex1(vertices[0], dstX, dstY,
168 s0, t0);
169 /* 2nd vertex */
170 setup_vertex1(vertices[1], dstX + width, dstY,
171 s1, t0);
172 /* 3rd vertex */
173 setup_vertex1(vertices[2], dstX + width, dstY + height,
174 s1, t1);
175 /* 4th vertex */
176 setup_vertex1(vertices[3], dstX, dstY + height,
177 s0, t1);
178
179 return pipe_user_buffer_create(ctx->ctx->screen,
180 vertices,
181 sizeof(vertices));
182 }
183
184
185 static INLINE void
186 setup_vertex2(float vertex[3][4], float x, float y,
187 float s0, float t0, float s1, float t1)
188 {
189 vertex[0][0] = x;
190 vertex[0][1] = y;
191 vertex[0][2] = 0.f; /*z*/
192 vertex[0][3] = 1.f; /*w*/
193
194 vertex[1][0] = s0; /*s*/
195 vertex[1][1] = t0; /*t*/
196 vertex[1][2] = 0.f; /*r*/
197 vertex[1][3] = 1.f; /*q*/
198
199 vertex[2][0] = s1; /*s*/
200 vertex[2][1] = t1; /*t*/
201 vertex[2][2] = 0.f; /*r*/
202 vertex[2][3] = 1.f; /*q*/
203 }
204
205 static struct pipe_buffer *
206 setup_vertex_data2(struct exa_context *ctx,
207 int srcX, int srcY, int maskX, int maskY,
208 int dstX, int dstY, int width, int height)
209 {
210 float vertices[4][3][4];
211 float st0[4], st1[4];
212 struct pipe_texture *src = ctx->bound_textures[0];
213 struct pipe_texture *mask = ctx->bound_textures[0];
214
215 st0[0] = srcX / src->width[0];
216 st0[1] = srcY / src->height[0];
217 st0[2] = srcX + width / src->width[0];
218 st0[3] = srcY + height / src->height[0];
219
220 st1[0] = maskX / mask->width[0];
221 st1[1] = maskY / mask->height[0];
222 st1[2] = maskX + width / mask->width[0];
223 st1[3] = maskY + height / mask->height[0];
224
225 /* 1st vertex */
226 setup_vertex2(vertices[0], dstX, dstY,
227 st0[0], st0[1], st1[0], st1[1]);
228 /* 2nd vertex */
229 setup_vertex2(vertices[1], dstX + width, dstY,
230 st0[2], st0[1], st1[2], st1[1]);
231 /* 3rd vertex */
232 setup_vertex2(vertices[2], dstX + width, dstY + height,
233 st0[2], st0[3], st1[2], st1[3]);
234 /* 4th vertex */
235 setup_vertex2(vertices[3], dstX, dstY + height,
236 st0[0], st0[3], st1[0], st1[3]);
237
238 return pipe_user_buffer_create(ctx->ctx->screen,
239 vertices,
240 sizeof(vertices));
241 }
242
243 boolean xorg_composite_accelerated(int op,
244 PicturePtr pSrcPicture,
245 PicturePtr pMaskPicture,
246 PicturePtr pDstPicture)
247 {
248 unsigned i;
249 unsigned accel_ops_count =
250 sizeof(accelerated_ops)/sizeof(struct acceleration_info);
251
252
253 /*FIXME: currently accel is disabled */
254 return FALSE;
255
256 if (pSrcPicture) {
257 /* component alpha not supported */
258 if (pSrcPicture->componentAlpha)
259 return FALSE;
260 /* fills not supported */
261 if (pSrcPicture->pSourcePict)
262 return FALSE;
263 }
264
265 for (i = 0; i < accel_ops_count; ++i) {
266 if (op == accelerated_ops[i].op) {
267 if (pMaskPicture && !accelerated_ops[i].with_mask)
268 return FALSE;
269 return TRUE;
270 }
271 }
272 return FALSE;
273 }
274
275 static void
276 bind_framebuffer_state(struct exa_context *exa, PicturePtr pDstPicture,
277 struct exa_pixmap_priv *pDst)
278 {
279 unsigned i;
280 struct pipe_framebuffer_state state;
281 struct pipe_surface *surface = exa_gpu_surface(exa, pDst);
282 memset(&state, 0, sizeof(struct pipe_framebuffer_state));
283
284 state.width = pDstPicture->pDrawable->width;
285 state.height = pDstPicture->pDrawable->height;
286
287 state.nr_cbufs = 1;
288 state.cbufs[0] = surface;
289 for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
290 state.cbufs[i] = 0;
291
292 /* currently we don't use depth/stencil */
293 state.zsbuf = 0;
294
295 cso_set_framebuffer(exa->cso, &state);
296 }
297
298 enum AxisOrientation {
299 Y0_BOTTOM,
300 Y0_TOP
301 };
302
303 static void
304 set_viewport(struct exa_context *exa, int width, int height,
305 enum AxisOrientation orientation)
306 {
307 struct pipe_viewport_state viewport;
308 float y_scale = (orientation == Y0_BOTTOM) ? -2.f : 2.f;
309
310 viewport.scale[0] = width / 2.f;
311 viewport.scale[1] = height / y_scale;
312 viewport.scale[2] = 1.0;
313 viewport.scale[3] = 1.0;
314 viewport.translate[0] = width / 2.f;
315 viewport.translate[1] = height / 2.f;
316 viewport.translate[2] = 0.0;
317 viewport.translate[3] = 0.0;
318
319 cso_set_viewport(exa->cso, &viewport);
320 }
321
322 static void
323 bind_viewport_state(struct exa_context *exa, PicturePtr pDstPicture)
324 {
325 int width = pDstPicture->pDrawable->width;
326 int height = pDstPicture->pDrawable->height;
327
328 set_viewport(exa, width, height, Y0_TOP);
329 }
330
331 static void
332 bind_blend_state(struct exa_context *exa, int op,
333 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
334 {
335 boolean component_alpha = pSrcPicture->componentAlpha;
336 struct xorg_composite_blend blend_opt;
337 struct pipe_blend_state blend;
338
339 if (component_alpha) {
340 op = PictOpOver;
341 }
342 blend_opt = blend_for_op(op);
343
344 memset(&blend, 0, sizeof(struct pipe_blend_state));
345 blend.blend_enable = 1;
346 blend.colormask |= PIPE_MASK_R;
347 blend.colormask |= PIPE_MASK_G;
348 blend.colormask |= PIPE_MASK_B;
349 blend.colormask |= PIPE_MASK_A;
350
351 blend.rgb_src_factor = blend_opt.rgb_src_factor;
352 blend.alpha_src_factor = blend_opt.alpha_src_factor;
353 blend.rgb_dst_factor = blend_opt.rgb_dst_factor;
354 blend.alpha_dst_factor = blend_opt.alpha_dst_factor;
355
356 cso_set_blend(exa->cso, &blend);
357 }
358
359 static void
360 bind_rasterizer_state(struct exa_context *exa)
361 {
362 struct pipe_rasterizer_state raster;
363 memset(&raster, 0, sizeof(struct pipe_rasterizer_state));
364 raster.gl_rasterization_rules = 1;
365 cso_set_rasterizer(exa->cso, &raster);
366 }
367
368 static void
369 bind_shaders(struct exa_context *exa, int op,
370 PicturePtr pSrcPicture, PicturePtr pMaskPicture)
371 {
372 unsigned vs_traits = 0, fs_traits = 0;
373 struct xorg_shader shader;
374
375 if (pSrcPicture) {
376 if (pSrcPicture->pSourcePict) {
377 if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
378 fs_traits |= FS_FILL;
379 vs_traits |= VS_FILL;
380 pixel_to_float4(pSrcPicture->pFormat,
381 pSrcPicture->pSourcePict->solidFill.color,
382 exa->solid_color);
383 } else {
384 debug_assert("!gradients not supported");
385 }
386 } else {
387 fs_traits |= FS_COMPOSITE;
388 vs_traits |= VS_COMPOSITE;
389 }
390 }
391
392 if (pMaskPicture) {
393 vs_traits |= VS_MASK;
394 fs_traits |= FS_MASK;
395 }
396
397 shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits);
398 cso_set_vertex_shader_handle(exa->cso, shader.vs);
399 cso_set_fragment_shader_handle(exa->cso, shader.fs);
400 }
401
402
403 static void
404 bind_samplers(struct exa_context *exa, int op,
405 PicturePtr pSrcPicture, PicturePtr pMaskPicture,
406 PicturePtr pDstPicture,
407 struct exa_pixmap_priv *pSrc,
408 struct exa_pixmap_priv *pMask,
409 struct exa_pixmap_priv *pDst)
410 {
411 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
412 struct pipe_sampler_state src_sampler, mask_sampler;
413
414 exa->num_bound_samplers = 0;
415
416 memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));
417 memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));
418
419 if (pSrcPicture && pSrc) {
420 src_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
421 src_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
422 src_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
423 src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
424 src_sampler.normalized_coords = 1;
425 samplers[0] = &src_sampler;
426 exa->bound_textures[0] = pSrc->tex;
427 ++exa->num_bound_samplers;
428 }
429
430 if (pMaskPicture && pMask) {
431 mask_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
432 mask_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
433 mask_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
434 mask_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST;
435 mask_sampler.normalized_coords = 1;
436 samplers[1] = &mask_sampler;
437 exa->bound_textures[1] = pMask->tex;
438 ++exa->num_bound_samplers;
439 }
440
441 cso_set_samplers(exa->cso, exa->num_bound_samplers,
442 (const struct pipe_sampler_state **)samplers);
443 cso_set_sampler_textures(exa->cso, exa->num_bound_samplers,
444 exa->bound_textures);
445 }
446
447 static void
448 setup_vs_constant_buffer(struct exa_context *exa,
449 int width, int height)
450 {
451 const int param_bytes = 8 * sizeof(float);
452 float vs_consts[8] = {
453 2.f/width, 2.f/height, 1, 1,
454 -1, -1, 0, 0
455 };
456 struct pipe_constant_buffer *cbuf = &exa->vs_const_buffer;
457
458 pipe_buffer_reference(&cbuf->buffer, NULL);
459 cbuf->buffer = pipe_buffer_create(exa->ctx->screen, 16,
460 PIPE_BUFFER_USAGE_CONSTANT,
461 param_bytes);
462
463 if (cbuf->buffer) {
464 pipe_buffer_write(exa->ctx->screen, cbuf->buffer,
465 0, param_bytes, vs_consts);
466 }
467 exa->ctx->set_constant_buffer(exa->ctx, PIPE_SHADER_VERTEX, 0, cbuf);
468 }
469
470
471 static void
472 setup_fs_constant_buffer(struct exa_context *exa)
473 {
474 const int param_bytes = 4 * sizeof(float);
475 float fs_consts[8] = {
476 0, 0, 0, 1,
477 };
478 struct pipe_constant_buffer *cbuf = &exa->fs_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, fs_consts);
488 }
489 exa->ctx->set_constant_buffer(exa->ctx, PIPE_SHADER_FRAGMENT, 0, cbuf);
490 }
491
492 static void
493 setup_constant_buffers(struct exa_context *exa, PicturePtr pDstPicture)
494 {
495 int width = pDstPicture->pDrawable->width;
496 int height = pDstPicture->pDrawable->height;
497
498 setup_vs_constant_buffer(exa, width, height);
499 setup_fs_constant_buffer(exa);
500 }
501
502 boolean xorg_composite_bind_state(struct exa_context *exa,
503 int op,
504 PicturePtr pSrcPicture,
505 PicturePtr pMaskPicture,
506 PicturePtr pDstPicture,
507 struct exa_pixmap_priv *pSrc,
508 struct exa_pixmap_priv *pMask,
509 struct exa_pixmap_priv *pDst)
510 {
511 bind_framebuffer_state(exa, pDstPicture, pDst);
512 bind_viewport_state(exa, pDstPicture);
513 bind_blend_state(exa, op, pSrcPicture, pMaskPicture);
514 bind_rasterizer_state(exa);
515 bind_shaders(exa, op, pSrcPicture, pMaskPicture);
516 bind_samplers(exa, op, pSrcPicture, pMaskPicture,
517 pDstPicture, pSrc, pMask, pDst);
518
519 setup_constant_buffers(exa, pDstPicture);
520
521 return FALSE;
522 }
523
524 void xorg_composite(struct exa_context *exa,
525 struct exa_pixmap_priv *dst,
526 int srcX, int srcY, int maskX, int maskY,
527 int dstX, int dstY, int width, int height)
528 {
529 struct pipe_context *pipe = exa->ctx;
530 struct pipe_buffer *buf = 0;
531
532 if (exa->num_bound_samplers == 0 ) { /* solid fill */
533 buf = setup_vertex_data0(exa,
534 srcX, srcY, maskX, maskY,
535 dstX, dstY, width, height);
536 } else if (exa->num_bound_samplers == 1 ) /* src */
537 buf = setup_vertex_data1(exa,
538 srcX, srcY, maskX, maskY,
539 dstX, dstY, width, height);
540 else if (exa->num_bound_samplers == 2) /* src + mask */
541 buf = setup_vertex_data2(exa,
542 srcX, srcY, maskX, maskY,
543 dstX, dstY, width, height);
544 else if (exa->num_bound_samplers == 3) { /* src + mask + dst */
545 debug_assert(!"src/mask/dst not handled right now");
546 #if 0
547 buf = setup_vertex_data2(exa,
548 srcX, srcY, maskX, maskY,
549 dstX, dstY, width, height);
550 #endif
551 }
552
553 if (buf) {
554 util_draw_vertex_buffer(pipe, buf, 0,
555 PIPE_PRIM_TRIANGLE_FAN,
556 4, /* verts */
557 1 + exa->num_bound_samplers); /* attribs/vert */
558
559 pipe_buffer_reference(&buf, NULL);
560 }
561 }
562