xserver

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

glamor_prepare.c (9591B)


      1 /*
      2  * Copyright © 2014 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that copyright
      7  * notice and this permission notice appear in supporting documentation, and
      8  * that the name of the copyright holders not be used in advertising or
      9  * publicity pertaining to distribution of the software without specific,
     10  * written prior permission.  The copyright holders make no representations
     11  * about the suitability of this software for any purpose.  It is provided "as
     12  * is" without express or implied warranty.
     13  *
     14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     20  * OF THIS SOFTWARE.
     21  */
     22 
     23 #include "glamor_priv.h"
     24 #include "glamor_prepare.h"
     25 #include "glamor_transfer.h"
     26 
     27 /*
     28  * Make a pixmap ready to draw with fb by
     29  * creating a PBO large enough for the whole object
     30  * and downloading all of the FBOs into it.
     31  */
     32 
     33 static Bool
     34 glamor_prep_pixmap_box(PixmapPtr pixmap, glamor_access_t access, BoxPtr box)
     35 {
     36     ScreenPtr                   screen = pixmap->drawable.pScreen;
     37     glamor_screen_private       *glamor_priv = glamor_get_screen_private(screen);
     38     glamor_pixmap_private       *priv = glamor_get_pixmap_private(pixmap);
     39     int                         gl_access, gl_usage;
     40     RegionRec                   region;
     41 
     42     if (priv->type == GLAMOR_DRM_ONLY)
     43         return FALSE;
     44 
     45     if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
     46         return TRUE;
     47 
     48     glamor_make_current(glamor_priv);
     49 
     50     RegionInit(&region, box, 1);
     51 
     52     /* See if it's already mapped */
     53     if (pixmap->devPrivate.ptr) {
     54         /*
     55          * Someone else has mapped this pixmap;
     56          * we'll assume that it's directly mapped
     57          * by a lower level driver
     58          */
     59         if (!priv->prepared)
     60             return TRUE;
     61 
     62         /* In X, multiple Drawables can be stored in the same Pixmap (such as
     63          * each individual window in a non-composited screen pixmap, or the
     64          * reparented window contents inside the window-manager-decorated window
     65          * pixmap on a composited screen).
     66          *
     67          * As a result, when doing a series of mappings for a fallback, we may
     68          * need to add more boxes to the set of data we've downloaded, as we go.
     69          */
     70         RegionSubtract(&region, &region, &priv->prepare_region);
     71         if (!RegionNotEmpty(&region))
     72             return TRUE;
     73 
     74         if (access == GLAMOR_ACCESS_RW)
     75             FatalError("attempt to remap buffer as writable");
     76 
     77         if (priv->pbo) {
     78             glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
     79             glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
     80             pixmap->devPrivate.ptr = NULL;
     81         }
     82     } else {
     83         RegionInit(&priv->prepare_region, box, 1);
     84 
     85         if (glamor_priv->has_rw_pbo) {
     86             if (priv->pbo == 0)
     87                 glGenBuffers(1, &priv->pbo);
     88 
     89             gl_usage = GL_STREAM_READ;
     90 
     91             glamor_priv->suppress_gl_out_of_memory_logging = true;
     92 
     93             glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
     94             glBufferData(GL_PIXEL_PACK_BUFFER,
     95                          pixmap->devKind * pixmap->drawable.height, NULL,
     96                          gl_usage);
     97 
     98             glamor_priv->suppress_gl_out_of_memory_logging = false;
     99 
    100             if (glGetError() == GL_OUT_OF_MEMORY) {
    101                 if (!glamor_priv->logged_any_pbo_allocation_failure) {
    102                     LogMessageVerb(X_WARNING, 0, "glamor: Failed to allocate %d "
    103                                    "bytes PBO due to GL_OUT_OF_MEMORY.\n",
    104                                    pixmap->devKind * pixmap->drawable.height);
    105                     glamor_priv->logged_any_pbo_allocation_failure = true;
    106                 }
    107                 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
    108                 glDeleteBuffers(1, &priv->pbo);
    109                 priv->pbo = 0;
    110             }
    111         }
    112 
    113         if (!priv->pbo) {
    114             pixmap->devPrivate.ptr = xallocarray(pixmap->devKind,
    115                                                  pixmap->drawable.height);
    116             if (!pixmap->devPrivate.ptr)
    117                 return FALSE;
    118         }
    119         priv->map_access = access;
    120     }
    121 
    122     glamor_download_boxes(pixmap, RegionRects(&region), RegionNumRects(&region),
    123                           0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
    124 
    125     RegionUninit(&region);
    126 
    127     if (priv->pbo) {
    128         if (priv->map_access == GLAMOR_ACCESS_RW)
    129             gl_access = GL_READ_WRITE;
    130         else
    131             gl_access = GL_READ_ONLY;
    132 
    133         pixmap->devPrivate.ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, gl_access);
    134         glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
    135     }
    136 
    137     priv->prepared = TRUE;
    138     return TRUE;
    139 }
    140 
    141 /*
    142  * When we're done with the drawable, unmap the PBO, reupload
    143  * if we were writing to it and then unbind it to release the memory
    144  */
    145 
    146 static void
    147 glamor_fini_pixmap(PixmapPtr pixmap)
    148 {
    149     glamor_pixmap_private       *priv = glamor_get_pixmap_private(pixmap);
    150 
    151     if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
    152         return;
    153 
    154     if (!priv->prepared)
    155         return;
    156 
    157     if (priv->pbo) {
    158         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, priv->pbo);
    159         glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
    160         pixmap->devPrivate.ptr = NULL;
    161     }
    162 
    163     if (priv->map_access == GLAMOR_ACCESS_RW) {
    164         glamor_upload_boxes(pixmap,
    165                             RegionRects(&priv->prepare_region),
    166                             RegionNumRects(&priv->prepare_region),
    167                             0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
    168     }
    169 
    170     RegionUninit(&priv->prepare_region);
    171 
    172     if (priv->pbo) {
    173         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
    174         glDeleteBuffers(1, &priv->pbo);
    175         priv->pbo = 0;
    176     } else {
    177         free(pixmap->devPrivate.ptr);
    178         pixmap->devPrivate.ptr = NULL;
    179     }
    180 
    181     priv->prepared = FALSE;
    182 }
    183 
    184 Bool
    185 glamor_prepare_access(DrawablePtr drawable, glamor_access_t access)
    186 {
    187     PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
    188     BoxRec box;
    189     int off_x, off_y;
    190 
    191     glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
    192 
    193     box.x1 = drawable->x + off_x;
    194     box.x2 = box.x1 + drawable->width;
    195     box.y1 = drawable->y + off_y;
    196     box.y2 = box.y1 + drawable->height;
    197     return glamor_prep_pixmap_box(pixmap, access, &box);
    198 }
    199 
    200 Bool
    201 glamor_prepare_access_box(DrawablePtr drawable, glamor_access_t access,
    202                          int x, int y, int w, int h)
    203 {
    204     PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
    205     BoxRec box;
    206     int off_x, off_y;
    207 
    208     glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
    209     box.x1 = drawable->x + x + off_x;
    210     box.x2 = box.x1 + w;
    211     box.y1 = drawable->y + y + off_y;
    212     box.y2 = box.y1 + h;
    213     return glamor_prep_pixmap_box(pixmap, access, &box);
    214 }
    215 
    216 void
    217 glamor_finish_access(DrawablePtr drawable)
    218 {
    219     glamor_fini_pixmap(glamor_get_drawable_pixmap(drawable));
    220 }
    221 
    222 /*
    223  * Make a picture ready to use with fb.
    224  */
    225 
    226 Bool
    227 glamor_prepare_access_picture(PicturePtr picture, glamor_access_t access)
    228 {
    229     if (!picture || !picture->pDrawable)
    230         return TRUE;
    231 
    232     return glamor_prepare_access(picture->pDrawable, access);
    233 }
    234 
    235 Bool
    236 glamor_prepare_access_picture_box(PicturePtr picture, glamor_access_t access,
    237                         int x, int y, int w, int h)
    238 {
    239     if (!picture || !picture->pDrawable)
    240         return TRUE;
    241 
    242     /* If a transform is set, we don't know what the bounds is on the
    243      * source, so just prepare the whole pixmap.  XXX: We could
    244      * potentially work out where in the source would be sampled based
    245      * on the transform, and we don't need do do this for destination
    246      * pixmaps at all.
    247      */
    248     if (picture->transform) {
    249         return glamor_prepare_access_box(picture->pDrawable, access,
    250                                          0, 0,
    251                                          picture->pDrawable->width,
    252                                          picture->pDrawable->height);
    253     } else {
    254         return glamor_prepare_access_box(picture->pDrawable, access,
    255                                          x, y, w, h);
    256     }
    257 }
    258 
    259 void
    260 glamor_finish_access_picture(PicturePtr picture)
    261 {
    262     if (!picture || !picture->pDrawable)
    263         return;
    264 
    265     glamor_finish_access(picture->pDrawable);
    266 }
    267 
    268 /*
    269  * Make a GC ready to use with fb. This just
    270  * means making sure the appropriate fill pixmap is
    271  * in CPU memory again
    272  */
    273 
    274 Bool
    275 glamor_prepare_access_gc(GCPtr gc)
    276 {
    277     switch (gc->fillStyle) {
    278     case FillTiled:
    279         return glamor_prepare_access(&gc->tile.pixmap->drawable,
    280                                      GLAMOR_ACCESS_RO);
    281     case FillStippled:
    282     case FillOpaqueStippled:
    283         return glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RO);
    284     }
    285     return TRUE;
    286 }
    287 
    288 /*
    289  * Free any temporary CPU pixmaps for the GC
    290  */
    291 void
    292 glamor_finish_access_gc(GCPtr gc)
    293 {
    294     switch (gc->fillStyle) {
    295     case FillTiled:
    296         glamor_finish_access(&gc->tile.pixmap->drawable);
    297         break;
    298     case FillStippled:
    299     case FillOpaqueStippled:
    300         glamor_finish_access(&gc->stipple->drawable);
    301         break;
    302     }
    303 }