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