tizen 2.4 release
[framework/uifw/xorg/server/xorg-server.git] / glamor / glamor_fill.c
1 /*
2  * Copyright © 2008 Intel Corporation
3  * Copyright © 1998 Keith Packard
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of Keith Packard not be used in
10  * advertising or publicity pertaining to distribution of the software without
11  * specific, written prior permission.  Keith Packard makes no
12  * representations about the suitability of this software for any purpose.  It
13  * is provided "as is" without express or implied warranty.
14  *
15  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21  * PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors:
24  *    Eric Anholt <eric@anholt.net>
25  *    Zhigang Gong <zhigang.gong@linux.intel.com>
26  */
27
28 #include "glamor_priv.h"
29
30 /** @file glamor_fill.c
31  *
32  * GC fill implementation, based loosely on fb_fill.c
33  */
34
35 /**
36  * Fills the given rectangle of a drawable with the GC's fill style.
37  */
38 Bool
39 glamor_fill(DrawablePtr drawable,
40             GCPtr gc, int x, int y, int width, int height, Bool fallback)
41 {
42     PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(drawable);
43     int off_x, off_y;
44     PixmapPtr sub_pixmap = NULL;
45     glamor_access_t sub_pixmap_access;
46     DrawablePtr saved_drawable = NULL;
47     int saved_x = x, saved_y = y;
48
49     glamor_get_drawable_deltas(drawable, dst_pixmap, &off_x, &off_y);
50
51     switch (gc->fillStyle) {
52     case FillSolid:
53         if (!glamor_solid(dst_pixmap,
54                           x + off_x,
55                           y + off_y,
56                           width, height, gc->alu, gc->planemask, gc->fgPixel))
57             goto fail;
58         break;
59     case FillStippled:
60     case FillOpaqueStippled:
61         if (!glamor_stipple(dst_pixmap,
62                             gc->stipple,
63                             x + off_x,
64                             y + off_y,
65                             width,
66                             height,
67                             gc->alu,
68                             gc->planemask,
69                             gc->fgPixel,
70                             gc->bgPixel, gc->patOrg.x, gc->patOrg.y))
71             goto fail;
72         break;
73     case FillTiled:
74         if (!glamor_tile(dst_pixmap,
75                          gc->tile.pixmap,
76                          x + off_x,
77                          y + off_y,
78                          width,
79                          height,
80                          gc->alu,
81                          gc->planemask,
82                          x - drawable->x - gc->patOrg.x,
83                          y - drawable->y - gc->patOrg.y))
84             goto fail;
85         break;
86     }
87     return TRUE;
88
89  fail:
90     if (!fallback) {
91         if (glamor_ddx_fallback_check_pixmap(&dst_pixmap->drawable)
92             && glamor_ddx_fallback_check_gc(gc))
93             return FALSE;
94     }
95     /* Is it possible to set the access as WO? */
96
97     sub_pixmap_access = GLAMOR_ACCESS_RW;
98
99     sub_pixmap = glamor_get_sub_pixmap(dst_pixmap, x + off_x,
100                                        y + off_y, width, height,
101                                        sub_pixmap_access);
102
103     if (sub_pixmap != NULL) {
104         if (gc->fillStyle != FillSolid) {
105             gc->patOrg.x += (drawable->x - x);
106             gc->patOrg.y += (drawable->y - y);
107         }
108         saved_drawable = drawable;
109         drawable = &sub_pixmap->drawable;
110         saved_x = x;
111         saved_y = y;
112         x = 0;
113         y = 0;
114     }
115     if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW) &&
116         glamor_prepare_access_gc(gc)) {
117         fbFill(drawable, gc, x, y, width, height);
118     }
119     glamor_finish_access_gc(gc);
120     glamor_finish_access(drawable);
121
122     if (sub_pixmap != NULL) {
123         if (gc->fillStyle != FillSolid) {
124             gc->patOrg.x -= (saved_drawable->x - saved_x);
125             gc->patOrg.y -= (saved_drawable->y - saved_y);
126         }
127
128         x = saved_x;
129         y = saved_y;
130
131         glamor_put_sub_pixmap(sub_pixmap, dst_pixmap,
132                               x + off_x, y + off_y,
133                               width, height, sub_pixmap_access);
134     }
135
136     return TRUE;
137 }
138
139 void
140 glamor_init_solid_shader(ScreenPtr screen)
141 {
142     glamor_screen_private *glamor_priv;
143     const char *solid_vs =
144         "attribute vec4 v_position;"
145         "void main()\n"
146         "{\n"
147         "       gl_Position = v_position;\n"
148         "}\n";
149     const char *solid_fs =
150         GLAMOR_DEFAULT_PRECISION
151         "uniform vec4 color;\n"
152         "void main()\n"
153         "{\n"
154         "       gl_FragColor = color;\n"
155         "}\n";
156     GLint fs_prog, vs_prog;
157
158     glamor_priv = glamor_get_screen_private(screen);
159     glamor_make_current(glamor_priv);
160     glamor_priv->solid_prog = glCreateProgram();
161     vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, solid_vs);
162     fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, solid_fs);
163     glAttachShader(glamor_priv->solid_prog, vs_prog);
164     glAttachShader(glamor_priv->solid_prog, fs_prog);
165
166     glBindAttribLocation(glamor_priv->solid_prog,
167                          GLAMOR_VERTEX_POS, "v_position");
168     glamor_link_glsl_prog(screen, glamor_priv->solid_prog, "solid");
169
170     glamor_priv->solid_color_uniform_location =
171         glGetUniformLocation(glamor_priv->solid_prog, "color");
172 }
173
174 void
175 glamor_fini_solid_shader(ScreenPtr screen)
176 {
177     glamor_screen_private *glamor_priv;
178
179     glamor_priv = glamor_get_screen_private(screen);
180     glamor_make_current(glamor_priv);
181     glDeleteProgram(glamor_priv->solid_prog);
182 }
183
184 static void
185 _glamor_solid_boxes(PixmapPtr pixmap, BoxPtr box, int nbox, float *color)
186 {
187     ScreenPtr screen = pixmap->drawable.pScreen;
188     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
189     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
190     GLfloat xscale, yscale;
191     float stack_vertices[32];
192     float *vertices = stack_vertices;
193     int valid_nbox = ARRAY_SIZE(stack_vertices) / (4 * 2);
194
195     glamor_set_destination_pixmap_priv_nc(pixmap_priv);
196
197     glamor_make_current(glamor_priv);
198     glUseProgram(glamor_priv->solid_prog);
199
200     glUniform4fv(glamor_priv->solid_color_uniform_location, 1, color);
201
202     pixmap_priv_get_dest_scale(pixmap_priv, &xscale, &yscale);
203
204     if (nbox > valid_nbox) {
205         int allocated_nbox;
206         float *new_vertices;
207
208         if (nbox > GLAMOR_COMPOSITE_VBO_VERT_CNT / 6)
209             allocated_nbox = GLAMOR_COMPOSITE_VBO_VERT_CNT / 6;
210         else
211             allocated_nbox = nbox;
212         new_vertices = malloc(allocated_nbox * 4 * 2 * sizeof(float));
213         if (new_vertices) {
214             vertices = new_vertices;
215             valid_nbox = allocated_nbox;
216         }
217     }
218
219     glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
220                           GL_FALSE, 2 * sizeof(float), vertices);
221     glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
222
223     while (nbox) {
224         int box_cnt, i;
225         float *next_box;
226
227         next_box = vertices;
228         box_cnt = nbox > valid_nbox ? valid_nbox : nbox;
229         for (i = 0; i < box_cnt; i++) {
230             glamor_set_normalize_vcoords(pixmap_priv, xscale, yscale,
231                                          box[i].x1, box[i].y1,
232                                          box[i].x2, box[i].y2,
233                                          glamor_priv->yInverted,
234                                          next_box);
235             next_box += 4 * 2;
236         }
237         if (box_cnt == 1)
238             glDrawArrays(GL_TRIANGLE_FAN, 0, box_cnt * 4);
239         else {
240             if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
241                 glDrawRangeElements(GL_TRIANGLES, 0, box_cnt * 4, box_cnt * 6,
242                                     GL_UNSIGNED_SHORT, NULL);
243             } else {
244                 glDrawElements(GL_TRIANGLES, box_cnt * 6, GL_UNSIGNED_SHORT,
245                                NULL);
246             }
247         }
248         nbox -= box_cnt;
249         box += box_cnt;
250     }
251
252     if (vertices != stack_vertices)
253         free(vertices);
254
255     glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
256     glamor_priv->state = RENDER_STATE;
257     glamor_priv->render_idle_cnt = 0;
258 }
259
260 /**
261  * Fills the given rectangles of pixmap with an X pixel value.
262  *
263  * This is a helper used by other code after clipping and translation
264  * of coordinates to a glamor backing pixmap.
265  */
266 Bool
267 glamor_solid_boxes(PixmapPtr pixmap,
268                    BoxPtr box, int nbox, unsigned long fg_pixel)
269 {
270     glamor_pixmap_private *pixmap_priv;
271     GLfloat color[4];
272
273     pixmap_priv = glamor_get_pixmap_private(pixmap);
274
275     if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
276         return FALSE;
277
278     glamor_get_rgba_from_pixel(fg_pixel,
279                                &color[0],
280                                &color[1],
281                                &color[2], &color[3], format_for_pixmap(pixmap));
282
283     if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
284         RegionRec region;
285         int n_region;
286         glamor_pixmap_clipped_regions *clipped_regions;
287         int i;
288
289         RegionInitBoxes(&region, box, nbox);
290         clipped_regions =
291             glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0,
292                                            0, 0);
293         for (i = 0; i < n_region; i++) {
294             BoxPtr inner_box;
295             int inner_nbox;
296
297             SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
298
299             inner_box = RegionRects(clipped_regions[i].region);
300             inner_nbox = RegionNumRects(clipped_regions[i].region);
301             _glamor_solid_boxes(pixmap, inner_box, inner_nbox, color);
302             RegionDestroy(clipped_regions[i].region);
303         }
304         free(clipped_regions);
305         RegionUninit(&region);
306     }
307     else
308         _glamor_solid_boxes(pixmap, box, nbox, color);
309
310     return TRUE;
311 }
312
313 /**
314  * Fills a rectangle of a pixmap with an X pixel value.
315  *
316  * This is a helper used by other glamor code mostly for clearing of
317  * buffers to 0.
318  */
319 Bool
320 glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
321              unsigned char alu, unsigned long planemask, unsigned long fg_pixel)
322 {
323     ScreenPtr screen = pixmap->drawable.pScreen;
324     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
325     glamor_pixmap_private *pixmap_priv;
326     BoxRec box;
327
328     pixmap_priv = glamor_get_pixmap_private(pixmap);
329
330     if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
331         return FALSE;
332
333     if (!glamor_set_planemask(pixmap, planemask)) {
334         glamor_fallback("Failedto set planemask  in glamor_solid.\n");
335         return FALSE;
336     }
337
338     glamor_make_current(glamor_priv);
339     if (!glamor_set_alu(screen, alu)) {
340         if (alu == GXclear)
341             fg_pixel = 0;
342         else {
343             glamor_fallback("unsupported alu %x\n", alu);
344             return FALSE;
345         }
346     }
347     box.x1 = x;
348     box.y1 = y;
349     box.x2 = x + width;
350     box.y2 = y + height;
351     glamor_solid_boxes(pixmap, &box, 1, fg_pixel);
352
353     glamor_set_alu(screen, GXcopy);
354
355     return TRUE;
356 }