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 
114 static GCOps glamor_gc_ops = {
115     .FillSpans = glamor_fill_spans,
116     .SetSpans = glamor_set_spans,
117     .PutImage = glamor_put_image,
118     .CopyArea = glamor_copy_area,
119     .CopyPlane = glamor_copy_plane,
120     .PolyPoint = glamor_poly_point,
121     .Polylines = glamor_poly_lines,
122     .PolySegment = glamor_poly_segment,
123     .PolyRectangle = miPolyRectangle,
124     .PolyArc = miPolyArc,
125     .FillPolygon = miFillPolygon,
126     .PolyFillRect = glamor_poly_fill_rect,
127     .PolyFillArc = miPolyFillArc,
128     .PolyText8 = glamor_poly_text8,
129     .PolyText16 = glamor_poly_text16,
130     .ImageText8 = glamor_image_text8,
131     .ImageText16 = glamor_image_text16,
132     .ImageGlyphBlt = miImageGlyphBlt,
133     .PolyGlyphBlt = glamor_poly_glyph_blt,
134     .PushPixels = glamor_push_pixels,
135 };
136 
137 /*
138  * When the stipple is changed or drawn to, invalidate any
139  * cached copy
140  */
141 static void
glamor_invalidate_stipple(GCPtr gc)142 glamor_invalidate_stipple(GCPtr gc)
143 {
144     glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
145 
146     if (gc_priv->stipple) {
147         if (gc_priv->stipple_damage)
148             DamageUnregister(gc_priv->stipple_damage);
149         glamor_destroy_pixmap(gc_priv->stipple);
150         gc_priv->stipple = NULL;
151     }
152 }
153 
154 static void
glamor_stipple_damage_report(DamagePtr damage,RegionPtr region,void * closure)155 glamor_stipple_damage_report(DamagePtr damage, RegionPtr region,
156                              void *closure)
157 {
158     GCPtr       gc = closure;
159 
160     glamor_invalidate_stipple(gc);
161 }
162 
163 static void
glamor_stipple_damage_destroy(DamagePtr damage,void * closure)164 glamor_stipple_damage_destroy(DamagePtr damage, void *closure)
165 {
166     GCPtr               gc = closure;
167     glamor_gc_private   *gc_priv = glamor_get_gc_private(gc);
168 
169     gc_priv->stipple_damage = NULL;
170     glamor_invalidate_stipple(gc);
171 }
172 
173 void
glamor_track_stipple(GCPtr gc)174 glamor_track_stipple(GCPtr gc)
175 {
176     if (gc->stipple) {
177         glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
178 
179         if (!gc_priv->stipple_damage)
180             gc_priv->stipple_damage = DamageCreate(glamor_stipple_damage_report,
181                                                    glamor_stipple_damage_destroy,
182                                                    DamageReportNonEmpty,
183                                                    TRUE, gc->pScreen, gc);
184         if (gc_priv->stipple_damage)
185             DamageRegister(&gc->stipple->drawable, gc_priv->stipple_damage);
186     }
187 }
188 
189 /**
190  * uxa_validate_gc() sets the ops to glamor's implementations, which may be
191  * accelerated or may sync the card and fall back to fb.
192  */
193 void
glamor_validate_gc(GCPtr gc,unsigned long changes,DrawablePtr drawable)194 glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
195 {
196     /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
197      * Preempt fbValidateGC by doing its work and masking the change out, so
198      * that we can do the Prepare/finish_access.
199      */
200     if (changes & GCTile) {
201         if (!gc->tileIsPixel) {
202             glamor_pixmap_private *pixmap_priv =
203                 glamor_get_pixmap_private(gc->tile.pixmap);
204             if ((!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
205                 && FbEvenTile(gc->tile.pixmap->drawable.width *
206                               drawable->bitsPerPixel)) {
207                 glamor_fallback
208                     ("GC %p tile changed %p.\n", gc, gc->tile.pixmap);
209                 if (glamor_prepare_access
210                     (&gc->tile.pixmap->drawable, GLAMOR_ACCESS_RW)) {
211                     fbPadPixmap(gc->tile.pixmap);
212                     glamor_finish_access(&gc->tile.pixmap->drawable);
213                 }
214             }
215         }
216         /* Mask out the GCTile change notification, now that we've done FB's
217          * job for it.
218          */
219         changes &= ~GCTile;
220     }
221 
222     if (changes & GCStipple)
223         glamor_invalidate_stipple(gc);
224 
225     if (changes & GCStipple && gc->stipple) {
226         /* We can't inline stipple handling like we do for GCTile because
227          * it sets fbgc privates.
228          */
229         if (glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RW)) {
230             fbValidateGC(gc, changes, drawable);
231             glamor_finish_access(&gc->stipple->drawable);
232         }
233     }
234     else {
235         fbValidateGC(gc, changes, drawable);
236     }
237 
238     if (changes & GCDashList) {
239         glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
240 
241         if (gc_priv->dash) {
242             glamor_destroy_pixmap(gc_priv->dash);
243             gc_priv->dash = NULL;
244         }
245     }
246 
247     gc->ops = &glamor_gc_ops;
248 }
249 
250 void
glamor_destroy_gc(GCPtr gc)251 glamor_destroy_gc(GCPtr gc)
252 {
253     glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
254 
255     if (gc_priv->dash) {
256         glamor_destroy_pixmap(gc_priv->dash);
257         gc_priv->dash = NULL;
258     }
259     glamor_invalidate_stipple(gc);
260     if (gc_priv->stipple_damage)
261         DamageDestroy(gc_priv->stipple_damage);
262     miDestroyGC(gc);
263 }
264 
265 static GCFuncs glamor_gc_funcs = {
266     glamor_validate_gc,
267     miChangeGC,
268     miCopyGC,
269     glamor_destroy_gc,
270     miChangeClip,
271     miDestroyClip,
272     miCopyClip
273 };
274 
275 /**
276  * exaCreateGC makes a new GC and hooks up its funcs handler, so that
277  * exaValidateGC() will get called.
278  */
279 int
glamor_create_gc(GCPtr gc)280 glamor_create_gc(GCPtr gc)
281 {
282     glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
283 
284     gc_priv->dash = NULL;
285     gc_priv->stipple = NULL;
286     if (!fbCreateGC(gc))
287         return FALSE;
288 
289     gc->funcs = &glamor_gc_funcs;
290 
291     return TRUE;
292 }
293 
294 RegionPtr
glamor_bitmap_to_region(PixmapPtr pixmap)295 glamor_bitmap_to_region(PixmapPtr pixmap)
296 {
297     RegionPtr ret;
298 
299     glamor_fallback("pixmap %p \n", pixmap);
300     if (!glamor_prepare_access(&pixmap->drawable, GLAMOR_ACCESS_RO))
301         return NULL;
302     ret = fbPixmapToRegion(pixmap);
303     glamor_finish_access(&pixmap->drawable);
304     return ret;
305 }
306 
307