xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

glamor_fbo.c (11389B)


      1 /*
      2  * Copyright © 2009 Intel Corporation
      3  * Copyright © 1998 Keith Packard
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     22  * IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Zhigang Gong <zhigang.gong@gmail.com>
     26  *
     27  */
     28 
     29 #include <stdlib.h>
     30 
     31 #include "glamor_priv.h"
     32 
     33 void
     34 glamor_destroy_fbo(glamor_screen_private *glamor_priv,
     35                    glamor_pixmap_fbo *fbo)
     36 {
     37     glamor_make_current(glamor_priv);
     38 
     39     if (fbo->fb)
     40         glDeleteFramebuffers(1, &fbo->fb);
     41     if (fbo->tex)
     42         glDeleteTextures(1, &fbo->tex);
     43 
     44     free(fbo);
     45 }
     46 
     47 static int
     48 glamor_pixmap_ensure_fb(glamor_screen_private *glamor_priv,
     49                         glamor_pixmap_fbo *fbo)
     50 {
     51     int status, err = 0;
     52 
     53     glamor_make_current(glamor_priv);
     54 
     55     if (fbo->fb == 0)
     56         glGenFramebuffers(1, &fbo->fb);
     57     assert(fbo->tex != 0);
     58     glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
     59     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
     60                            GL_TEXTURE_2D, fbo->tex, 0);
     61     status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
     62     if (status != GL_FRAMEBUFFER_COMPLETE) {
     63         const char *str;
     64 
     65         switch (status) {
     66         case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
     67             str = "incomplete attachment";
     68             break;
     69         case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
     70             str = "incomplete/missing attachment";
     71             break;
     72         case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
     73             str = "incomplete draw buffer";
     74             break;
     75         case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
     76             str = "incomplete read buffer";
     77             break;
     78         case GL_FRAMEBUFFER_UNSUPPORTED:
     79             str = "unsupported";
     80             break;
     81         case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
     82             str = "incomplete multiple";
     83             break;
     84         default:
     85             str = "unknown error";
     86             break;
     87         }
     88 
     89         glamor_fallback("glamor: Failed to create fbo, %s\n", str);
     90         err = -1;
     91     }
     92 
     93     return err;
     94 }
     95 
     96 glamor_pixmap_fbo *
     97 glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
     98                            PixmapPtr pixmap, int w, int h, GLint tex, int flag)
     99 {
    100     const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
    101     glamor_pixmap_fbo *fbo;
    102 
    103     fbo = calloc(1, sizeof(*fbo));
    104     if (fbo == NULL)
    105         return NULL;
    106 
    107     fbo->tex = tex;
    108     fbo->width = w;
    109     fbo->height = h;
    110     fbo->is_red = f->format == GL_RED;
    111 
    112     if (flag != GLAMOR_CREATE_FBO_NO_FBO) {
    113         if (glamor_pixmap_ensure_fb(glamor_priv, fbo) != 0) {
    114             glamor_destroy_fbo(glamor_priv, fbo);
    115             fbo = NULL;
    116         }
    117     }
    118 
    119     return fbo;
    120 }
    121 
    122 static int
    123 _glamor_create_tex(glamor_screen_private *glamor_priv,
    124                    PixmapPtr pixmap, int w, int h)
    125 {
    126     const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
    127     unsigned int tex;
    128 
    129     glamor_make_current(glamor_priv);
    130     glGenTextures(1, &tex);
    131     glBindTexture(GL_TEXTURE_2D, tex);
    132     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    133     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    134     if (f->format == GL_RED)
    135         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
    136     glamor_priv->suppress_gl_out_of_memory_logging = true;
    137     glTexImage2D(GL_TEXTURE_2D, 0, f->internalformat, w, h, 0,
    138                  f->format, f->type, NULL);
    139     glamor_priv->suppress_gl_out_of_memory_logging = false;
    140 
    141     if (glGetError() == GL_OUT_OF_MEMORY) {
    142         if (!glamor_priv->logged_any_fbo_allocation_failure) {
    143             LogMessageVerb(X_WARNING, 0, "glamor: Failed to allocate %dx%d "
    144                            "FBO due to GL_OUT_OF_MEMORY.\n", w, h);
    145             LogMessageVerb(X_WARNING, 0,
    146                            "glamor: Expect reduced performance.\n");
    147             glamor_priv->logged_any_fbo_allocation_failure = true;
    148         }
    149         glDeleteTextures(1, &tex);
    150         return 0;
    151     }
    152 
    153     return tex;
    154 }
    155 
    156 glamor_pixmap_fbo *
    157 glamor_create_fbo(glamor_screen_private *glamor_priv,
    158                   PixmapPtr pixmap, int w, int h, int flag)
    159 {
    160     GLint tex = _glamor_create_tex(glamor_priv, pixmap, w, h);
    161 
    162     if (!tex) /* Texture creation failed due to GL_OUT_OF_MEMORY */
    163         return NULL;
    164 
    165     return glamor_create_fbo_from_tex(glamor_priv, pixmap, w, h,
    166                                       tex, flag);
    167 }
    168 
    169 /**
    170  * Create storage for the w * h region, using FBOs of the GL's maximum
    171  * supported size.
    172  */
    173 glamor_pixmap_fbo *
    174 glamor_create_fbo_array(glamor_screen_private *glamor_priv,
    175                         PixmapPtr pixmap, int flag,
    176                          int block_w, int block_h,
    177                          glamor_pixmap_private *priv)
    178 {
    179     int w = pixmap->drawable.width;
    180     int h = pixmap->drawable.height;
    181     int block_wcnt;
    182     int block_hcnt;
    183     glamor_pixmap_fbo **fbo_array;
    184     BoxPtr box_array;
    185     int i, j;
    186 
    187     priv->block_w = block_w;
    188     priv->block_h = block_h;
    189 
    190     block_wcnt = (w + block_w - 1) / block_w;
    191     block_hcnt = (h + block_h - 1) / block_h;
    192 
    193     box_array = calloc(block_wcnt * block_hcnt, sizeof(box_array[0]));
    194     if (box_array == NULL)
    195         return NULL;
    196 
    197     fbo_array = calloc(block_wcnt * block_hcnt, sizeof(glamor_pixmap_fbo *));
    198     if (fbo_array == NULL) {
    199         free(box_array);
    200         return FALSE;
    201     }
    202     for (i = 0; i < block_hcnt; i++) {
    203         int block_y1, block_y2;
    204         int fbo_w, fbo_h;
    205 
    206         block_y1 = i * block_h;
    207         block_y2 = (block_y1 + block_h) > h ? h : (block_y1 + block_h);
    208         fbo_h = block_y2 - block_y1;
    209 
    210         for (j = 0; j < block_wcnt; j++) {
    211             box_array[i * block_wcnt + j].x1 = j * block_w;
    212             box_array[i * block_wcnt + j].y1 = block_y1;
    213             box_array[i * block_wcnt + j].x2 =
    214                 (j + 1) * block_w > w ? w : (j + 1) * block_w;
    215             box_array[i * block_wcnt + j].y2 = block_y2;
    216             fbo_w =
    217                 box_array[i * block_wcnt + j].x2 - box_array[i * block_wcnt +
    218                                                              j].x1;
    219             fbo_array[i * block_wcnt + j] = glamor_create_fbo(glamor_priv,
    220                                                               pixmap,
    221                                                               fbo_w, fbo_h,
    222                                                               GLAMOR_CREATE_PIXMAP_FIXUP);
    223             if (fbo_array[i * block_wcnt + j] == NULL)
    224                 goto cleanup;
    225         }
    226     }
    227 
    228     priv->box = box_array[0];
    229     priv->box_array = box_array;
    230     priv->fbo_array = fbo_array;
    231     priv->block_wcnt = block_wcnt;
    232     priv->block_hcnt = block_hcnt;
    233     return fbo_array[0];
    234 
    235  cleanup:
    236     for (i = 0; i < block_wcnt * block_hcnt; i++)
    237         if (fbo_array[i])
    238             glamor_destroy_fbo(glamor_priv, fbo_array[i]);
    239     free(box_array);
    240     free(fbo_array);
    241     return NULL;
    242 }
    243 
    244 void
    245 glamor_pixmap_clear_fbo(glamor_screen_private *glamor_priv, glamor_pixmap_fbo *fbo,
    246                         const struct glamor_format *pixmap_format)
    247 {
    248     glamor_make_current(glamor_priv);
    249 
    250     assert(fbo->fb != 0 && fbo->tex != 0);
    251 
    252     if (glamor_priv->has_clear_texture) {
    253         glClearTexImage(fbo->tex, 0, pixmap_format->format, pixmap_format->type, NULL);
    254     }
    255     else {
    256         glamor_set_destination_pixmap_fbo(glamor_priv, fbo, 0, 0, fbo->width, fbo->height);
    257 
    258         glClearColor(0.0, 0.0, 0.0, 0.0);
    259         glClear(GL_COLOR_BUFFER_BIT);
    260     }
    261 }
    262 
    263 glamor_pixmap_fbo *
    264 glamor_pixmap_detach_fbo(glamor_pixmap_private *pixmap_priv)
    265 {
    266     glamor_pixmap_fbo *fbo;
    267 
    268     if (pixmap_priv == NULL)
    269         return NULL;
    270 
    271     fbo = pixmap_priv->fbo;
    272     if (fbo == NULL)
    273         return NULL;
    274 
    275     pixmap_priv->fbo = NULL;
    276     return fbo;
    277 }
    278 
    279 /* The pixmap must not be attached to another fbo. */
    280 void
    281 glamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo)
    282 {
    283     glamor_pixmap_private *pixmap_priv;
    284 
    285     pixmap_priv = glamor_get_pixmap_private(pixmap);
    286 
    287     if (pixmap_priv->fbo)
    288         return;
    289 
    290     pixmap_priv->fbo = fbo;
    291 
    292     switch (pixmap_priv->type) {
    293     case GLAMOR_TEXTURE_ONLY:
    294     case GLAMOR_TEXTURE_DRM:
    295         pixmap_priv->gl_fbo = GLAMOR_FBO_NORMAL;
    296         pixmap->devPrivate.ptr = NULL;
    297     default:
    298         break;
    299     }
    300 }
    301 
    302 void
    303 glamor_pixmap_destroy_fbo(PixmapPtr pixmap)
    304 {
    305     ScreenPtr screen = pixmap->drawable.pScreen;
    306     glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    307     glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
    308     glamor_pixmap_fbo *fbo;
    309 
    310     if (glamor_pixmap_priv_is_large(priv)) {
    311         int i;
    312 
    313         for (i = 0; i < priv->block_wcnt * priv->block_hcnt; i++)
    314             glamor_destroy_fbo(glamor_priv, priv->fbo_array[i]);
    315         free(priv->fbo_array);
    316         priv->fbo_array = NULL;
    317     }
    318     else {
    319         fbo = glamor_pixmap_detach_fbo(priv);
    320         if (fbo)
    321             glamor_destroy_fbo(glamor_priv, fbo);
    322     }
    323 }
    324 
    325 Bool
    326 glamor_pixmap_ensure_fbo(PixmapPtr pixmap, int flag)
    327 {
    328     glamor_screen_private *glamor_priv;
    329     glamor_pixmap_private *pixmap_priv;
    330     glamor_pixmap_fbo *fbo;
    331 
    332     glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
    333     pixmap_priv = glamor_get_pixmap_private(pixmap);
    334     if (pixmap_priv->fbo == NULL) {
    335 
    336         fbo = glamor_create_fbo(glamor_priv, pixmap, pixmap->drawable.width,
    337                                 pixmap->drawable.height, flag);
    338         if (fbo == NULL)
    339             return FALSE;
    340 
    341         glamor_pixmap_attach_fbo(pixmap, fbo);
    342     }
    343     else {
    344         /* We do have a fbo, but it may lack of fb or tex. */
    345         if (!pixmap_priv->fbo->tex)
    346             pixmap_priv->fbo->tex =
    347                 _glamor_create_tex(glamor_priv, pixmap, pixmap->drawable.width,
    348                                    pixmap->drawable.height);
    349 
    350         if (flag != GLAMOR_CREATE_FBO_NO_FBO && pixmap_priv->fbo->fb == 0)
    351             if (glamor_pixmap_ensure_fb(glamor_priv, pixmap_priv->fbo) != 0)
    352                 return FALSE;
    353     }
    354 
    355     return TRUE;
    356 }
    357 
    358 _X_EXPORT void
    359 glamor_pixmap_exchange_fbos(PixmapPtr front, PixmapPtr back)
    360 {
    361     glamor_pixmap_private *front_priv, *back_priv;
    362     glamor_pixmap_fbo *temp_fbo;
    363 
    364     front_priv = glamor_get_pixmap_private(front);
    365     back_priv = glamor_get_pixmap_private(back);
    366     temp_fbo = front_priv->fbo;
    367     front_priv->fbo = back_priv->fbo;
    368     back_priv->fbo = temp_fbo;
    369 }