1 /*
2  * Copyright © 2008,2011 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Eric Anholt <eric@anholt.net>
25  *    Zhigang Gong <zhigang.gong@linux.intel.com>
26  *    Chad Versace <chad.versace@linux.intel.com>
27  */
28 
29 /** @file glamor.c
30  * This file covers the initialization and teardown of glamor, and has various
31  * functions not responsible for performing rendering.
32  */
33 
34 #include <stdlib.h>
35 #include <unistd.h>
36 
37 #include "glamor_priv.h"
38 #include "mipict.h"
39 
40 DevPrivateKeyRec glamor_screen_private_key;
41 DevPrivateKeyRec glamor_pixmap_private_key;
42 DevPrivateKeyRec glamor_gc_private_key;
43 
44 glamor_screen_private *
glamor_get_screen_private(ScreenPtr screen)45 glamor_get_screen_private(ScreenPtr screen)
46 {
47     return (glamor_screen_private *)
48         dixLookupPrivate(&screen->devPrivates, &glamor_screen_private_key);
49 }
50 
51 void
glamor_set_screen_private(ScreenPtr screen,glamor_screen_private * priv)52 glamor_set_screen_private(ScreenPtr screen, glamor_screen_private *priv)
53 {
54     dixSetPrivate(&screen->devPrivates, &glamor_screen_private_key, priv);
55 }
56 
57 /**
58  * glamor_get_drawable_pixmap() returns a backing pixmap for a given drawable.
59  *
60  * @param drawable the drawable being requested.
61  *
62  * This function returns the backing pixmap for a drawable, whether it is a
63  * redirected window, unredirected window, or already a pixmap.  Note that
64  * coordinate translation is needed when drawing to the backing pixmap of a
65  * redirected window, and the translation coordinates are provided by calling
66  * exaGetOffscreenPixmap() on the drawable.
67  */
68 PixmapPtr
glamor_get_drawable_pixmap(DrawablePtr drawable)69 glamor_get_drawable_pixmap(DrawablePtr drawable)
70 {
71     if (drawable->type == DRAWABLE_WINDOW)
72         return drawable->pScreen->GetWindowPixmap((WindowPtr) drawable);
73     else
74         return (PixmapPtr) drawable;
75 }
76 
77 static void
glamor_init_pixmap_private_small(PixmapPtr pixmap,glamor_pixmap_private * pixmap_priv)78 glamor_init_pixmap_private_small(PixmapPtr pixmap, glamor_pixmap_private *pixmap_priv)
79 {
80     pixmap_priv->box.x1 = 0;
81     pixmap_priv->box.x2 = pixmap->drawable.width;
82     pixmap_priv->box.y1 = 0;
83     pixmap_priv->box.y2 = pixmap->drawable.height;
84     pixmap_priv->block_w = pixmap->drawable.width;
85     pixmap_priv->block_h = pixmap->drawable.height;
86     pixmap_priv->block_hcnt = 1;
87     pixmap_priv->block_wcnt = 1;
88     pixmap_priv->box_array = &pixmap_priv->box;
89     pixmap_priv->fbo_array = &pixmap_priv->fbo;
90 }
91 
92 _X_EXPORT void
glamor_set_pixmap_type(PixmapPtr pixmap,glamor_pixmap_type_t type)93 glamor_set_pixmap_type(PixmapPtr pixmap, glamor_pixmap_type_t type)
94 {
95     glamor_pixmap_private *pixmap_priv;
96 
97     pixmap_priv = glamor_get_pixmap_private(pixmap);
98     pixmap_priv->type = type;
99     glamor_init_pixmap_private_small(pixmap, pixmap_priv);
100 }
101 
102 _X_EXPORT void
glamor_set_pixmap_texture(PixmapPtr pixmap,unsigned int tex)103 glamor_set_pixmap_texture(PixmapPtr pixmap, unsigned int tex)
104 {
105     ScreenPtr screen = pixmap->drawable.pScreen;
106     glamor_pixmap_private *pixmap_priv;
107     glamor_screen_private *glamor_priv;
108     glamor_pixmap_fbo *fbo;
109     GLenum format;
110 
111     glamor_priv = glamor_get_screen_private(screen);
112     pixmap_priv = glamor_get_pixmap_private(pixmap);
113 
114     if (pixmap_priv->fbo) {
115         fbo = glamor_pixmap_detach_fbo(pixmap_priv);
116         glamor_destroy_fbo(glamor_priv, fbo);
117     }
118 
119     format = gl_iformat_for_pixmap(pixmap);
120     fbo = glamor_create_fbo_from_tex(glamor_priv, pixmap->drawable.width,
121                                      pixmap->drawable.height, format, tex, 0);
122 
123     if (fbo == NULL) {
124         ErrorF("XXX fail to create fbo.\n");
125         return;
126     }
127 
128     glamor_pixmap_attach_fbo(pixmap, fbo);
129 }
130 
131 _X_EXPORT void
glamor_clear_pixmap(PixmapPtr pixmap)132 glamor_clear_pixmap(PixmapPtr pixmap)
133 {
134     ScreenPtr screen = pixmap->drawable.pScreen;
135     glamor_screen_private *glamor_priv;
136     glamor_pixmap_private *pixmap_priv;
137 
138     glamor_priv = glamor_get_screen_private(screen);
139     pixmap_priv = glamor_get_pixmap_private(pixmap);
140 
141     assert(pixmap_priv->fbo != NULL);
142 
143     glamor_pixmap_clear_fbo(glamor_priv, pixmap_priv->fbo);
144 }
145 
146 uint32_t
glamor_get_pixmap_texture(PixmapPtr pixmap)147 glamor_get_pixmap_texture(PixmapPtr pixmap)
148 {
149     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
150 
151     if (!pixmap_priv)
152         return 0;
153 
154     if (!pixmap_priv->fbo)
155         return 0;
156 
157     if (pixmap_priv->type != GLAMOR_TEXTURE_ONLY)
158         return 0;
159 
160     return pixmap_priv->fbo->tex;
161 }
162 
163 void
glamor_bind_texture(glamor_screen_private * glamor_priv,GLenum texture,glamor_pixmap_fbo * fbo,Bool destination_red)164 glamor_bind_texture(glamor_screen_private *glamor_priv, GLenum texture,
165                     glamor_pixmap_fbo *fbo, Bool destination_red)
166 {
167     glActiveTexture(texture);
168     glBindTexture(GL_TEXTURE_2D, fbo->tex);
169 
170     /* If we're pulling data from a GL_RED texture, then whether we
171      * want to make it an A,0,0,0 result or a 0,0,0,R result depends
172      * on whether the destination is also a GL_RED texture.
173      *
174      * For GL_RED destinations, we need to leave the bits in the R
175      * channel. For all other destinations, we need to clear out the R
176      * channel so that it returns zero for R, G and B.
177      *
178      * Note that we're leaving the SWIZZLE_A value alone; for GL_RED
179      * destinations, that means we'll actually be returning R,0,0,R,
180      * but it doesn't matter as the bits in the alpha channel aren't
181      * going anywhere.
182      */
183 
184     /* Is the operand a GL_RED fbo?
185      */
186 
187     if (glamor_fbo_red_is_alpha(glamor_priv, fbo)) {
188 
189         /* If destination is also GL_RED, then preserve the bits in
190          * the R channel */
191 
192         if (destination_red)
193             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
194         else
195             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ZERO);
196     }
197 }
198 
199 PixmapPtr
glamor_create_pixmap(ScreenPtr screen,int w,int h,int depth,unsigned int usage)200 glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
201                      unsigned int usage)
202 {
203     PixmapPtr pixmap;
204     glamor_pixmap_private *pixmap_priv;
205     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
206     glamor_pixmap_fbo *fbo = NULL;
207     int pitch;
208     GLenum format;
209 
210     if (w > 32767 || h > 32767)
211         return NullPixmap;
212 
213     if ((usage == GLAMOR_CREATE_PIXMAP_CPU
214          || (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE &&
215              w <= glamor_priv->glyph_max_dim &&
216              h <= glamor_priv->glyph_max_dim)
217          || (w == 0 && h == 0)
218          || !glamor_check_pixmap_fbo_depth(depth)))
219         return fbCreatePixmap(screen, w, h, depth, usage);
220     else
221         pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
222 
223     pixmap_priv = glamor_get_pixmap_private(pixmap);
224 
225     format = gl_iformat_for_pixmap(pixmap);
226 
227     pitch = (((w * pixmap->drawable.bitsPerPixel + 7) / 8) + 3) & ~3;
228     screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, pitch, NULL);
229 
230     pixmap_priv->type = GLAMOR_TEXTURE_ONLY;
231 
232     if (usage == GLAMOR_CREATE_PIXMAP_NO_TEXTURE) {
233         glamor_init_pixmap_private_small(pixmap, pixmap_priv);
234         return pixmap;
235     }
236     else if (usage == GLAMOR_CREATE_NO_LARGE ||
237         glamor_check_fbo_size(glamor_priv, w, h))
238     {
239         glamor_init_pixmap_private_small(pixmap, pixmap_priv);
240         fbo = glamor_create_fbo(glamor_priv, w, h, format, usage);
241     } else {
242         int tile_size = glamor_priv->max_fbo_size;
243         DEBUGF("Create LARGE pixmap %p width %d height %d, tile size %d\n",
244                pixmap, w, h, tile_size);
245         fbo = glamor_create_fbo_array(glamor_priv, w, h, format, usage,
246                                       tile_size, tile_size, pixmap_priv);
247     }
248 
249     if (fbo == NULL) {
250         fbDestroyPixmap(pixmap);
251         return fbCreatePixmap(screen, w, h, depth, usage);
252     }
253 
254     glamor_pixmap_attach_fbo(pixmap, fbo);
255 
256     return pixmap;
257 }
258 
259 Bool
glamor_destroy_pixmap(PixmapPtr pixmap)260 glamor_destroy_pixmap(PixmapPtr pixmap)
261 {
262     if (pixmap->refcnt == 1) {
263         glamor_pixmap_destroy_fbo(pixmap);
264     }
265 
266     return fbDestroyPixmap(pixmap);
267 }
268 
269 void
glamor_block_handler(ScreenPtr screen)270 glamor_block_handler(ScreenPtr screen)
271 {
272     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
273 
274     glamor_make_current(glamor_priv);
275     glFlush();
276 }
277 
278 static void
_glamor_block_handler(ScreenPtr screen,void * timeout)279 _glamor_block_handler(ScreenPtr screen, void *timeout)
280 {
281     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
282 
283     glamor_make_current(glamor_priv);
284     glFlush();
285 
286     screen->BlockHandler = glamor_priv->saved_procs.block_handler;
287     screen->BlockHandler(screen, timeout);
288     glamor_priv->saved_procs.block_handler = screen->BlockHandler;
289     screen->BlockHandler = _glamor_block_handler;
290 }
291 
292 static void
glamor_set_debug_level(int * debug_level)293 glamor_set_debug_level(int *debug_level)
294 {
295     char *debug_level_string;
296 
297     debug_level_string = getenv("GLAMOR_DEBUG");
298     if (debug_level_string
299         && sscanf(debug_level_string, "%d", debug_level) == 1)
300         return;
301     *debug_level = 0;
302 }
303 
304 int glamor_debug_level;
305 
306 void
glamor_gldrawarrays_quads_using_indices(glamor_screen_private * glamor_priv,unsigned count)307 glamor_gldrawarrays_quads_using_indices(glamor_screen_private *glamor_priv,
308                                         unsigned count)
309 {
310     unsigned i;
311 
312     /* For a single quad, don't bother with an index buffer. */
313     if (count ==  1)
314         goto fallback;
315 
316     if (glamor_priv->ib_size < count) {
317         /* Basic GLES2 doesn't have any way to map buffer objects for
318          * writing, but it's long past time for drivers to have
319          * MapBufferRange.
320          */
321         if (!glamor_priv->has_map_buffer_range)
322             goto fallback;
323 
324         /* Lazy create the buffer name, and only bind it once since
325          * none of the glamor code binds it to anything else.
326          */
327         if (!glamor_priv->ib) {
328             glGenBuffers(1, &glamor_priv->ib);
329             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ib);
330         }
331 
332         /* For now, only support GL_UNSIGNED_SHORTs. */
333         if (count > ((1 << 16) - 1) / 4) {
334             goto fallback;
335         } else {
336             uint16_t *data;
337             size_t size = count * 6 * sizeof(GLushort);
338 
339             glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL, GL_STATIC_DRAW);
340             data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,
341                                     0, size,
342                                     GL_MAP_WRITE_BIT |
343                                     GL_MAP_INVALIDATE_BUFFER_BIT);
344             for (i = 0; i < count; i++) {
345                 data[i * 6 + 0] = i * 4 + 0;
346                 data[i * 6 + 1] = i * 4 + 1;
347                 data[i * 6 + 2] = i * 4 + 2;
348                 data[i * 6 + 3] = i * 4 + 0;
349                 data[i * 6 + 4] = i * 4 + 2;
350                 data[i * 6 + 5] = i * 4 + 3;
351             }
352             glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
353 
354             glamor_priv->ib_size = count;
355             glamor_priv->ib_type = GL_UNSIGNED_SHORT;
356         }
357     }
358 
359     glDrawElements(GL_TRIANGLES, count * 6, glamor_priv->ib_type, NULL);
360     return;
361 
362 fallback:
363     for (i = 0; i < count; i++)
364         glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4);
365 }
366 
367 
368 static Bool
glamor_check_instruction_count(int gl_version)369 glamor_check_instruction_count(int gl_version)
370 {
371     GLint max_native_alu_instructions;
372 
373     /* Avoid using glamor if the reported instructions limit is too low,
374      * as this would cause glamor to fallback on sw due to large shaders
375      * which ends up being unbearably slow.
376      */
377     if (gl_version < 30) {
378         if (!epoxy_has_gl_extension("GL_ARB_fragment_program")) {
379             ErrorF("GL_ARB_fragment_program required\n");
380             return FALSE;
381         }
382 
383         glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
384                           GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB,
385                           &max_native_alu_instructions);
386         if (max_native_alu_instructions < GLAMOR_MIN_ALU_INSTRUCTIONS) {
387             LogMessage(X_WARNING,
388                        "glamor requires at least %d instructions (%d reported)\n",
389                        GLAMOR_MIN_ALU_INSTRUCTIONS, max_native_alu_instructions);
390             return FALSE;
391         }
392     }
393 
394     return TRUE;
395 }
396 
397 static void GLAPIENTRY
glamor_debug_output_callback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * userParam)398 glamor_debug_output_callback(GLenum source,
399                              GLenum type,
400                              GLuint id,
401                              GLenum severity,
402                              GLsizei length,
403                              const GLchar *message,
404                              const void *userParam)
405 {
406     ScreenPtr screen = (void *)userParam;
407     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
408 
409     if (glamor_priv->suppress_gl_out_of_memory_logging &&
410         source == GL_DEBUG_SOURCE_API && type == GL_DEBUG_TYPE_ERROR) {
411         return;
412     }
413 
414     LogMessageVerb(X_ERROR, 0, "glamor%d: GL error: %*s\n",
415                screen->myNum, length, message);
416 }
417 
418 /**
419  * Configures GL_ARB_debug_output to give us immediate callbacks when
420  * GL errors occur, so that we can log them.
421  */
422 static void
glamor_setup_debug_output(ScreenPtr screen)423 glamor_setup_debug_output(ScreenPtr screen)
424 {
425     if (!epoxy_has_gl_extension("GL_ARB_debug_output"))
426         return;
427 
428     glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
429     /* Disable debugging messages other than GL API errors */
430     glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL,
431                           GL_FALSE);
432     glDebugMessageControl(GL_DEBUG_SOURCE_API,
433                           GL_DEBUG_TYPE_ERROR,
434                           GL_DONT_CARE,
435                           0, NULL, GL_TRUE);
436     glDebugMessageCallback(glamor_debug_output_callback,
437                            screen);
438 
439     /* If KHR_debug is present, all debug output is disabled by
440      * default on non-debug contexts.
441      */
442     if (epoxy_has_gl_extension("GL_KHR_debug"))
443         glEnable(GL_DEBUG_OUTPUT);
444 }
445 
446 /** Set up glamor for an already-configured GL context. */
447 Bool
glamor_init(ScreenPtr screen,unsigned int flags)448 glamor_init(ScreenPtr screen, unsigned int flags)
449 {
450     glamor_screen_private *glamor_priv;
451     int gl_version;
452     int glsl_major, glsl_minor;
453     int max_viewport_size[2];
454     const char *shading_version_string;
455     int shading_version_offset;
456 
457     PictureScreenPtr ps = GetPictureScreenIfSet(screen);
458 
459     if (flags & ~GLAMOR_VALID_FLAGS) {
460         ErrorF("glamor_init: Invalid flags %x\n", flags);
461         return FALSE;
462     }
463     glamor_priv = calloc(1, sizeof(*glamor_priv));
464     if (glamor_priv == NULL)
465         return FALSE;
466 
467     glamor_priv->flags = flags;
468 
469     if (!dixRegisterPrivateKey(&glamor_screen_private_key, PRIVATE_SCREEN, 0)) {
470         LogMessage(X_WARNING,
471                    "glamor%d: Failed to allocate screen private\n",
472                    screen->myNum);
473         goto free_glamor_private;
474     }
475 
476     glamor_set_screen_private(screen, glamor_priv);
477 
478     if (!dixRegisterPrivateKey(&glamor_pixmap_private_key, PRIVATE_PIXMAP,
479                                sizeof(struct glamor_pixmap_private))) {
480         LogMessage(X_WARNING,
481                    "glamor%d: Failed to allocate pixmap private\n",
482                    screen->myNum);
483         goto free_glamor_private;
484     }
485 
486     if (!dixRegisterPrivateKey(&glamor_gc_private_key, PRIVATE_GC,
487                                sizeof (glamor_gc_private))) {
488         LogMessage(X_WARNING,
489                    "glamor%d: Failed to allocate gc private\n",
490                    screen->myNum);
491         goto free_glamor_private;
492     }
493 
494     glamor_priv->saved_procs.close_screen = screen->CloseScreen;
495     screen->CloseScreen = glamor_close_screen;
496 
497     glamor_priv->saved_procs.destroy_pixmap = screen->DestroyPixmap;
498     screen->DestroyPixmap = glamor_destroy_pixmap;
499 
500     /* If we are using egl screen, call egl screen init to
501      * register correct close screen function. */
502     if (flags & GLAMOR_USE_EGL_SCREEN) {
503         glamor_egl_screen_init(screen, &glamor_priv->ctx);
504     } else {
505         if (!glamor_glx_screen_init(&glamor_priv->ctx))
506             goto fail;
507     }
508 
509     glamor_make_current(glamor_priv);
510 
511     if (epoxy_is_desktop_gl())
512         glamor_priv->gl_flavor = GLAMOR_GL_DESKTOP;
513     else
514         glamor_priv->gl_flavor = GLAMOR_GL_ES2;
515 
516     gl_version = epoxy_gl_version();
517 
518     /* assume a core profile if we are GL 3.1 and don't have ARB_compatibility */
519     glamor_priv->is_core_profile =
520         gl_version >= 31 && !epoxy_has_gl_extension("GL_ARB_compatibility");
521 
522     shading_version_string = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
523 
524     if (!shading_version_string) {
525         LogMessage(X_WARNING,
526                    "glamor%d: Failed to get GLSL version\n",
527                    screen->myNum);
528         goto fail;
529     }
530 
531     shading_version_offset = 0;
532     if (strncmp("OpenGL ES GLSL ES ", shading_version_string, 18) == 0)
533         shading_version_offset = 18;
534 
535     if (sscanf(shading_version_string + shading_version_offset,
536                "%i.%i",
537                &glsl_major,
538                &glsl_minor) != 2) {
539         LogMessage(X_WARNING,
540                    "glamor%d: Failed to parse GLSL version string %s\n",
541                    screen->myNum, shading_version_string);
542         goto fail;
543     }
544     glamor_priv->glsl_version = glsl_major * 100 + glsl_minor;
545 
546     if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
547         /* Force us back to the base version of our programs on an ES
548          * context, anyway.  Basically glamor only uses desktop 1.20
549          * or 1.30 currently.  1.30's new features are also present in
550          * ES 3.0, but our glamor_program.c constructions use a lot of
551          * compatibility features (to reduce the diff between 1.20 and
552          * 1.30 programs).
553          */
554         glamor_priv->glsl_version = 120;
555     }
556 
557     /* We'd like to require GL_ARB_map_buffer_range or
558      * GL_OES_map_buffer_range, since it offers more information to
559      * the driver than plain old glMapBuffer() or glBufferSubData().
560      * It's been supported on Mesa on the desktop since 2009 and on
561      * GLES2 since October 2012.  It's supported on Apple's iOS
562      * drivers for SGX535 and A7, but apparently not on most Android
563      * devices (the OES extension spec wasn't released until June
564      * 2012).
565      *
566      * 82% of 0 A.D. players (desktop GL) submitting hardware reports
567      * have support for it, with most of the ones lacking it being on
568      * Windows with Intel 4-series (G45) graphics or older.
569      */
570     if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
571         if (gl_version < 21) {
572             ErrorF("Require OpenGL version 2.1 or later.\n");
573             goto fail;
574         }
575 
576         if (!glamor_priv->is_core_profile &&
577             !epoxy_has_gl_extension("GL_ARB_texture_border_clamp")) {
578             ErrorF("GL_ARB_texture_border_clamp required\n");
579             goto fail;
580         }
581 
582         if (!glamor_check_instruction_count(gl_version))
583             goto fail;
584 
585         /* Glamor rendering assumes that platforms with GLSL 130+
586          * have instanced arrays, but this is not always the case.
587          * etnaviv offers GLSL 140 with OpenGL 2.1.
588          */
589         if (glamor_priv->glsl_version >= 130 &&
590             !epoxy_has_gl_extension("GL_ARB_instanced_arrays"))
591                 glamor_priv->glsl_version = 120;
592     } else {
593         if (gl_version < 20) {
594             ErrorF("Require Open GLES2.0 or later.\n");
595             goto fail;
596         }
597 
598         if (!epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) {
599             ErrorF("GL_EXT_texture_format_BGRA8888 required\n");
600             goto fail;
601         }
602 
603         if (!epoxy_has_gl_extension("GL_OES_texture_border_clamp")) {
604             ErrorF("GL_OES_texture_border_clamp required\n");
605             goto fail;
606         }
607     }
608 
609     if (!epoxy_has_gl_extension("GL_ARB_vertex_array_object") &&
610         !epoxy_has_gl_extension("GL_OES_vertex_array_object")) {
611         ErrorF("GL_{ARB,OES}_vertex_array_object required\n");
612         goto fail;
613     }
614 
615     glamor_priv->has_rw_pbo = FALSE;
616     if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
617         glamor_priv->has_rw_pbo = TRUE;
618 
619     glamor_priv->has_khr_debug = epoxy_has_gl_extension("GL_KHR_debug");
620     glamor_priv->has_pack_invert =
621         epoxy_has_gl_extension("GL_MESA_pack_invert");
622     glamor_priv->has_fbo_blit =
623         epoxy_has_gl_extension("GL_EXT_framebuffer_blit");
624     glamor_priv->has_map_buffer_range =
625         epoxy_has_gl_extension("GL_ARB_map_buffer_range") ||
626         epoxy_has_gl_extension("GL_EXT_map_buffer_range");
627     glamor_priv->has_buffer_storage =
628         epoxy_has_gl_extension("GL_ARB_buffer_storage");
629     glamor_priv->has_mesa_tile_raster_order =
630         epoxy_has_gl_extension("GL_MESA_tile_raster_order");
631     glamor_priv->has_nv_texture_barrier =
632         epoxy_has_gl_extension("GL_NV_texture_barrier");
633     glamor_priv->has_unpack_subimage =
634         glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP ||
635         epoxy_gl_version() >= 30 ||
636         epoxy_has_gl_extension("GL_EXT_unpack_subimage");
637     glamor_priv->has_pack_subimage =
638         glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP ||
639         epoxy_gl_version() >= 30 ||
640         epoxy_has_gl_extension("GL_NV_pack_subimage");
641     glamor_priv->has_dual_blend =
642         glamor_priv->glsl_version >= 130 &&
643         epoxy_has_gl_extension("GL_ARB_blend_func_extended");
644 
645     glamor_priv->can_copyplane = (gl_version >= 30);
646 
647     glamor_setup_debug_output(screen);
648 
649     glamor_priv->use_quads = (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) &&
650                              !glamor_priv->is_core_profile;
651 
652     /* Driver-specific hack: Avoid using GL_QUADS on VC4, where
653      * they'll be emulated more expensively than we can with our
654      * cached IB.
655      */
656     if (strstr((char *)glGetString(GL_VENDOR), "Broadcom") &&
657         (strstr((char *)glGetString(GL_RENDERER), "VC4") ||
658          strstr((char *)glGetString(GL_RENDERER), "V3D")))
659         glamor_priv->use_quads = FALSE;
660 
661     glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glamor_priv->max_fbo_size);
662     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glamor_priv->max_fbo_size);
663     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
664     glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[0]);
665     glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[1]);
666 #ifdef MAX_FBO_SIZE
667     glamor_priv->max_fbo_size = MAX_FBO_SIZE;
668 #endif
669 
670     glamor_priv->has_texture_swizzle =
671         (epoxy_has_gl_extension("GL_ARB_texture_swizzle") ||
672          (glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP && gl_version >= 30));
673 
674     glamor_priv->one_channel_format = GL_ALPHA;
675     if (epoxy_has_gl_extension("GL_ARB_texture_rg") &&
676         glamor_priv->has_texture_swizzle) {
677         glamor_priv->one_channel_format = GL_RED;
678     }
679 
680     glamor_set_debug_level(&glamor_debug_level);
681 
682     if (!glamor_font_init(screen))
683         goto fail;
684 
685     glamor_priv->saved_procs.block_handler = screen->BlockHandler;
686     screen->BlockHandler = _glamor_block_handler;
687 
688     if (!glamor_composite_glyphs_init(screen)) {
689         ErrorF("Failed to initialize composite masks\n");
690         goto fail;
691     }
692 
693     glamor_priv->saved_procs.create_gc = screen->CreateGC;
694     screen->CreateGC = glamor_create_gc;
695 
696     glamor_priv->saved_procs.create_pixmap = screen->CreatePixmap;
697     screen->CreatePixmap = glamor_create_pixmap;
698 
699     glamor_priv->saved_procs.get_spans = screen->GetSpans;
700     screen->GetSpans = glamor_get_spans;
701 
702     glamor_priv->saved_procs.get_image = screen->GetImage;
703     screen->GetImage = glamor_get_image;
704 
705     glamor_priv->saved_procs.change_window_attributes =
706         screen->ChangeWindowAttributes;
707     screen->ChangeWindowAttributes = glamor_change_window_attributes;
708 
709     glamor_priv->saved_procs.copy_window = screen->CopyWindow;
710     screen->CopyWindow = glamor_copy_window;
711 
712     glamor_priv->saved_procs.bitmap_to_region = screen->BitmapToRegion;
713     screen->BitmapToRegion = glamor_bitmap_to_region;
714 
715     glamor_priv->saved_procs.composite = ps->Composite;
716     ps->Composite = glamor_composite;
717 
718     glamor_priv->saved_procs.trapezoids = ps->Trapezoids;
719     ps->Trapezoids = glamor_trapezoids;
720 
721     glamor_priv->saved_procs.triangles = ps->Triangles;
722     ps->Triangles = glamor_triangles;
723 
724     glamor_priv->saved_procs.addtraps = ps->AddTraps;
725     ps->AddTraps = glamor_add_traps;
726 
727     glamor_priv->saved_procs.composite_rects = ps->CompositeRects;
728     ps->CompositeRects = glamor_composite_rectangles;
729 
730     glamor_priv->saved_procs.glyphs = ps->Glyphs;
731     ps->Glyphs = glamor_composite_glyphs;
732 
733     glamor_init_vbo(screen);
734     glamor_init_gradient_shader(screen);
735     glamor_pixmap_init(screen);
736     glamor_sync_init(screen);
737 
738     glamor_priv->screen = screen;
739 
740     return TRUE;
741 
742  fail:
743     /* Restore default CloseScreen and DestroyPixmap handlers */
744     screen->CloseScreen = glamor_priv->saved_procs.close_screen;
745     screen->DestroyPixmap = glamor_priv->saved_procs.destroy_pixmap;
746 
747  free_glamor_private:
748     free(glamor_priv);
749     glamor_set_screen_private(screen, NULL);
750     return FALSE;
751 }
752 
753 static void
glamor_release_screen_priv(ScreenPtr screen)754 glamor_release_screen_priv(ScreenPtr screen)
755 {
756     glamor_screen_private *glamor_priv;
757 
758     glamor_priv = glamor_get_screen_private(screen);
759     glamor_fini_vbo(screen);
760     glamor_pixmap_fini(screen);
761     free(glamor_priv);
762 
763     glamor_set_screen_private(screen, NULL);
764 }
765 
766 Bool
glamor_close_screen(ScreenPtr screen)767 glamor_close_screen(ScreenPtr screen)
768 {
769     glamor_screen_private *glamor_priv;
770     PixmapPtr screen_pixmap;
771     PictureScreenPtr ps = GetPictureScreenIfSet(screen);
772 
773     glamor_priv = glamor_get_screen_private(screen);
774     glamor_sync_close(screen);
775     glamor_composite_glyphs_fini(screen);
776     screen->CloseScreen = glamor_priv->saved_procs.close_screen;
777 
778     screen->CreateGC = glamor_priv->saved_procs.create_gc;
779     screen->CreatePixmap = glamor_priv->saved_procs.create_pixmap;
780     screen->DestroyPixmap = glamor_priv->saved_procs.destroy_pixmap;
781     screen->GetSpans = glamor_priv->saved_procs.get_spans;
782     screen->ChangeWindowAttributes =
783         glamor_priv->saved_procs.change_window_attributes;
784     screen->CopyWindow = glamor_priv->saved_procs.copy_window;
785     screen->BitmapToRegion = glamor_priv->saved_procs.bitmap_to_region;
786     screen->BlockHandler = glamor_priv->saved_procs.block_handler;
787 
788     ps->Composite = glamor_priv->saved_procs.composite;
789     ps->Trapezoids = glamor_priv->saved_procs.trapezoids;
790     ps->Triangles = glamor_priv->saved_procs.triangles;
791     ps->CompositeRects = glamor_priv->saved_procs.composite_rects;
792     ps->Glyphs = glamor_priv->saved_procs.glyphs;
793 
794     screen_pixmap = screen->GetScreenPixmap(screen);
795     glamor_pixmap_destroy_fbo(screen_pixmap);
796 
797     glamor_release_screen_priv(screen);
798 
799     return screen->CloseScreen(screen);
800 }
801 
802 void
glamor_fini(ScreenPtr screen)803 glamor_fini(ScreenPtr screen)
804 {
805     /* Do nothing currently. */
806 }
807 
808 void
glamor_enable_dri3(ScreenPtr screen)809 glamor_enable_dri3(ScreenPtr screen)
810 {
811     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
812 
813     glamor_priv->dri3_enabled = TRUE;
814 }
815 
816 Bool
glamor_supports_pixmap_import_export(ScreenPtr screen)817 glamor_supports_pixmap_import_export(ScreenPtr screen)
818 {
819     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
820 
821     return glamor_priv->dri3_enabled;
822 }
823 
824 _X_EXPORT void
glamor_set_drawable_modifiers_func(ScreenPtr screen,GetDrawableModifiersFuncPtr func)825 glamor_set_drawable_modifiers_func(ScreenPtr screen,
826                                    GetDrawableModifiersFuncPtr func)
827 {
828     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
829 
830     glamor_priv->get_drawable_modifiers = func;
831 }
832 
833 _X_EXPORT Bool
glamor_get_drawable_modifiers(DrawablePtr draw,uint32_t format,uint32_t * num_modifiers,uint64_t ** modifiers)834 glamor_get_drawable_modifiers(DrawablePtr draw, uint32_t format,
835                               uint32_t *num_modifiers, uint64_t **modifiers)
836 {
837     struct glamor_screen_private *glamor_priv =
838         glamor_get_screen_private(draw->pScreen);
839 
840     if (glamor_priv->get_drawable_modifiers) {
841         return glamor_priv->get_drawable_modifiers(draw, format,
842                                                    num_modifiers, modifiers);
843     }
844     *num_modifiers = 0;
845     *modifiers = NULL;
846     return TRUE;
847 }
848 
849 static int
_glamor_fds_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,int * fds,uint32_t * strides,uint32_t * offsets,CARD32 * size,uint64_t * modifier)850 _glamor_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
851                         uint32_t *strides, uint32_t *offsets,
852                         CARD32 *size, uint64_t *modifier)
853 {
854     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
855     glamor_screen_private *glamor_priv =
856         glamor_get_screen_private(pixmap->drawable.pScreen);
857 
858     if (!glamor_priv->dri3_enabled)
859         return 0;
860     switch (pixmap_priv->type) {
861     case GLAMOR_TEXTURE_DRM:
862     case GLAMOR_TEXTURE_ONLY:
863         if (!glamor_pixmap_ensure_fbo(pixmap, pixmap->drawable.depth == 30 ?
864                                       GL_RGB10_A2 : GL_RGBA, 0))
865             return 0;
866 
867         if (modifier) {
868             return glamor_egl_fds_from_pixmap(screen, pixmap, fds,
869                                               strides, offsets,
870                                               modifier);
871         } else {
872             CARD16 stride;
873 
874             fds[0] = glamor_egl_fd_from_pixmap(screen, pixmap, &stride, size);
875             strides[0] = stride;
876 
877             return fds[0] >= 0;
878         }
879     default:
880         break;
881     }
882     return 0;
883 }
884 
885 _X_EXPORT int
glamor_fds_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,int * fds,uint32_t * strides,uint32_t * offsets,uint64_t * modifier)886 glamor_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
887                        uint32_t *strides, uint32_t *offsets,
888                        uint64_t *modifier)
889 {
890     return _glamor_fds_from_pixmap(screen, pixmap, fds, strides, offsets,
891                                    NULL, modifier);
892 }
893 
894 _X_EXPORT int
glamor_fd_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,CARD16 * stride,CARD32 * size)895 glamor_fd_from_pixmap(ScreenPtr screen,
896                       PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
897 {
898     int fd;
899     int ret;
900     uint32_t stride32;
901 
902     ret = _glamor_fds_from_pixmap(screen, pixmap, &fd, &stride32, NULL, size,
903                                   NULL);
904     if (ret != 1)
905         return -1;
906 
907     *stride = stride32;
908     return fd;
909 }
910 
911 _X_EXPORT int
glamor_shareable_fd_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,CARD16 * stride,CARD32 * size)912 glamor_shareable_fd_from_pixmap(ScreenPtr screen,
913                                 PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
914 {
915     unsigned orig_usage_hint = pixmap->usage_hint;
916     int ret;
917 
918     /*
919      * The actual difference between a sharable and non sharable buffer
920      * is decided 4 call levels deep in glamor_make_pixmap_exportable()
921      * based on pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED
922      * 2 of those calls are also exported API, so we cannot just add a flag.
923      */
924     pixmap->usage_hint = CREATE_PIXMAP_USAGE_SHARED;
925 
926     ret = glamor_fd_from_pixmap(screen, pixmap, stride, size);
927 
928     pixmap->usage_hint = orig_usage_hint;
929     return ret;
930 }
931 
932 int
glamor_name_from_pixmap(PixmapPtr pixmap,CARD16 * stride,CARD32 * size)933 glamor_name_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
934 {
935     glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
936 
937     switch (pixmap_priv->type) {
938     case GLAMOR_TEXTURE_DRM:
939     case GLAMOR_TEXTURE_ONLY:
940         if (!glamor_pixmap_ensure_fbo(pixmap, pixmap->drawable.depth == 30 ?
941                                       GL_RGB10_A2 : GL_RGBA, 0))
942             return -1;
943         return glamor_egl_fd_name_from_pixmap(pixmap->drawable.pScreen,
944                                               pixmap, stride, size);
945     default:
946         break;
947     }
948     return -1;
949 }
950 
951 void
glamor_finish(ScreenPtr screen)952 glamor_finish(ScreenPtr screen)
953 {
954     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
955 
956     glamor_make_current(glamor_priv);
957     glFinish();
958 }
959