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