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