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  */
29 void
glamor_upload_boxes(PixmapPtr pixmap,BoxPtr in_boxes,int in_nbox,int dx_src,int dy_src,int dx_dst,int dy_dst,uint8_t * bits,uint32_t byte_stride)30 glamor_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 
99 void
glamor_upload_region(PixmapPtr pixmap,RegionPtr region,int region_x,int region_y,uint8_t * bits,uint32_t byte_stride)100 glamor_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  */
113 void
glamor_upload_pixmap(PixmapPtr pixmap)114 glamor_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  */
129 void
glamor_download_boxes(PixmapPtr pixmap,BoxPtr in_boxes,int in_nbox,int dx_src,int dy_src,int dx_dst,int dy_dst,uint8_t * bits,uint32_t byte_stride)130 glamor_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  */
189 void
glamor_download_rect(PixmapPtr pixmap,int x,int y,int w,int h,uint8_t * bits)190 glamor_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  */
206 void
glamor_download_pixmap(PixmapPtr pixmap)207 glamor_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