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