1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright © 2014 Keith Packard
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission to use, copy, modify, distribute, and sell this software and its
5*4882a593Smuzhiyun * documentation for any purpose is hereby granted without fee, provided that
6*4882a593Smuzhiyun * the above copyright notice appear in all copies and that both that copyright
7*4882a593Smuzhiyun * notice and this permission notice appear in supporting documentation, and
8*4882a593Smuzhiyun * that the name of the copyright holders not be used in advertising or
9*4882a593Smuzhiyun * publicity pertaining to distribution of the software without specific,
10*4882a593Smuzhiyun * written prior permission. The copyright holders make no representations
11*4882a593Smuzhiyun * about the suitability of this software for any purpose. It is provided "as
12*4882a593Smuzhiyun * is" without express or implied warranty.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15*4882a593Smuzhiyun * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16*4882a593Smuzhiyun * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17*4882a593Smuzhiyun * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18*4882a593Smuzhiyun * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19*4882a593Smuzhiyun * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20*4882a593Smuzhiyun * OF THIS SOFTWARE.
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "glamor_priv.h"
24*4882a593Smuzhiyun #include "glamor_prepare.h"
25*4882a593Smuzhiyun #include "glamor_transfer.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun * Make a pixmap ready to draw with fb by
29*4882a593Smuzhiyun * creating a PBO large enough for the whole object
30*4882a593Smuzhiyun * and downloading all of the FBOs into it.
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun static Bool
glamor_prep_pixmap_box(PixmapPtr pixmap,glamor_access_t access,BoxPtr box)34*4882a593Smuzhiyun glamor_prep_pixmap_box(PixmapPtr pixmap, glamor_access_t access, BoxPtr box)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun ScreenPtr screen = pixmap->drawable.pScreen;
37*4882a593Smuzhiyun glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
38*4882a593Smuzhiyun glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
39*4882a593Smuzhiyun int gl_access, gl_usage;
40*4882a593Smuzhiyun RegionRec region;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun if (priv->type == GLAMOR_DRM_ONLY)
43*4882a593Smuzhiyun return FALSE;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
46*4882a593Smuzhiyun return TRUE;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun glamor_make_current(glamor_priv);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun RegionInit(®ion, box, 1);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /* See if it's already mapped */
53*4882a593Smuzhiyun if (pixmap->devPrivate.ptr) {
54*4882a593Smuzhiyun /*
55*4882a593Smuzhiyun * Someone else has mapped this pixmap;
56*4882a593Smuzhiyun * we'll assume that it's directly mapped
57*4882a593Smuzhiyun * by a lower level driver
58*4882a593Smuzhiyun */
59*4882a593Smuzhiyun if (!priv->prepared)
60*4882a593Smuzhiyun goto done;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* In X, multiple Drawables can be stored in the same Pixmap (such as
63*4882a593Smuzhiyun * each individual window in a non-composited screen pixmap, or the
64*4882a593Smuzhiyun * reparented window contents inside the window-manager-decorated window
65*4882a593Smuzhiyun * pixmap on a composited screen).
66*4882a593Smuzhiyun *
67*4882a593Smuzhiyun * As a result, when doing a series of mappings for a fallback, we may
68*4882a593Smuzhiyun * need to add more boxes to the set of data we've downloaded, as we go.
69*4882a593Smuzhiyun */
70*4882a593Smuzhiyun RegionSubtract(®ion, ®ion, &priv->prepare_region);
71*4882a593Smuzhiyun if (!RegionNotEmpty(®ion))
72*4882a593Smuzhiyun goto done;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun if (access == GLAMOR_ACCESS_RW)
75*4882a593Smuzhiyun FatalError("attempt to remap buffer as writable");
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (priv->pbo) {
78*4882a593Smuzhiyun glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
79*4882a593Smuzhiyun glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
80*4882a593Smuzhiyun pixmap->devPrivate.ptr = NULL;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun } else {
83*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM_MAP
84*4882a593Smuzhiyun struct gbm_bo *gbm = NULL;
85*4882a593Smuzhiyun uint32_t stride;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun RegionInit(&priv->prepare_region, box, 1);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (!priv->exporting)
90*4882a593Smuzhiyun gbm = glamor_gbm_bo_from_pixmap(screen, pixmap);
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun if (gbm) {
93*4882a593Smuzhiyun pixmap->devPrivate.ptr =
94*4882a593Smuzhiyun gbm_bo_map(gbm, 0, 0, pixmap->drawable.width,
95*4882a593Smuzhiyun pixmap->drawable.height,
96*4882a593Smuzhiyun (access == GLAMOR_ACCESS_RW) ?
97*4882a593Smuzhiyun GBM_BO_TRANSFER_READ_WRITE : GBM_BO_TRANSFER_READ,
98*4882a593Smuzhiyun &stride, &priv->map_data);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun if (pixmap->devPrivate.ptr) {
101*4882a593Smuzhiyun pixmap->devKind = stride;
102*4882a593Smuzhiyun priv->bo_mapped = TRUE;
103*4882a593Smuzhiyun priv->map_access = access;
104*4882a593Smuzhiyun goto done;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun #endif
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun if (glamor_priv->has_rw_pbo) {
110*4882a593Smuzhiyun if (priv->pbo == 0)
111*4882a593Smuzhiyun glGenBuffers(1, &priv->pbo);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun gl_usage = GL_STREAM_READ;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun glamor_priv->suppress_gl_out_of_memory_logging = true;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
118*4882a593Smuzhiyun glBufferData(GL_PIXEL_PACK_BUFFER,
119*4882a593Smuzhiyun pixmap->devKind * pixmap->drawable.height, NULL,
120*4882a593Smuzhiyun gl_usage);
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun glamor_priv->suppress_gl_out_of_memory_logging = false;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (glGetError() == GL_OUT_OF_MEMORY) {
125*4882a593Smuzhiyun if (!glamor_priv->logged_any_pbo_allocation_failure) {
126*4882a593Smuzhiyun LogMessageVerb(X_WARNING, 0, "glamor: Failed to allocate %d "
127*4882a593Smuzhiyun "bytes PBO due to GL_OUT_OF_MEMORY.\n",
128*4882a593Smuzhiyun pixmap->devKind * pixmap->drawable.height);
129*4882a593Smuzhiyun glamor_priv->logged_any_pbo_allocation_failure = true;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
132*4882a593Smuzhiyun glDeleteBuffers(1, &priv->pbo);
133*4882a593Smuzhiyun priv->pbo = 0;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if (!priv->pbo) {
138*4882a593Smuzhiyun pixmap->devPrivate.ptr = xallocarray(pixmap->devKind,
139*4882a593Smuzhiyun pixmap->drawable.height);
140*4882a593Smuzhiyun if (!pixmap->devPrivate.ptr)
141*4882a593Smuzhiyun return FALSE;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun priv->map_access = access;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun glamor_download_boxes(pixmap, RegionRects(®ion), RegionNumRects(®ion),
147*4882a593Smuzhiyun 0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if (priv->pbo) {
150*4882a593Smuzhiyun if (priv->map_access == GLAMOR_ACCESS_RW)
151*4882a593Smuzhiyun gl_access = GL_READ_WRITE;
152*4882a593Smuzhiyun else
153*4882a593Smuzhiyun gl_access = GL_READ_ONLY;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun pixmap->devPrivate.ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, gl_access);
156*4882a593Smuzhiyun glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun done:
160*4882a593Smuzhiyun RegionUninit(®ion);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (priv->bo_mapped) {
163*4882a593Smuzhiyun /* Finish all gpu commands before accessing the buffer */
164*4882a593Smuzhiyun if (!priv->gl_synced && !glamor_priv->gl_synced)
165*4882a593Smuzhiyun glamor_finish(screen);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun priv->gl_synced = TRUE;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun /* No prepared flag for directly mapping */
170*4882a593Smuzhiyun return TRUE;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun priv->prepared = TRUE;
174*4882a593Smuzhiyun return TRUE;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun /*
178*4882a593Smuzhiyun * When we're done with the drawable, unmap the PBO, reupload
179*4882a593Smuzhiyun * if we were writing to it and then unbind it to release the memory
180*4882a593Smuzhiyun */
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun void
glamor_finish_access_pixmap(PixmapPtr pixmap,Bool force)183*4882a593Smuzhiyun glamor_finish_access_pixmap(PixmapPtr pixmap, Bool force)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
188*4882a593Smuzhiyun return;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
191*4882a593Smuzhiyun if (priv->bo_mapped) {
192*4882a593Smuzhiyun if (priv->prepared)
193*4882a593Smuzhiyun FatalError("something wrong during buffer mapping");
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun /* Delay unmap to finalize when not forced */
196*4882a593Smuzhiyun if (force) {
197*4882a593Smuzhiyun pixmap->devPrivate.ptr = NULL;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun gbm_bo_unmap(priv->bo, priv->map_data);
200*4882a593Smuzhiyun priv->bo_mapped = FALSE;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun #endif
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (!priv->prepared)
206*4882a593Smuzhiyun return;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (priv->pbo) {
209*4882a593Smuzhiyun glBindBuffer(GL_PIXEL_UNPACK_BUFFER, priv->pbo);
210*4882a593Smuzhiyun glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
211*4882a593Smuzhiyun pixmap->devPrivate.ptr = NULL;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun if (priv->map_access == GLAMOR_ACCESS_RW) {
215*4882a593Smuzhiyun glamor_upload_boxes(pixmap,
216*4882a593Smuzhiyun RegionRects(&priv->prepare_region),
217*4882a593Smuzhiyun RegionNumRects(&priv->prepare_region),
218*4882a593Smuzhiyun 0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun RegionUninit(&priv->prepare_region);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (priv->pbo) {
224*4882a593Smuzhiyun glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
225*4882a593Smuzhiyun glDeleteBuffers(1, &priv->pbo);
226*4882a593Smuzhiyun priv->pbo = 0;
227*4882a593Smuzhiyun } else {
228*4882a593Smuzhiyun free(pixmap->devPrivate.ptr);
229*4882a593Smuzhiyun pixmap->devPrivate.ptr = NULL;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun priv->prepared = FALSE;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun Bool
glamor_prepare_access(DrawablePtr drawable,glamor_access_t access)236*4882a593Smuzhiyun glamor_prepare_access(DrawablePtr drawable, glamor_access_t access)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
239*4882a593Smuzhiyun BoxRec box;
240*4882a593Smuzhiyun int off_x, off_y;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun box.x1 = drawable->x + off_x;
245*4882a593Smuzhiyun box.x2 = box.x1 + drawable->width;
246*4882a593Smuzhiyun box.y1 = drawable->y + off_y;
247*4882a593Smuzhiyun box.y2 = box.y1 + drawable->height;
248*4882a593Smuzhiyun return glamor_prep_pixmap_box(pixmap, access, &box);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun Bool
glamor_prepare_access_box(DrawablePtr drawable,glamor_access_t access,int x,int y,int w,int h)252*4882a593Smuzhiyun glamor_prepare_access_box(DrawablePtr drawable, glamor_access_t access,
253*4882a593Smuzhiyun int x, int y, int w, int h)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
256*4882a593Smuzhiyun BoxRec box;
257*4882a593Smuzhiyun int off_x, off_y;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
260*4882a593Smuzhiyun box.x1 = drawable->x + x + off_x;
261*4882a593Smuzhiyun box.x2 = box.x1 + w;
262*4882a593Smuzhiyun box.y1 = drawable->y + y + off_y;
263*4882a593Smuzhiyun box.y2 = box.y1 + h;
264*4882a593Smuzhiyun return glamor_prep_pixmap_box(pixmap, access, &box);
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun void
glamor_finish_access(DrawablePtr drawable)268*4882a593Smuzhiyun glamor_finish_access(DrawablePtr drawable)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun glamor_finish_access_pixmap(glamor_get_drawable_pixmap(drawable), FALSE);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /*
274*4882a593Smuzhiyun * Make a picture ready to use with fb.
275*4882a593Smuzhiyun */
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun Bool
glamor_prepare_access_picture(PicturePtr picture,glamor_access_t access)278*4882a593Smuzhiyun glamor_prepare_access_picture(PicturePtr picture, glamor_access_t access)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun if (!picture || !picture->pDrawable)
281*4882a593Smuzhiyun return TRUE;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun return glamor_prepare_access(picture->pDrawable, access);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun Bool
glamor_prepare_access_picture_box(PicturePtr picture,glamor_access_t access,int x,int y,int w,int h)287*4882a593Smuzhiyun glamor_prepare_access_picture_box(PicturePtr picture, glamor_access_t access,
288*4882a593Smuzhiyun int x, int y, int w, int h)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun if (!picture || !picture->pDrawable)
291*4882a593Smuzhiyun return TRUE;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun /* If a transform is set, we don't know what the bounds is on the
294*4882a593Smuzhiyun * source, so just prepare the whole pixmap. XXX: We could
295*4882a593Smuzhiyun * potentially work out where in the source would be sampled based
296*4882a593Smuzhiyun * on the transform, and we don't need do do this for destination
297*4882a593Smuzhiyun * pixmaps at all.
298*4882a593Smuzhiyun */
299*4882a593Smuzhiyun if (picture->transform) {
300*4882a593Smuzhiyun return glamor_prepare_access_box(picture->pDrawable, access,
301*4882a593Smuzhiyun 0, 0,
302*4882a593Smuzhiyun picture->pDrawable->width,
303*4882a593Smuzhiyun picture->pDrawable->height);
304*4882a593Smuzhiyun } else {
305*4882a593Smuzhiyun return glamor_prepare_access_box(picture->pDrawable, access,
306*4882a593Smuzhiyun x, y, w, h);
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun void
glamor_finish_access_picture(PicturePtr picture)311*4882a593Smuzhiyun glamor_finish_access_picture(PicturePtr picture)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun if (!picture || !picture->pDrawable)
314*4882a593Smuzhiyun return;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun glamor_finish_access(picture->pDrawable);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /*
320*4882a593Smuzhiyun * Make a GC ready to use with fb. This just
321*4882a593Smuzhiyun * means making sure the appropriate fill pixmap is
322*4882a593Smuzhiyun * in CPU memory again
323*4882a593Smuzhiyun */
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun Bool
glamor_prepare_access_gc(GCPtr gc)326*4882a593Smuzhiyun glamor_prepare_access_gc(GCPtr gc)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun switch (gc->fillStyle) {
329*4882a593Smuzhiyun case FillTiled:
330*4882a593Smuzhiyun return glamor_prepare_access(&gc->tile.pixmap->drawable,
331*4882a593Smuzhiyun GLAMOR_ACCESS_RO);
332*4882a593Smuzhiyun case FillStippled:
333*4882a593Smuzhiyun case FillOpaqueStippled:
334*4882a593Smuzhiyun return glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RO);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun return TRUE;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /*
340*4882a593Smuzhiyun * Free any temporary CPU pixmaps for the GC
341*4882a593Smuzhiyun */
342*4882a593Smuzhiyun void
glamor_finish_access_gc(GCPtr gc)343*4882a593Smuzhiyun glamor_finish_access_gc(GCPtr gc)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun switch (gc->fillStyle) {
346*4882a593Smuzhiyun case FillTiled:
347*4882a593Smuzhiyun glamor_finish_access(&gc->tile.pixmap->drawable);
348*4882a593Smuzhiyun break;
349*4882a593Smuzhiyun case FillStippled:
350*4882a593Smuzhiyun case FillOpaqueStippled:
351*4882a593Smuzhiyun glamor_finish_access(&gc->stipple->drawable);
352*4882a593Smuzhiyun break;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun }
355