glamor.c revision 3517b66b
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
131uint32_t
132glamor_get_pixmap_texture(PixmapPtr pixmap)
133{
134    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
135
136    if (!pixmap_priv)
137        return 0;
138
139    if (!pixmap_priv->fbo)
140        return 0;
141
142    if (pixmap_priv->type != GLAMOR_TEXTURE_ONLY)
143        return 0;
144
145    return pixmap_priv->fbo->tex;
146}
147
148void
149glamor_bind_texture(glamor_screen_private *glamor_priv, GLenum texture,
150                    glamor_pixmap_fbo *fbo, Bool destination_red)
151{
152    glActiveTexture(texture);
153    glBindTexture(GL_TEXTURE_2D, fbo->tex);
154
155    /* If we're pulling data from a GL_RED texture, then whether we
156     * want to make it an A,0,0,0 result or a 0,0,0,R result depends
157     * on whether the destination is also a GL_RED texture.
158     *
159     * For GL_RED destinations, we need to leave the bits in the R
160     * channel. For all other destinations, we need to clear out the R
161     * channel so that it returns zero for R, G and B.
162     *
163     * Note that we're leaving the SWIZZLE_A value alone; for GL_RED
164     * destinations, that means we'll actually be returning R,0,0,R,
165     * but it doesn't matter as the bits in the alpha channel aren't
166     * going anywhere.
167     */
168
169    /* Is the operand a GL_RED fbo?
170     */
171
172    if (glamor_fbo_red_is_alpha(glamor_priv, fbo)) {
173
174        /* If destination is also GL_RED, then preserve the bits in
175         * the R channel */
176
177        if (destination_red)
178            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
179        else
180            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ZERO);
181    }
182}
183
184PixmapPtr
185glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
186                     unsigned int usage)
187{
188    PixmapPtr pixmap;
189    glamor_pixmap_private *pixmap_priv;
190    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
191    glamor_pixmap_fbo *fbo = NULL;
192    int pitch;
193    GLenum format;
194
195    if (w > 32767 || h > 32767)
196        return NullPixmap;
197
198    if ((usage == GLAMOR_CREATE_PIXMAP_CPU
199         || (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE &&
200             w <= glamor_priv->glyph_max_dim &&
201             h <= glamor_priv->glyph_max_dim)
202         || (w == 0 && h == 0)
203         || !glamor_check_pixmap_fbo_depth(depth)))
204        return fbCreatePixmap(screen, w, h, depth, usage);
205    else
206        pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
207
208    pixmap_priv = glamor_get_pixmap_private(pixmap);
209
210    format = gl_iformat_for_pixmap(pixmap);
211
212    pitch = (((w * pixmap->drawable.bitsPerPixel + 7) / 8) + 3) & ~3;
213    screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, pitch, NULL);
214
215    pixmap_priv->type = GLAMOR_TEXTURE_ONLY;
216
217    if (usage == GLAMOR_CREATE_PIXMAP_NO_TEXTURE) {
218        glamor_init_pixmap_private_small(pixmap, pixmap_priv);
219        return pixmap;
220    }
221    else if (usage == GLAMOR_CREATE_NO_LARGE ||
222        glamor_check_fbo_size(glamor_priv, w, h))
223    {
224        glamor_init_pixmap_private_small(pixmap, pixmap_priv);
225        fbo = glamor_create_fbo(glamor_priv, w, h, format, usage);
226    } else {
227        int tile_size = glamor_priv->max_fbo_size;
228        DEBUGF("Create LARGE pixmap %p width %d height %d, tile size %d\n",
229               pixmap, w, h, tile_size);
230        fbo = glamor_create_fbo_array(glamor_priv, w, h, format, usage,
231                                      tile_size, tile_size, pixmap_priv);
232    }
233
234    if (fbo == NULL) {
235        fbDestroyPixmap(pixmap);
236        return fbCreatePixmap(screen, w, h, depth, usage);
237    }
238
239    glamor_pixmap_attach_fbo(pixmap, fbo);
240
241    return pixmap;
242}
243
244Bool
245glamor_destroy_pixmap(PixmapPtr pixmap)
246{
247    if (pixmap->refcnt == 1) {
248        glamor_pixmap_destroy_fbo(pixmap);
249    }
250
251    return fbDestroyPixmap(pixmap);
252}
253
254void
255glamor_block_handler(ScreenPtr screen)
256{
257    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
258
259    glamor_make_current(glamor_priv);
260    glFlush();
261}
262
263static void
264_glamor_block_handler(ScreenPtr screen, void *timeout)
265{
266    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
267
268    glamor_make_current(glamor_priv);
269    glFlush();
270
271    screen->BlockHandler = glamor_priv->saved_procs.block_handler;
272    screen->BlockHandler(screen, timeout);
273    glamor_priv->saved_procs.block_handler = screen->BlockHandler;
274    screen->BlockHandler = _glamor_block_handler;
275}
276
277static void
278glamor_set_debug_level(int *debug_level)
279{
280    char *debug_level_string;
281
282    debug_level_string = getenv("GLAMOR_DEBUG");
283    if (debug_level_string
284        && sscanf(debug_level_string, "%d", debug_level) == 1)
285        return;
286    *debug_level = 0;
287}
288
289int glamor_debug_level;
290
291void
292glamor_gldrawarrays_quads_using_indices(glamor_screen_private *glamor_priv,
293                                        unsigned count)
294{
295    unsigned i;
296
297    /* For a single quad, don't bother with an index buffer. */
298    if (count ==  1)
299        goto fallback;
300
301    if (glamor_priv->ib_size < count) {
302        /* Basic GLES2 doesn't have any way to map buffer objects for
303         * writing, but it's long past time for drivers to have
304         * MapBufferRange.
305         */
306        if (!glamor_priv->has_map_buffer_range)
307            goto fallback;
308
309        /* Lazy create the buffer name, and only bind it once since
310         * none of the glamor code binds it to anything else.
311         */
312        if (!glamor_priv->ib) {
313            glGenBuffers(1, &glamor_priv->ib);
314            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ib);
315        }
316
317        /* For now, only support GL_UNSIGNED_SHORTs. */
318        if (count > ((1 << 16) - 1) / 4) {
319            goto fallback;
320        } else {
321            uint16_t *data;
322            size_t size = count * 6 * sizeof(GLushort);
323
324            glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, NULL, GL_STATIC_DRAW);
325            data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,
326                                    0, size,
327                                    GL_MAP_WRITE_BIT |
328                                    GL_MAP_INVALIDATE_BUFFER_BIT);
329            for (i = 0; i < count; i++) {
330                data[i * 6 + 0] = i * 4 + 0;
331                data[i * 6 + 1] = i * 4 + 1;
332                data[i * 6 + 2] = i * 4 + 2;
333                data[i * 6 + 3] = i * 4 + 0;
334                data[i * 6 + 4] = i * 4 + 2;
335                data[i * 6 + 5] = i * 4 + 3;
336            }
337            glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
338
339            glamor_priv->ib_size = count;
340            glamor_priv->ib_type = GL_UNSIGNED_SHORT;
341        }
342    }
343
344    glDrawElements(GL_TRIANGLES, count * 6, glamor_priv->ib_type, NULL);
345    return;
346
347fallback:
348    for (i = 0; i < count; i++)
349        glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4);
350}
351
352
353static Bool
354glamor_check_instruction_count(int gl_version)
355{
356    GLint max_native_alu_instructions;
357
358    /* Avoid using glamor if the reported instructions limit is too low,
359     * as this would cause glamor to fallback on sw due to large shaders
360     * which ends up being unbearably slow.
361     */
362    if (gl_version < 30) {
363        if (!epoxy_has_gl_extension("GL_ARB_fragment_program")) {
364            ErrorF("GL_ARB_fragment_program required\n");
365            return FALSE;
366        }
367
368        glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
369                          GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB,
370                          &max_native_alu_instructions);
371        if (max_native_alu_instructions < GLAMOR_MIN_ALU_INSTRUCTIONS) {
372            LogMessage(X_WARNING,
373                       "glamor requires at least %d instructions (%d reported)\n",
374                       GLAMOR_MIN_ALU_INSTRUCTIONS, max_native_alu_instructions);
375            return FALSE;
376        }
377    }
378
379    return TRUE;
380}
381
382static void GLAPIENTRY
383glamor_debug_output_callback(GLenum source,
384                             GLenum type,
385                             GLuint id,
386                             GLenum severity,
387                             GLsizei length,
388                             const GLchar *message,
389                             const void *userParam)
390{
391    ScreenPtr screen = (void *)userParam;
392    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
393
394    if (glamor_priv->suppress_gl_out_of_memory_logging &&
395        source == GL_DEBUG_SOURCE_API && type == GL_DEBUG_TYPE_ERROR) {
396        return;
397    }
398
399    LogMessageVerb(X_ERROR, 0, "glamor%d: GL error: %*s\n",
400               screen->myNum, length, message);
401}
402
403/**
404 * Configures GL_ARB_debug_output to give us immediate callbacks when
405 * GL errors occur, so that we can log them.
406 */
407static void
408glamor_setup_debug_output(ScreenPtr screen)
409{
410    if (!epoxy_has_gl_extension("GL_ARB_debug_output"))
411        return;
412
413    glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
414    /* Disable debugging messages other than GL API errors */
415    glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL,
416                          GL_FALSE);
417    glDebugMessageControl(GL_DEBUG_SOURCE_API,
418                          GL_DEBUG_TYPE_ERROR,
419                          GL_DONT_CARE,
420                          0, NULL, GL_TRUE);
421    glDebugMessageCallback(glamor_debug_output_callback,
422                           screen);
423
424    /* If KHR_debug is present, all debug output is disabled by
425     * default on non-debug contexts.
426     */
427    if (epoxy_has_gl_extension("GL_KHR_debug"))
428        glEnable(GL_DEBUG_OUTPUT);
429}
430
431/** Set up glamor for an already-configured GL context. */
432Bool
433glamor_init(ScreenPtr screen, unsigned int flags)
434{
435    glamor_screen_private *glamor_priv;
436    int gl_version;
437    int glsl_major, glsl_minor;
438    int max_viewport_size[2];
439    const char *shading_version_string;
440    int shading_version_offset;
441
442    PictureScreenPtr ps = GetPictureScreenIfSet(screen);
443
444    if (flags & ~GLAMOR_VALID_FLAGS) {
445        ErrorF("glamor_init: Invalid flags %x\n", flags);
446        return FALSE;
447    }
448    glamor_priv = calloc(1, sizeof(*glamor_priv));
449    if (glamor_priv == NULL)
450        return FALSE;
451
452    glamor_priv->flags = flags;
453
454    if (!dixRegisterPrivateKey(&glamor_screen_private_key, PRIVATE_SCREEN, 0)) {
455        LogMessage(X_WARNING,
456                   "glamor%d: Failed to allocate screen private\n",
457                   screen->myNum);
458        goto free_glamor_private;
459    }
460
461    glamor_set_screen_private(screen, glamor_priv);
462
463    if (!dixRegisterPrivateKey(&glamor_pixmap_private_key, PRIVATE_PIXMAP,
464                               sizeof(struct glamor_pixmap_private))) {
465        LogMessage(X_WARNING,
466                   "glamor%d: Failed to allocate pixmap private\n",
467                   screen->myNum);
468        goto free_glamor_private;
469    }
470
471    if (!dixRegisterPrivateKey(&glamor_gc_private_key, PRIVATE_GC,
472                               sizeof (glamor_gc_private))) {
473        LogMessage(X_WARNING,
474                   "glamor%d: Failed to allocate gc private\n",
475                   screen->myNum);
476        goto free_glamor_private;
477    }
478
479    glamor_priv->saved_procs.close_screen = screen->CloseScreen;
480    screen->CloseScreen = glamor_close_screen;
481
482    glamor_priv->saved_procs.destroy_pixmap = screen->DestroyPixmap;
483    screen->DestroyPixmap = glamor_destroy_pixmap;
484
485    /* If we are using egl screen, call egl screen init to
486     * register correct close screen function. */
487    if (flags & GLAMOR_USE_EGL_SCREEN) {
488        glamor_egl_screen_init(screen, &glamor_priv->ctx);
489    } else {
490        if (!glamor_glx_screen_init(&glamor_priv->ctx))
491            goto fail;
492    }
493
494    glamor_make_current(glamor_priv);
495
496    if (epoxy_is_desktop_gl())
497        glamor_priv->gl_flavor = GLAMOR_GL_DESKTOP;
498    else
499        glamor_priv->gl_flavor = GLAMOR_GL_ES2;
500
501    gl_version = epoxy_gl_version();
502
503    /* assume a core profile if we are GL 3.1 and don't have ARB_compatibility */
504    glamor_priv->is_core_profile =
505        gl_version >= 31 && !epoxy_has_gl_extension("GL_ARB_compatibility");
506
507    shading_version_string = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
508
509    if (!shading_version_string) {
510        LogMessage(X_WARNING,
511                   "glamor%d: Failed to get GLSL version\n",
512                   screen->myNum);
513        goto fail;
514    }
515
516    shading_version_offset = 0;
517    if (strncmp("OpenGL ES GLSL ES ", shading_version_string, 18) == 0)
518        shading_version_offset = 18;
519
520    if (sscanf(shading_version_string + shading_version_offset,
521               "%i.%i",
522               &glsl_major,
523               &glsl_minor) != 2) {
524        LogMessage(X_WARNING,
525                   "glamor%d: Failed to parse GLSL version string %s\n",
526                   screen->myNum, shading_version_string);
527        goto fail;
528    }
529    glamor_priv->glsl_version = glsl_major * 100 + glsl_minor;
530
531    if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
532        /* Force us back to the base version of our programs on an ES
533         * context, anyway.  Basically glamor only uses desktop 1.20
534         * or 1.30 currently.  1.30's new features are also present in
535         * ES 3.0, but our glamor_program.c constructions use a lot of
536         * compatibility features (to reduce the diff between 1.20 and
537         * 1.30 programs).
538         */
539        glamor_priv->glsl_version = 120;
540    }
541
542    /* We'd like to require GL_ARB_map_buffer_range or
543     * GL_OES_map_buffer_range, since it offers more information to
544     * the driver than plain old glMapBuffer() or glBufferSubData().
545     * It's been supported on Mesa on the desktop since 2009 and on
546     * GLES2 since October 2012.  It's supported on Apple's iOS
547     * drivers for SGX535 and A7, but apparently not on most Android
548     * devices (the OES extension spec wasn't released until June
549     * 2012).
550     *
551     * 82% of 0 A.D. players (desktop GL) submitting hardware reports
552     * have support for it, with most of the ones lacking it being on
553     * Windows with Intel 4-series (G45) graphics or older.
554     */
555    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
556        if (gl_version < 21) {
557            ErrorF("Require OpenGL version 2.1 or later.\n");
558            goto fail;
559        }
560
561        if (!glamor_priv->is_core_profile &&
562            !epoxy_has_gl_extension("GL_ARB_texture_border_clamp")) {
563            ErrorF("GL_ARB_texture_border_clamp required\n");
564            goto fail;
565        }
566
567        if (!glamor_check_instruction_count(gl_version))
568            goto fail;
569
570        /* Glamor rendering assumes that platforms with GLSL 130+
571         * have instanced arrays, but this is not always the case.
572         * etnaviv offers GLSL 140 with OpenGL 2.1.
573         */
574        if (glamor_priv->glsl_version >= 130 &&
575            !epoxy_has_gl_extension("GL_ARB_instanced_arrays"))
576                glamor_priv->glsl_version = 120;
577    } else {
578        if (gl_version < 20) {
579            ErrorF("Require Open GLES2.0 or later.\n");
580            goto fail;
581        }
582
583        if (!epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) {
584            ErrorF("GL_EXT_texture_format_BGRA8888 required\n");
585            goto fail;
586        }
587
588        if (!epoxy_has_gl_extension("GL_OES_texture_border_clamp")) {
589            ErrorF("GL_OES_texture_border_clamp required\n");
590            goto fail;
591        }
592    }
593
594    if (!epoxy_has_gl_extension("GL_ARB_vertex_array_object") &&
595        !epoxy_has_gl_extension("GL_OES_vertex_array_object")) {
596        ErrorF("GL_{ARB,OES}_vertex_array_object required\n");
597        goto fail;
598    }
599
600    glamor_priv->has_rw_pbo = FALSE;
601    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
602        glamor_priv->has_rw_pbo = TRUE;
603
604    glamor_priv->has_khr_debug = epoxy_has_gl_extension("GL_KHR_debug");
605    glamor_priv->has_pack_invert =
606        epoxy_has_gl_extension("GL_MESA_pack_invert");
607    glamor_priv->has_fbo_blit =
608        epoxy_has_gl_extension("GL_EXT_framebuffer_blit");
609    glamor_priv->has_map_buffer_range =
610        epoxy_has_gl_extension("GL_ARB_map_buffer_range") ||
611        epoxy_has_gl_extension("GL_EXT_map_buffer_range");
612    glamor_priv->has_buffer_storage =
613        epoxy_has_gl_extension("GL_ARB_buffer_storage");
614    glamor_priv->has_mesa_tile_raster_order =
615        epoxy_has_gl_extension("GL_MESA_tile_raster_order");
616    glamor_priv->has_nv_texture_barrier =
617        epoxy_has_gl_extension("GL_NV_texture_barrier");
618    glamor_priv->has_unpack_subimage =
619        glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP ||
620        epoxy_gl_version() >= 30 ||
621        epoxy_has_gl_extension("GL_EXT_unpack_subimage");
622    glamor_priv->has_pack_subimage =
623        glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP ||
624        epoxy_gl_version() >= 30 ||
625        epoxy_has_gl_extension("GL_NV_pack_subimage");
626    glamor_priv->has_dual_blend =
627        epoxy_has_gl_extension("GL_ARB_blend_func_extended");
628
629    glamor_priv->can_copyplane = (gl_version >= 30);
630
631    glamor_setup_debug_output(screen);
632
633    glamor_priv->use_quads = (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) &&
634                             !glamor_priv->is_core_profile;
635
636    /* Driver-specific hack: Avoid using GL_QUADS on VC4, where
637     * they'll be emulated more expensively than we can with our
638     * cached IB.
639     */
640    if (strstr((char *)glGetString(GL_VENDOR), "Broadcom") &&
641        strstr((char *)glGetString(GL_RENDERER), "VC4"))
642        glamor_priv->use_quads = FALSE;
643
644    glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glamor_priv->max_fbo_size);
645    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glamor_priv->max_fbo_size);
646    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
647    glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[0]);
648    glamor_priv->max_fbo_size = MIN(glamor_priv->max_fbo_size, max_viewport_size[1]);
649#ifdef MAX_FBO_SIZE
650    glamor_priv->max_fbo_size = MAX_FBO_SIZE;
651#endif
652
653    glamor_priv->has_texture_swizzle =
654        (epoxy_has_gl_extension("GL_ARB_texture_swizzle") ||
655         (glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP && gl_version >= 30));
656
657    glamor_priv->one_channel_format = GL_ALPHA;
658    if (epoxy_has_gl_extension("GL_ARB_texture_rg") &&
659        glamor_priv->has_texture_swizzle) {
660        glamor_priv->one_channel_format = GL_RED;
661    }
662
663    glamor_set_debug_level(&glamor_debug_level);
664
665    if (!glamor_font_init(screen))
666        goto fail;
667
668    glamor_priv->saved_procs.block_handler = screen->BlockHandler;
669    screen->BlockHandler = _glamor_block_handler;
670
671    if (!glamor_composite_glyphs_init(screen)) {
672        ErrorF("Failed to initialize composite masks\n");
673        goto fail;
674    }
675
676    glamor_priv->saved_procs.create_gc = screen->CreateGC;
677    screen->CreateGC = glamor_create_gc;
678
679    glamor_priv->saved_procs.create_pixmap = screen->CreatePixmap;
680    screen->CreatePixmap = glamor_create_pixmap;
681
682    glamor_priv->saved_procs.get_spans = screen->GetSpans;
683    screen->GetSpans = glamor_get_spans;
684
685    glamor_priv->saved_procs.get_image = screen->GetImage;
686    screen->GetImage = glamor_get_image;
687
688    glamor_priv->saved_procs.change_window_attributes =
689        screen->ChangeWindowAttributes;
690    screen->ChangeWindowAttributes = glamor_change_window_attributes;
691
692    glamor_priv->saved_procs.copy_window = screen->CopyWindow;
693    screen->CopyWindow = glamor_copy_window;
694
695    glamor_priv->saved_procs.bitmap_to_region = screen->BitmapToRegion;
696    screen->BitmapToRegion = glamor_bitmap_to_region;
697
698    glamor_priv->saved_procs.composite = ps->Composite;
699    ps->Composite = glamor_composite;
700
701    glamor_priv->saved_procs.trapezoids = ps->Trapezoids;
702    ps->Trapezoids = glamor_trapezoids;
703
704    glamor_priv->saved_procs.triangles = ps->Triangles;
705    ps->Triangles = glamor_triangles;
706
707    glamor_priv->saved_procs.addtraps = ps->AddTraps;
708    ps->AddTraps = glamor_add_traps;
709
710    glamor_priv->saved_procs.composite_rects = ps->CompositeRects;
711    ps->CompositeRects = glamor_composite_rectangles;
712
713    glamor_priv->saved_procs.glyphs = ps->Glyphs;
714    ps->Glyphs = glamor_composite_glyphs;
715
716    glamor_init_vbo(screen);
717    glamor_init_gradient_shader(screen);
718    glamor_pixmap_init(screen);
719    glamor_sync_init(screen);
720
721    glamor_priv->screen = screen;
722
723    return TRUE;
724
725 fail:
726    /* Restore default CloseScreen and DestroyPixmap handlers */
727    screen->CloseScreen = glamor_priv->saved_procs.close_screen;
728    screen->DestroyPixmap = glamor_priv->saved_procs.destroy_pixmap;
729
730 free_glamor_private:
731    free(glamor_priv);
732    glamor_set_screen_private(screen, NULL);
733    return FALSE;
734}
735
736static void
737glamor_release_screen_priv(ScreenPtr screen)
738{
739    glamor_screen_private *glamor_priv;
740
741    glamor_priv = glamor_get_screen_private(screen);
742    glamor_fini_vbo(screen);
743    glamor_pixmap_fini(screen);
744    free(glamor_priv);
745
746    glamor_set_screen_private(screen, NULL);
747}
748
749Bool
750glamor_close_screen(ScreenPtr screen)
751{
752    glamor_screen_private *glamor_priv;
753    PixmapPtr screen_pixmap;
754    PictureScreenPtr ps = GetPictureScreenIfSet(screen);
755
756    glamor_priv = glamor_get_screen_private(screen);
757    glamor_sync_close(screen);
758    glamor_composite_glyphs_fini(screen);
759    screen->CloseScreen = glamor_priv->saved_procs.close_screen;
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 void
808glamor_set_drawable_modifiers_func(ScreenPtr screen,
809                                   GetDrawableModifiersFuncPtr func)
810{
811    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
812
813    glamor_priv->get_drawable_modifiers = func;
814}
815
816_X_EXPORT Bool
817glamor_get_drawable_modifiers(DrawablePtr draw, uint32_t format,
818                              uint32_t *num_modifiers, uint64_t **modifiers)
819{
820    struct glamor_screen_private *glamor_priv =
821        glamor_get_screen_private(draw->pScreen);
822
823    if (glamor_priv->get_drawable_modifiers) {
824        return glamor_priv->get_drawable_modifiers(draw, format,
825                                                   num_modifiers, modifiers);
826    }
827    *num_modifiers = 0;
828    *modifiers = NULL;
829    return TRUE;
830}
831
832static int
833_glamor_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
834                        uint32_t *strides, uint32_t *offsets,
835                        CARD32 *size, uint64_t *modifier)
836{
837    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
838    glamor_screen_private *glamor_priv =
839        glamor_get_screen_private(pixmap->drawable.pScreen);
840
841    if (!glamor_priv->dri3_enabled)
842        return 0;
843    switch (pixmap_priv->type) {
844    case GLAMOR_TEXTURE_DRM:
845    case GLAMOR_TEXTURE_ONLY:
846        if (!glamor_pixmap_ensure_fbo(pixmap, pixmap->drawable.depth == 30 ?
847                                      GL_RGB10_A2 : GL_RGBA, 0))
848            return 0;
849
850        if (modifier) {
851            return glamor_egl_fds_from_pixmap(screen, pixmap, fds,
852                                              strides, offsets,
853                                              modifier);
854        } else {
855            CARD16 stride;
856
857            fds[0] = glamor_egl_fd_from_pixmap(screen, pixmap, &stride, size);
858            strides[0] = stride;
859
860            return fds[0] >= 0;
861        }
862    default:
863        break;
864    }
865    return 0;
866}
867
868_X_EXPORT int
869glamor_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds,
870                       uint32_t *strides, uint32_t *offsets,
871                       uint64_t *modifier)
872{
873    return _glamor_fds_from_pixmap(screen, pixmap, fds, strides, offsets,
874                                   NULL, modifier);
875}
876
877_X_EXPORT int
878glamor_fd_from_pixmap(ScreenPtr screen,
879                      PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
880{
881    int fd;
882    int ret;
883    uint32_t stride32;
884
885    ret = _glamor_fds_from_pixmap(screen, pixmap, &fd, &stride32, NULL, size,
886                                  NULL);
887    if (ret != 1)
888        return -1;
889
890    *stride = stride32;
891    return fd;
892}
893
894_X_EXPORT int
895glamor_shareable_fd_from_pixmap(ScreenPtr screen,
896                                PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
897{
898    unsigned orig_usage_hint = pixmap->usage_hint;
899    int ret;
900
901    /*
902     * The actual difference between a sharable and non sharable buffer
903     * is decided 4 call levels deep in glamor_make_pixmap_exportable()
904     * based on pixmap->usage_hint == CREATE_PIXMAP_USAGE_SHARED
905     * 2 of those calls are also exported API, so we cannot just add a flag.
906     */
907    pixmap->usage_hint = CREATE_PIXMAP_USAGE_SHARED;
908
909    ret = glamor_fd_from_pixmap(screen, pixmap, stride, size);
910
911    pixmap->usage_hint = orig_usage_hint;
912    return ret;
913}
914
915int
916glamor_name_from_pixmap(PixmapPtr pixmap, CARD16 *stride, CARD32 *size)
917{
918    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
919
920    switch (pixmap_priv->type) {
921    case GLAMOR_TEXTURE_DRM:
922    case GLAMOR_TEXTURE_ONLY:
923        if (!glamor_pixmap_ensure_fbo(pixmap, pixmap->drawable.depth == 30 ?
924                                      GL_RGB10_A2 : GL_RGBA, 0))
925            return -1;
926        return glamor_egl_fd_name_from_pixmap(pixmap->drawable.pScreen,
927                                              pixmap, stride, size);
928    default:
929        break;
930    }
931    return -1;
932}
933
934void
935glamor_finish(ScreenPtr screen)
936{
937    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
938
939    glamor_make_current(glamor_priv);
940    glFinish();
941}
942