xref: /OK3568_Linux_fs/external/xserver/glamor/glamor_core.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright © 2001 Keith Packard
3  * Copyright © 2008 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Eric Anholt <eric@anholt.net>
26  *
27  */
28 
29 /** @file glamor_core.c
30  *
31  * This file covers core X rendering in glamor.
32  */
33 
34 #include <stdlib.h>
35 
36 #include "glamor_priv.h"
37 
38 Bool
glamor_get_drawable_location(const DrawablePtr drawable)39 glamor_get_drawable_location(const DrawablePtr drawable)
40 {
41     PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
42     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
43 
44     if (pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED)
45         return 'm';
46     else
47         return 'f';
48 }
49 
50 GLint
glamor_compile_glsl_prog(GLenum type,const char * source)51 glamor_compile_glsl_prog(GLenum type, const char *source)
52 {
53     GLint ok;
54     GLint prog;
55 
56     prog = glCreateShader(type);
57     glShaderSource(prog, 1, (const GLchar **) &source, NULL);
58     glCompileShader(prog);
59     glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
60     if (!ok) {
61         GLchar *info;
62         GLint size;
63 
64         glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
65         info = malloc(size);
66         if (info) {
67             glGetShaderInfoLog(prog, size, NULL, info);
68             ErrorF("Failed to compile %s: %s\n",
69                    type == GL_FRAGMENT_SHADER ? "FS" : "VS", info);
70             ErrorF("Program source:\n%s", source);
71             free(info);
72         }
73         else
74             ErrorF("Failed to get shader compilation info.\n");
75         FatalError("GLSL compile failure\n");
76     }
77 
78     return prog;
79 }
80 
81 void
glamor_link_glsl_prog(ScreenPtr screen,GLint prog,const char * format,...)82 glamor_link_glsl_prog(ScreenPtr screen, GLint prog, const char *format, ...)
83 {
84     GLint ok;
85     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
86 
87     if (glamor_priv->has_khr_debug) {
88         char *label;
89         va_list va;
90 
91         va_start(va, format);
92         XNFvasprintf(&label, format, va);
93         glObjectLabel(GL_PROGRAM, prog, -1, label);
94         free(label);
95         va_end(va);
96     }
97 
98     glLinkProgram(prog);
99     glGetProgramiv(prog, GL_LINK_STATUS, &ok);
100     if (!ok) {
101         GLchar *info;
102         GLint size;
103 
104         glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
105         info = malloc(size);
106 
107         glGetProgramInfoLog(prog, size, NULL, info);
108         ErrorF("Failed to link: %s\n", info);
109         FatalError("GLSL link failure\n");
110     }
111 }
112 
113 #ifdef GLAMOR_HAS_GBM_MAP
114 Bool
glamor_prefer_gl(const char * func)115 glamor_prefer_gl(const char *func) {
116     if (!strcmp(func, "glamor_copy") ||
117         !strcmp(func, "glamor_composite") ||
118         !strcmp(func, "glamor_put_image") ||
119         !strcmp(func, "glamor_get_image") ||
120         !strcmp(func, "glamor_poly_segment") ||
121         !strcmp(func, "glamor_push_pixels") ||
122         !strcmp(func, "glamor_poly_fill_rect") ||
123         !strcmp(func, "glamor_poly_glyph_blt"))
124         return TRUE;
125 
126     /*
127     if (!strcmp(func, "glamor_poly_lines") ||
128        !strcmp(func, "glamor_poly_point") ||
129        !strcmp(func, "glamor_fill_spans") ||
130        !strcmp(func, "glamor_get_spans") ||
131        !strcmp(func, "glamor_set_spans"))
132         return FALSE;
133         */
134 
135     return FALSE;
136 }
137 #else
glamor_prefer_gl(const char * func)138 Bool glamor_prefer_gl(const char *func) { return TRUE; }
139 #endif
140 
141 static GCOps glamor_gc_ops = {
142     .FillSpans = glamor_fill_spans,
143     .SetSpans = glamor_set_spans,
144     .PutImage = glamor_put_image,
145     .CopyArea = glamor_copy_area,
146     .CopyPlane = glamor_copy_plane,
147     .PolyPoint = glamor_poly_point,
148     .Polylines = glamor_poly_lines,
149     .PolySegment = glamor_poly_segment,
150     .PolyRectangle = miPolyRectangle,
151     .PolyArc = miPolyArc,
152     .FillPolygon = miFillPolygon,
153     .PolyFillRect = glamor_poly_fill_rect,
154     .PolyFillArc = miPolyFillArc,
155     .PolyText8 = glamor_poly_text8,
156     .PolyText16 = glamor_poly_text16,
157     .ImageText8 = glamor_image_text8,
158     .ImageText16 = glamor_image_text16,
159     .ImageGlyphBlt = miImageGlyphBlt,
160     .PolyGlyphBlt = glamor_poly_glyph_blt,
161     .PushPixels = glamor_push_pixels,
162 };
163 
164 /*
165  * When the stipple is changed or drawn to, invalidate any
166  * cached copy
167  */
168 static void
glamor_invalidate_stipple(GCPtr gc)169 glamor_invalidate_stipple(GCPtr gc)
170 {
171     glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
172 
173     if (gc_priv->stipple) {
174         if (gc_priv->stipple_damage)
175             DamageUnregister(gc_priv->stipple_damage);
176         glamor_destroy_pixmap(gc_priv->stipple);
177         gc_priv->stipple = NULL;
178     }
179 }
180 
181 static void
glamor_stipple_damage_report(DamagePtr damage,RegionPtr region,void * closure)182 glamor_stipple_damage_report(DamagePtr damage, RegionPtr region,
183                              void *closure)
184 {
185     GCPtr       gc = closure;
186 
187     glamor_invalidate_stipple(gc);
188 }
189 
190 static void
glamor_stipple_damage_destroy(DamagePtr damage,void * closure)191 glamor_stipple_damage_destroy(DamagePtr damage, void *closure)
192 {
193     GCPtr               gc = closure;
194     glamor_gc_private   *gc_priv = glamor_get_gc_private(gc);
195 
196     gc_priv->stipple_damage = NULL;
197     glamor_invalidate_stipple(gc);
198 }
199 
200 void
glamor_track_stipple(GCPtr gc)201 glamor_track_stipple(GCPtr gc)
202 {
203     if (gc->stipple) {
204         glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
205 
206         if (!gc_priv->stipple_damage)
207             gc_priv->stipple_damage = DamageCreate(glamor_stipple_damage_report,
208                                                    glamor_stipple_damage_destroy,
209                                                    DamageReportNonEmpty,
210                                                    TRUE, gc->pScreen, gc);
211         if (gc_priv->stipple_damage)
212             DamageRegister(&gc->stipple->drawable, gc_priv->stipple_damage);
213     }
214 }
215 
216 /**
217  * uxa_validate_gc() sets the ops to glamor's implementations, which may be
218  * accelerated or may sync the card and fall back to fb.
219  */
220 void
glamor_validate_gc(GCPtr gc,unsigned long changes,DrawablePtr drawable)221 glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
222 {
223     /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
224      * Preempt fbValidateGC by doing its work and masking the change out, so
225      * that we can do the Prepare/finish_access.
226      */
227     if (changes & GCTile) {
228         if (!gc->tileIsPixel) {
229             glamor_pixmap_private *pixmap_priv =
230                 glamor_get_pixmap_private(gc->tile.pixmap);
231             if ((!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
232                 && FbEvenTile(gc->tile.pixmap->drawable.width *
233                               drawable->bitsPerPixel)) {
234                 glamor_fallback
235                     ("GC %p tile changed %p.\n", gc, gc->tile.pixmap);
236                 if (glamor_prepare_access
237                     (&gc->tile.pixmap->drawable, GLAMOR_ACCESS_RW)) {
238                     fbPadPixmap(gc->tile.pixmap);
239                     glamor_finish_access(&gc->tile.pixmap->drawable);
240                 }
241             }
242         }
243         /* Mask out the GCTile change notification, now that we've done FB's
244          * job for it.
245          */
246         changes &= ~GCTile;
247     }
248 
249     if (changes & GCStipple)
250         glamor_invalidate_stipple(gc);
251 
252     if (changes & GCStipple && gc->stipple) {
253         /* We can't inline stipple handling like we do for GCTile because
254          * it sets fbgc privates.
255          */
256         if (glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RW)) {
257             fbValidateGC(gc, changes, drawable);
258             glamor_finish_access(&gc->stipple->drawable);
259         }
260     }
261     else {
262         fbValidateGC(gc, changes, drawable);
263     }
264 
265     if (changes & GCDashList) {
266         glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
267 
268         if (gc_priv->dash) {
269             glamor_destroy_pixmap(gc_priv->dash);
270             gc_priv->dash = NULL;
271         }
272     }
273 
274     gc->ops = &glamor_gc_ops;
275 }
276 
277 void
glamor_destroy_gc(GCPtr gc)278 glamor_destroy_gc(GCPtr gc)
279 {
280     glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
281 
282     if (gc_priv->dash) {
283         glamor_destroy_pixmap(gc_priv->dash);
284         gc_priv->dash = NULL;
285     }
286     glamor_invalidate_stipple(gc);
287     if (gc_priv->stipple_damage)
288         DamageDestroy(gc_priv->stipple_damage);
289     miDestroyGC(gc);
290 }
291 
292 static GCFuncs glamor_gc_funcs = {
293     glamor_validate_gc,
294     miChangeGC,
295     miCopyGC,
296     glamor_destroy_gc,
297     miChangeClip,
298     miDestroyClip,
299     miCopyClip
300 };
301 
302 /**
303  * exaCreateGC makes a new GC and hooks up its funcs handler, so that
304  * exaValidateGC() will get called.
305  */
306 int
glamor_create_gc(GCPtr gc)307 glamor_create_gc(GCPtr gc)
308 {
309     glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
310 
311     gc_priv->dash = NULL;
312     gc_priv->stipple = NULL;
313     if (!fbCreateGC(gc))
314         return FALSE;
315 
316     gc->funcs = &glamor_gc_funcs;
317 
318     return TRUE;
319 }
320 
321 RegionPtr
glamor_bitmap_to_region(PixmapPtr pixmap)322 glamor_bitmap_to_region(PixmapPtr pixmap)
323 {
324     RegionPtr ret;
325 
326     glamor_fallback("pixmap %p \n", pixmap);
327     if (!glamor_prepare_access(&pixmap->drawable, GLAMOR_ACCESS_RO))
328         return NULL;
329     ret = fbPixmapToRegion(pixmap);
330     glamor_finish_access(&pixmap->drawable);
331     return ret;
332 }
333 
334