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