135c4bbdfSmrg/* 235c4bbdfSmrg * Copyright © 2014 Keith Packard 335c4bbdfSmrg * 435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its 535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that 635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright 735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and 835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or 935c4bbdfSmrg * publicity pertaining to distribution of the software without specific, 1035c4bbdfSmrg * written prior permission. The copyright holders make no representations 1135c4bbdfSmrg * about the suitability of this software for any purpose. It is provided "as 1235c4bbdfSmrg * is" without express or implied warranty. 1335c4bbdfSmrg * 1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2035c4bbdfSmrg * OF THIS SOFTWARE. 2135c4bbdfSmrg */ 2235c4bbdfSmrg 2335c4bbdfSmrg#include "glamor_priv.h" 2435c4bbdfSmrg#include "glamor_transfer.h" 2535c4bbdfSmrg 2635c4bbdfSmrg/* 2735c4bbdfSmrg * Write a region of bits into a pixmap 2835c4bbdfSmrg */ 2935c4bbdfSmrgvoid 3035c4bbdfSmrgglamor_upload_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox, 3135c4bbdfSmrg int dx_src, int dy_src, 3235c4bbdfSmrg int dx_dst, int dy_dst, 3335c4bbdfSmrg uint8_t *bits, uint32_t byte_stride) 3435c4bbdfSmrg{ 3535c4bbdfSmrg ScreenPtr screen = pixmap->drawable.pScreen; 3635c4bbdfSmrg glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 3735c4bbdfSmrg glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 3835c4bbdfSmrg int box_index; 3935c4bbdfSmrg int bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3; 40ed6184dfSmrg const struct glamor_format *f = glamor_format_for_pixmap(pixmap); 4135c4bbdfSmrg 4235c4bbdfSmrg glamor_make_current(glamor_priv); 4335c4bbdfSmrg 4435c4bbdfSmrg glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 4535c4bbdfSmrg 4635c4bbdfSmrg if (glamor_priv->has_unpack_subimage) 4735c4bbdfSmrg glPixelStorei(GL_UNPACK_ROW_LENGTH, byte_stride / bytes_per_pixel); 4835c4bbdfSmrg 4935c4bbdfSmrg glamor_pixmap_loop(priv, box_index) { 5035c4bbdfSmrg BoxPtr box = glamor_pixmap_box_at(priv, box_index); 5135c4bbdfSmrg glamor_pixmap_fbo *fbo = glamor_pixmap_fbo_at(priv, box_index); 5235c4bbdfSmrg BoxPtr boxes = in_boxes; 5335c4bbdfSmrg int nbox = in_nbox; 5435c4bbdfSmrg 5535c4bbdfSmrg glamor_bind_texture(glamor_priv, GL_TEXTURE0, fbo, TRUE); 5635c4bbdfSmrg 5735c4bbdfSmrg while (nbox--) { 5835c4bbdfSmrg 5935c4bbdfSmrg /* compute drawable coordinates */ 6035c4bbdfSmrg int x1 = MAX(boxes->x1 + dx_dst, box->x1); 6135c4bbdfSmrg int x2 = MIN(boxes->x2 + dx_dst, box->x2); 6235c4bbdfSmrg int y1 = MAX(boxes->y1 + dy_dst, box->y1); 6335c4bbdfSmrg int y2 = MIN(boxes->y2 + dy_dst, box->y2); 6435c4bbdfSmrg 6535c4bbdfSmrg size_t ofs = (y1 - dy_dst + dy_src) * byte_stride; 6635c4bbdfSmrg ofs += (x1 - dx_dst + dx_src) * bytes_per_pixel; 6735c4bbdfSmrg 6835c4bbdfSmrg boxes++; 6935c4bbdfSmrg 7035c4bbdfSmrg if (x2 <= x1 || y2 <= y1) 7135c4bbdfSmrg continue; 7235c4bbdfSmrg 7335c4bbdfSmrg if (glamor_priv->has_unpack_subimage || 7435c4bbdfSmrg x2 - x1 == byte_stride / bytes_per_pixel) { 7535c4bbdfSmrg glTexSubImage2D(GL_TEXTURE_2D, 0, 7635c4bbdfSmrg x1 - box->x1, y1 - box->y1, 7735c4bbdfSmrg x2 - x1, y2 - y1, 78ed6184dfSmrg f->format, f->type, 7935c4bbdfSmrg bits + ofs); 8035c4bbdfSmrg } else { 8135c4bbdfSmrg for (; y1 < y2; y1++, ofs += byte_stride) 8235c4bbdfSmrg glTexSubImage2D(GL_TEXTURE_2D, 0, 8335c4bbdfSmrg x1 - box->x1, y1 - box->y1, 8435c4bbdfSmrg x2 - x1, 1, 85ed6184dfSmrg f->format, f->type, 8635c4bbdfSmrg bits + ofs); 8735c4bbdfSmrg } 8835c4bbdfSmrg } 8935c4bbdfSmrg } 9035c4bbdfSmrg 9135c4bbdfSmrg if (glamor_priv->has_unpack_subimage) 9235c4bbdfSmrg glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 9335c4bbdfSmrg} 9435c4bbdfSmrg 9535c4bbdfSmrg/* 9635c4bbdfSmrg * Upload a region of data 9735c4bbdfSmrg */ 9835c4bbdfSmrg 9935c4bbdfSmrgvoid 10035c4bbdfSmrgglamor_upload_region(PixmapPtr pixmap, RegionPtr region, 10135c4bbdfSmrg int region_x, int region_y, 10235c4bbdfSmrg uint8_t *bits, uint32_t byte_stride) 10335c4bbdfSmrg{ 10435c4bbdfSmrg glamor_upload_boxes(pixmap, RegionRects(region), RegionNumRects(region), 10535c4bbdfSmrg -region_x, -region_y, 10635c4bbdfSmrg 0, 0, 10735c4bbdfSmrg bits, byte_stride); 10835c4bbdfSmrg} 10935c4bbdfSmrg 11035c4bbdfSmrg/* 11135c4bbdfSmrg * Take the data in the pixmap and stuff it back into the FBO 11235c4bbdfSmrg */ 11335c4bbdfSmrgvoid 11435c4bbdfSmrgglamor_upload_pixmap(PixmapPtr pixmap) 11535c4bbdfSmrg{ 11635c4bbdfSmrg BoxRec box; 11735c4bbdfSmrg 11835c4bbdfSmrg box.x1 = 0; 11935c4bbdfSmrg box.x2 = pixmap->drawable.width; 12035c4bbdfSmrg box.y1 = 0; 12135c4bbdfSmrg box.y2 = pixmap->drawable.height; 12235c4bbdfSmrg glamor_upload_boxes(pixmap, &box, 1, 0, 0, 0, 0, 12335c4bbdfSmrg pixmap->devPrivate.ptr, pixmap->devKind); 12435c4bbdfSmrg} 12535c4bbdfSmrg 12635c4bbdfSmrg/* 12735c4bbdfSmrg * Read stuff from the pixmap FBOs and write to memory 12835c4bbdfSmrg */ 12935c4bbdfSmrgvoid 13035c4bbdfSmrgglamor_download_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox, 13135c4bbdfSmrg int dx_src, int dy_src, 13235c4bbdfSmrg int dx_dst, int dy_dst, 13335c4bbdfSmrg uint8_t *bits, uint32_t byte_stride) 13435c4bbdfSmrg{ 13535c4bbdfSmrg ScreenPtr screen = pixmap->drawable.pScreen; 13635c4bbdfSmrg glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 13735c4bbdfSmrg glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 13835c4bbdfSmrg int box_index; 13935c4bbdfSmrg int bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3; 140ed6184dfSmrg const struct glamor_format *f = glamor_format_for_pixmap(pixmap); 14135c4bbdfSmrg 14235c4bbdfSmrg glamor_make_current(glamor_priv); 14335c4bbdfSmrg 14435c4bbdfSmrg glPixelStorei(GL_PACK_ALIGNMENT, 4); 14535c4bbdfSmrg if (glamor_priv->has_pack_subimage) 14635c4bbdfSmrg glPixelStorei(GL_PACK_ROW_LENGTH, byte_stride / bytes_per_pixel); 14735c4bbdfSmrg 14835c4bbdfSmrg glamor_pixmap_loop(priv, box_index) { 14935c4bbdfSmrg BoxPtr box = glamor_pixmap_box_at(priv, box_index); 15035c4bbdfSmrg glamor_pixmap_fbo *fbo = glamor_pixmap_fbo_at(priv, box_index); 15135c4bbdfSmrg BoxPtr boxes = in_boxes; 15235c4bbdfSmrg int nbox = in_nbox; 15335c4bbdfSmrg 15435c4bbdfSmrg /* This should not be called on GLAMOR_FBO_NO_FBO-allocated pixmaps. */ 15535c4bbdfSmrg assert(fbo->fb); 15635c4bbdfSmrg glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb); 15735c4bbdfSmrg 15835c4bbdfSmrg while (nbox--) { 15935c4bbdfSmrg 16035c4bbdfSmrg /* compute drawable coordinates */ 16135c4bbdfSmrg int x1 = MAX(boxes->x1 + dx_src, box->x1); 16235c4bbdfSmrg int x2 = MIN(boxes->x2 + dx_src, box->x2); 16335c4bbdfSmrg int y1 = MAX(boxes->y1 + dy_src, box->y1); 16435c4bbdfSmrg int y2 = MIN(boxes->y2 + dy_src, box->y2); 16535c4bbdfSmrg size_t ofs = (y1 - dy_src + dy_dst) * byte_stride; 16635c4bbdfSmrg ofs += (x1 - dx_src + dx_dst) * bytes_per_pixel; 16735c4bbdfSmrg 16835c4bbdfSmrg boxes++; 16935c4bbdfSmrg 17035c4bbdfSmrg if (x2 <= x1 || y2 <= y1) 17135c4bbdfSmrg continue; 17235c4bbdfSmrg 17335c4bbdfSmrg if (glamor_priv->has_pack_subimage || 17435c4bbdfSmrg x2 - x1 == byte_stride / bytes_per_pixel) { 175ed6184dfSmrg glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, y2 - y1, f->format, f->type, bits + ofs); 17635c4bbdfSmrg } else { 17735c4bbdfSmrg for (; y1 < y2; y1++, ofs += byte_stride) 178ed6184dfSmrg glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, 1, f->format, f->type, bits + ofs); 17935c4bbdfSmrg } 18035c4bbdfSmrg } 18135c4bbdfSmrg } 18235c4bbdfSmrg if (glamor_priv->has_pack_subimage) 18335c4bbdfSmrg glPixelStorei(GL_PACK_ROW_LENGTH, 0); 18435c4bbdfSmrg} 18535c4bbdfSmrg 18635c4bbdfSmrg/* 18735c4bbdfSmrg * Read data from the pixmap FBO 18835c4bbdfSmrg */ 18935c4bbdfSmrgvoid 19035c4bbdfSmrgglamor_download_rect(PixmapPtr pixmap, int x, int y, int w, int h, uint8_t *bits) 19135c4bbdfSmrg{ 19235c4bbdfSmrg BoxRec box; 19335c4bbdfSmrg 19435c4bbdfSmrg box.x1 = x; 19535c4bbdfSmrg box.x2 = x + w; 19635c4bbdfSmrg box.y1 = y; 19735c4bbdfSmrg box.y2 = y + h; 19835c4bbdfSmrg 19935c4bbdfSmrg glamor_download_boxes(pixmap, &box, 1, 0, 0, -x, -y, 20035c4bbdfSmrg bits, PixmapBytePad(w, pixmap->drawable.depth)); 20135c4bbdfSmrg} 20235c4bbdfSmrg 20335c4bbdfSmrg/* 20435c4bbdfSmrg * Pull the data from the FBO down to the pixmap 20535c4bbdfSmrg */ 20635c4bbdfSmrgvoid 20735c4bbdfSmrgglamor_download_pixmap(PixmapPtr pixmap) 20835c4bbdfSmrg{ 20935c4bbdfSmrg BoxRec box; 21035c4bbdfSmrg 21135c4bbdfSmrg box.x1 = 0; 21235c4bbdfSmrg box.x2 = pixmap->drawable.width; 21335c4bbdfSmrg box.y1 = 0; 21435c4bbdfSmrg box.y2 = pixmap->drawable.height; 21535c4bbdfSmrg 21635c4bbdfSmrg glamor_download_boxes(pixmap, &box, 1, 0, 0, 0, 0, 21735c4bbdfSmrg pixmap->devPrivate.ptr, pixmap->devKind); 21835c4bbdfSmrg} 219