glamor_prepare.c revision 35c4bbdf
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 33static Bool 34glamor_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(®ion, 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(®ion, ®ion, &priv->prepare_region); 71 if (!RegionNotEmpty(®ion)) 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 glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo); 92 glBufferData(GL_PIXEL_PACK_BUFFER, 93 pixmap->devKind * pixmap->drawable.height, NULL, 94 gl_usage); 95 } else { 96 pixmap->devPrivate.ptr = xallocarray(pixmap->devKind, 97 pixmap->drawable.height); 98 if (!pixmap->devPrivate.ptr) 99 return FALSE; 100 } 101 priv->map_access = access; 102 } 103 104 glamor_download_boxes(pixmap, RegionRects(®ion), RegionNumRects(®ion), 105 0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind); 106 107 RegionUninit(®ion); 108 109 if (glamor_priv->has_rw_pbo) { 110 if (priv->map_access == GLAMOR_ACCESS_RW) 111 gl_access = GL_READ_WRITE; 112 else 113 gl_access = GL_READ_ONLY; 114 115 pixmap->devPrivate.ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, gl_access); 116 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 117 } 118 119 priv->prepared = TRUE; 120 return TRUE; 121} 122 123/* 124 * When we're done with the drawable, unmap the PBO, reupload 125 * if we were writing to it and then unbind it to release the memory 126 */ 127 128static void 129glamor_fini_pixmap(PixmapPtr pixmap) 130{ 131 ScreenPtr screen = pixmap->drawable.pScreen; 132 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 133 glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 134 135 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv)) 136 return; 137 138 if (!priv->prepared) 139 return; 140 141 if (glamor_priv->has_rw_pbo) { 142 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, priv->pbo); 143 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); 144 pixmap->devPrivate.ptr = NULL; 145 } 146 147 if (priv->map_access == GLAMOR_ACCESS_RW) { 148 glamor_upload_boxes(pixmap, 149 RegionRects(&priv->prepare_region), 150 RegionNumRects(&priv->prepare_region), 151 0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind); 152 } 153 154 RegionUninit(&priv->prepare_region); 155 156 if (glamor_priv->has_rw_pbo) { 157 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 158 glDeleteBuffers(1, &priv->pbo); 159 priv->pbo = 0; 160 } else { 161 free(pixmap->devPrivate.ptr); 162 pixmap->devPrivate.ptr = NULL; 163 } 164 165 priv->prepared = FALSE; 166} 167 168Bool 169glamor_prepare_access(DrawablePtr drawable, glamor_access_t access) 170{ 171 PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); 172 BoxRec box; 173 int off_x, off_y; 174 175 glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); 176 177 box.x1 = drawable->x + off_x; 178 box.x2 = box.x1 + drawable->width; 179 box.y1 = drawable->y + off_y; 180 box.y2 = box.y1 + drawable->height; 181 return glamor_prep_pixmap_box(pixmap, access, &box); 182} 183 184Bool 185glamor_prepare_access_box(DrawablePtr drawable, glamor_access_t access, 186 int x, int y, int w, int h) 187{ 188 PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); 189 BoxRec box; 190 int off_x, off_y; 191 192 glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); 193 box.x1 = drawable->x + x + off_x; 194 box.x2 = box.x1 + w; 195 box.y1 = drawable->y + y + off_y; 196 box.y2 = box.y1 + h; 197 return glamor_prep_pixmap_box(pixmap, access, &box); 198} 199 200void 201glamor_finish_access(DrawablePtr drawable) 202{ 203 glamor_fini_pixmap(glamor_get_drawable_pixmap(drawable)); 204} 205 206/* 207 * Make a picture ready to use with fb. 208 */ 209 210Bool 211glamor_prepare_access_picture(PicturePtr picture, glamor_access_t access) 212{ 213 if (!picture || !picture->pDrawable) 214 return TRUE; 215 216 return glamor_prepare_access(picture->pDrawable, access); 217} 218 219Bool 220glamor_prepare_access_picture_box(PicturePtr picture, glamor_access_t access, 221 int x, int y, int w, int h) 222{ 223 if (!picture || !picture->pDrawable) 224 return TRUE; 225 226 /* If a transform is set, we don't know what the bounds is on the 227 * source, so just prepare the whole pixmap. XXX: We could 228 * potentially work out where in the source would be sampled based 229 * on the transform, and we don't need do do this for destination 230 * pixmaps at all. 231 */ 232 if (picture->transform) { 233 return glamor_prepare_access_box(picture->pDrawable, access, 234 0, 0, 235 picture->pDrawable->width, 236 picture->pDrawable->height); 237 } else { 238 return glamor_prepare_access_box(picture->pDrawable, access, 239 x, y, w, h); 240 } 241} 242 243void 244glamor_finish_access_picture(PicturePtr picture) 245{ 246 if (!picture || !picture->pDrawable) 247 return; 248 249 glamor_finish_access(picture->pDrawable); 250} 251 252/* 253 * Make a GC ready to use with fb. This just 254 * means making sure the appropriate fill pixmap is 255 * in CPU memory again 256 */ 257 258Bool 259glamor_prepare_access_gc(GCPtr gc) 260{ 261 switch (gc->fillStyle) { 262 case FillTiled: 263 return glamor_prepare_access(&gc->tile.pixmap->drawable, 264 GLAMOR_ACCESS_RO); 265 case FillStippled: 266 case FillOpaqueStippled: 267 return glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RO); 268 } 269 return TRUE; 270} 271 272/* 273 * Free any temporary CPU pixmaps for the GC 274 */ 275void 276glamor_finish_access_gc(GCPtr gc) 277{ 278 switch (gc->fillStyle) { 279 case FillTiled: 280 glamor_finish_access(&gc->tile.pixmap->drawable); 281 break; 282 case FillStippled: 283 case FillOpaqueStippled: 284 glamor_finish_access(&gc->stipple->drawable); 285 break; 286 } 287} 288