"Fossies" - the Fresh Open Source Software Archive

Member "xorg-server-1.20.8/glamor/glamor.c" (29 Mar 2020, 31372 Bytes) of package /linux/misc/xorg-server-1.20.8.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "glamor.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.20.7_vs_1.20.8.

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