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