OSDN Git Service

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