glamor.c revision a035e2b2
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
40DevPrivateKeyRec glamor_screen_private_key;
41DevPrivateKeyRec glamor_pixmap_private_key;
42DevPrivateKeyRec glamor_gc_private_key;
43
44glamor_screen_private *
45glamor_get_screen_private(ScreenPtr screen)
46{
47    return (glamor_screen_private *)
48        dixLookupPrivate(&screen->devPrivates, &glamor_screen_private_key);
49}
50
51void
52glamor_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 */
68PixmapPtr
69glamor_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
77static void
78glamor_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
93glamor_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
103glamor_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
132glamor_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
146uint32_t
147glamor_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
163void
164glamor_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
199PixmapPtr
200glamor_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
259Bool
260glamor_destroy_pixmap(PixmapPtr pixmap)
261{
262    if (pixmap->refcnt == 1) {
263        glamor_pixmap_destroy_fbo(pixmap);
264    }
265
266    return fbDestroyPixmap(pixmap);
267}
268
269void
270glamor_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
278static void
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
292static void
293glamor_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
304int glamor_debug_level;
305
306void
307glamor_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
362fallback:
363    for (i = 0; i < count; i++)
364        glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4);
365}
366
367
368static Bool
369glamor_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
397static void GLAPIENTRY
398glamor_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 */
422static void
423glamor_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. */
447Bool
448glamor_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
753static void
754glamor_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
766Bool
767glamor_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
802void
803glamor_fini(ScreenPtr screen)
804{
805    /* Do nothing currently. */
806}
807
808void
809glamor_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
816Bool
817glamor_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
825glamor_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
834glamor_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
849static int
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
886glamor_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
895glamor_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
912glamor_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
932int
933glamor_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
951void
952glamor_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