glamor_transfer.c revision 1b5d61b8
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_transfer.h" 25 26/* XXX a kludge for now */ 27void 28glamor_format_for_pixmap(PixmapPtr pixmap, GLenum *format, GLenum *type) 29{ 30 switch (pixmap->drawable.depth) { 31 case 24: 32 case 32: 33 *format = GL_BGRA; 34 *type = GL_UNSIGNED_INT_8_8_8_8_REV; 35 break; 36 case 30: 37 *format = GL_BGRA; 38 *type = GL_UNSIGNED_INT_2_10_10_10_REV; 39 break; 40 case 16: 41 *format = GL_RGB; 42 *type = GL_UNSIGNED_SHORT_5_6_5; 43 break; 44 case 15: 45 *format = GL_BGRA; 46 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV; 47 break; 48 case 8: 49 *format = glamor_get_screen_private(pixmap->drawable.pScreen)->one_channel_format; 50 *type = GL_UNSIGNED_BYTE; 51 break; 52 default: 53 FatalError("Invalid pixmap depth %d\n", pixmap->drawable.depth); 54 break; 55 } 56} 57 58/* 59 * Write a region of bits into a pixmap 60 */ 61void 62glamor_upload_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox, 63 int dx_src, int dy_src, 64 int dx_dst, int dy_dst, 65 uint8_t *bits, uint32_t byte_stride) 66{ 67 ScreenPtr screen = pixmap->drawable.pScreen; 68 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 69 glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 70 int box_index; 71 int bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3; 72 GLenum type; 73 GLenum format; 74 75 glamor_format_for_pixmap(pixmap, &format, &type); 76 77 glamor_make_current(glamor_priv); 78 79 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 80 81 if (glamor_priv->has_unpack_subimage) 82 glPixelStorei(GL_UNPACK_ROW_LENGTH, byte_stride / bytes_per_pixel); 83 84 glamor_pixmap_loop(priv, box_index) { 85 BoxPtr box = glamor_pixmap_box_at(priv, box_index); 86 glamor_pixmap_fbo *fbo = glamor_pixmap_fbo_at(priv, box_index); 87 BoxPtr boxes = in_boxes; 88 int nbox = in_nbox; 89 90 glamor_bind_texture(glamor_priv, GL_TEXTURE0, fbo, TRUE); 91 92 while (nbox--) { 93 94 /* compute drawable coordinates */ 95 int x1 = MAX(boxes->x1 + dx_dst, box->x1); 96 int x2 = MIN(boxes->x2 + dx_dst, box->x2); 97 int y1 = MAX(boxes->y1 + dy_dst, box->y1); 98 int y2 = MIN(boxes->y2 + dy_dst, box->y2); 99 100 size_t ofs = (y1 - dy_dst + dy_src) * byte_stride; 101 ofs += (x1 - dx_dst + dx_src) * bytes_per_pixel; 102 103 boxes++; 104 105 if (x2 <= x1 || y2 <= y1) 106 continue; 107 108 if (glamor_priv->has_unpack_subimage || 109 x2 - x1 == byte_stride / bytes_per_pixel) { 110 glTexSubImage2D(GL_TEXTURE_2D, 0, 111 x1 - box->x1, y1 - box->y1, 112 x2 - x1, y2 - y1, 113 format, type, 114 bits + ofs); 115 } else { 116 for (; y1 < y2; y1++, ofs += byte_stride) 117 glTexSubImage2D(GL_TEXTURE_2D, 0, 118 x1 - box->x1, y1 - box->y1, 119 x2 - x1, 1, 120 format, type, 121 bits + ofs); 122 } 123 } 124 } 125 126 if (glamor_priv->has_unpack_subimage) 127 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 128} 129 130/* 131 * Upload a region of data 132 */ 133 134void 135glamor_upload_region(PixmapPtr pixmap, RegionPtr region, 136 int region_x, int region_y, 137 uint8_t *bits, uint32_t byte_stride) 138{ 139 glamor_upload_boxes(pixmap, RegionRects(region), RegionNumRects(region), 140 -region_x, -region_y, 141 0, 0, 142 bits, byte_stride); 143} 144 145/* 146 * Take the data in the pixmap and stuff it back into the FBO 147 */ 148void 149glamor_upload_pixmap(PixmapPtr pixmap) 150{ 151 BoxRec box; 152 153 box.x1 = 0; 154 box.x2 = pixmap->drawable.width; 155 box.y1 = 0; 156 box.y2 = pixmap->drawable.height; 157 glamor_upload_boxes(pixmap, &box, 1, 0, 0, 0, 0, 158 pixmap->devPrivate.ptr, pixmap->devKind); 159} 160 161/* 162 * Read stuff from the pixmap FBOs and write to memory 163 */ 164void 165glamor_download_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox, 166 int dx_src, int dy_src, 167 int dx_dst, int dy_dst, 168 uint8_t *bits, uint32_t byte_stride) 169{ 170 ScreenPtr screen = pixmap->drawable.pScreen; 171 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 172 glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 173 int box_index; 174 int bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3; 175 GLenum type; 176 GLenum format; 177 178 glamor_format_for_pixmap(pixmap, &format, &type); 179 180 glamor_make_current(glamor_priv); 181 182 glPixelStorei(GL_PACK_ALIGNMENT, 4); 183 if (glamor_priv->has_pack_subimage) 184 glPixelStorei(GL_PACK_ROW_LENGTH, byte_stride / bytes_per_pixel); 185 186 glamor_pixmap_loop(priv, box_index) { 187 BoxPtr box = glamor_pixmap_box_at(priv, box_index); 188 glamor_pixmap_fbo *fbo = glamor_pixmap_fbo_at(priv, box_index); 189 BoxPtr boxes = in_boxes; 190 int nbox = in_nbox; 191 192 /* This should not be called on GLAMOR_FBO_NO_FBO-allocated pixmaps. */ 193 assert(fbo->fb); 194 glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb); 195 196 while (nbox--) { 197 198 /* compute drawable coordinates */ 199 int x1 = MAX(boxes->x1 + dx_src, box->x1); 200 int x2 = MIN(boxes->x2 + dx_src, box->x2); 201 int y1 = MAX(boxes->y1 + dy_src, box->y1); 202 int y2 = MIN(boxes->y2 + dy_src, box->y2); 203 size_t ofs = (y1 - dy_src + dy_dst) * byte_stride; 204 ofs += (x1 - dx_src + dx_dst) * bytes_per_pixel; 205 206 boxes++; 207 208 if (x2 <= x1 || y2 <= y1) 209 continue; 210 211 if (glamor_priv->has_pack_subimage || 212 x2 - x1 == byte_stride / bytes_per_pixel) { 213 glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, y2 - y1, format, type, bits + ofs); 214 } else { 215 for (; y1 < y2; y1++, ofs += byte_stride) 216 glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, 1, format, type, bits + ofs); 217 } 218 } 219 } 220 if (glamor_priv->has_pack_subimage) 221 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 222} 223 224/* 225 * Read data from the pixmap FBO 226 */ 227void 228glamor_download_rect(PixmapPtr pixmap, int x, int y, int w, int h, uint8_t *bits) 229{ 230 BoxRec box; 231 232 box.x1 = x; 233 box.x2 = x + w; 234 box.y1 = y; 235 box.y2 = y + h; 236 237 glamor_download_boxes(pixmap, &box, 1, 0, 0, -x, -y, 238 bits, PixmapBytePad(w, pixmap->drawable.depth)); 239} 240 241/* 242 * Pull the data from the FBO down to the pixmap 243 */ 244void 245glamor_download_pixmap(PixmapPtr pixmap) 246{ 247 BoxRec box; 248 249 box.x1 = 0; 250 box.x2 = pixmap->drawable.width; 251 box.y1 = 0; 252 box.y2 = pixmap->drawable.height; 253 254 glamor_download_boxes(pixmap, &box, 1, 0, 0, 0, 0, 255 pixmap->devPrivate.ptr, pixmap->devKind); 256} 257