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