2 * Copyright © 2014 Keith Packard
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.
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
23 #include "glamor_priv.h"
24 #include "glamor_prepare.h"
25 #include "glamor_transfer.h"
28 * Make a drawable ready to draw with fb by
29 * creating a PBO large enough for the whole object
30 * and downloading all of the FBOs into it.
34 glamor_prep_drawable_box(DrawablePtr drawable
, glamor_access_t access
, BoxPtr box
)
36 ScreenPtr screen
= drawable
->pScreen
;
37 glamor_screen_private
*glamor_priv
= glamor_get_screen_private(screen
);
38 PixmapPtr pixmap
= glamor_get_drawable_pixmap(drawable
);
39 glamor_pixmap_private
*priv
= glamor_get_pixmap_private(pixmap
);
40 int gl_access
, gl_usage
;
44 if (priv
->type
== GLAMOR_DRM_ONLY
)
47 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv
))
50 glamor_make_current(glamor_priv
);
52 glamor_get_drawable_deltas(drawable
, pixmap
, &off_x
, &off_y
);
57 RegionInit(®ion
, box
, 1);
59 /* See if it's already mapped */
60 if (pixmap
->devPrivate
.ptr
) {
62 * Someone else has mapped this pixmap;
63 * we'll assume that it's directly mapped
64 * by a lower level driver
69 /* In X, multiple Drawables can be stored in the same Pixmap (such as
70 * each individual window in a non-composited screen pixmap, or the
71 * reparented window contents inside the window-manager-decorated window
72 * pixmap on a composited screen).
74 * As a result, when doing a series of mappings for a fallback, we may
75 * need to add more boxes to the set of data we've downloaded, as we go.
77 RegionSubtract(®ion
, ®ion
, &priv
->prepare_region
);
78 if (!RegionNotEmpty(®ion
))
81 if (access
== GLAMOR_ACCESS_RW
)
82 FatalError("attempt to remap buffer as writable");
85 glBindBuffer(GL_PIXEL_PACK_BUFFER
, priv
->pbo
);
86 glUnmapBuffer(GL_PIXEL_PACK_BUFFER
);
87 pixmap
->devPrivate
.ptr
= NULL
;
90 RegionInit(&priv
->prepare_region
, box
, 1);
92 if (glamor_priv
->has_rw_pbo
) {
94 glGenBuffers(1, &priv
->pbo
);
96 gl_usage
= GL_STREAM_READ
;
98 glamor_priv
->suppress_gl_out_of_memory_logging
= true;
100 glBindBuffer(GL_PIXEL_PACK_BUFFER
, priv
->pbo
);
101 glBufferData(GL_PIXEL_PACK_BUFFER
,
102 pixmap
->devKind
* pixmap
->drawable
.height
, NULL
,
105 glamor_priv
->suppress_gl_out_of_memory_logging
= false;
107 if (glGetError() == GL_OUT_OF_MEMORY
) {
108 if (!glamor_priv
->logged_any_pbo_allocation_failure
) {
109 LogMessageVerb(X_WARNING
, 0, "glamor: Failed to allocate %d "
110 "bytes PBO due to GL_OUT_OF_MEMORY.\n",
111 pixmap
->devKind
* pixmap
->drawable
.height
);
112 glamor_priv
->logged_any_pbo_allocation_failure
= true;
114 glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0);
115 glDeleteBuffers(1, &priv
->pbo
);
121 pixmap
->devPrivate
.ptr
= xallocarray(pixmap
->devKind
,
122 pixmap
->drawable
.height
);
123 if (!pixmap
->devPrivate
.ptr
)
126 priv
->map_access
= access
;
129 glamor_download_boxes(drawable
, RegionRects(®ion
), RegionNumRects(®ion
),
130 0, 0, 0, 0, pixmap
->devPrivate
.ptr
, pixmap
->devKind
);
132 RegionUninit(®ion
);
135 if (priv
->map_access
== GLAMOR_ACCESS_RW
)
136 gl_access
= GL_READ_WRITE
;
138 gl_access
= GL_READ_ONLY
;
140 pixmap
->devPrivate
.ptr
= glMapBuffer(GL_PIXEL_PACK_BUFFER
, gl_access
);
141 glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0);
144 priv
->prepared
= TRUE
;
149 * When we're done with the drawable, unmap the PBO, reupload
150 * if we were writing to it and then unbind it to release the memory
154 glamor_finish_access(DrawablePtr drawable
)
156 PixmapPtr pixmap
= glamor_get_drawable_pixmap(drawable
);
157 glamor_pixmap_private
*priv
= glamor_get_pixmap_private(pixmap
);
159 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv
))
166 !(glamor_drawable_effective_depth(drawable
) == 24 && pixmap
->drawable
.depth
== 32)) {
167 glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, priv
->pbo
);
168 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
169 pixmap
->devPrivate
.ptr
= NULL
;
172 if (priv
->map_access
== GLAMOR_ACCESS_RW
) {
173 glamor_upload_boxes(drawable
,
174 RegionRects(&priv
->prepare_region
),
175 RegionNumRects(&priv
->prepare_region
),
176 0, 0, 0, 0, pixmap
->devPrivate
.ptr
, pixmap
->devKind
);
179 RegionUninit(&priv
->prepare_region
);
182 if (glamor_drawable_effective_depth(drawable
) == 24 && pixmap
->drawable
.depth
== 32)
183 pixmap
->devPrivate
.ptr
= NULL
;
185 glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
187 glDeleteBuffers(1, &priv
->pbo
);
190 free(pixmap
->devPrivate
.ptr
);
191 pixmap
->devPrivate
.ptr
= NULL
;
194 priv
->prepared
= FALSE
;
198 glamor_prepare_access(DrawablePtr drawable
, glamor_access_t access
)
202 box
.x1
= drawable
->x
;
203 box
.x2
= box
.x1
+ drawable
->width
;
204 box
.y1
= drawable
->y
;
205 box
.y2
= box
.y1
+ drawable
->height
;
206 return glamor_prep_drawable_box(drawable
, access
, &box
);
210 glamor_prepare_access_box(DrawablePtr drawable
, glamor_access_t access
,
211 int x
, int y
, int w
, int h
)
215 box
.x1
= drawable
->x
+ x
;
217 box
.y1
= drawable
->y
+ y
;
219 return glamor_prep_drawable_box(drawable
, access
, &box
);
223 * Make a picture ready to use with fb.
227 glamor_prepare_access_picture(PicturePtr picture
, glamor_access_t access
)
229 if (!picture
|| !picture
->pDrawable
)
232 return glamor_prepare_access(picture
->pDrawable
, access
);
236 glamor_prepare_access_picture_box(PicturePtr picture
, glamor_access_t access
,
237 int x
, int y
, int w
, int h
)
239 if (!picture
|| !picture
->pDrawable
)
242 /* If a transform is set, we don't know what the bounds is on the
243 * source, so just prepare the whole pixmap. XXX: We could
244 * potentially work out where in the source would be sampled based
245 * on the transform, and we don't need do do this for destination
248 if (picture
->transform
) {
249 return glamor_prepare_access_box(picture
->pDrawable
, access
,
251 picture
->pDrawable
->width
,
252 picture
->pDrawable
->height
);
254 return glamor_prepare_access_box(picture
->pDrawable
, access
,
260 glamor_finish_access_picture(PicturePtr picture
)
262 if (!picture
|| !picture
->pDrawable
)
265 glamor_finish_access(picture
->pDrawable
);
269 * Make a GC ready to use with fb. This just
270 * means making sure the appropriate fill pixmap is
271 * in CPU memory again
275 glamor_prepare_access_gc(GCPtr gc
)
277 switch (gc
->fillStyle
) {
279 return glamor_prepare_access(&gc
->tile
.pixmap
->drawable
,
282 case FillOpaqueStippled
:
283 return glamor_prepare_access(&gc
->stipple
->drawable
, GLAMOR_ACCESS_RO
);
289 * Free any temporary CPU pixmaps for the GC
292 glamor_finish_access_gc(GCPtr gc
)
294 switch (gc
->fillStyle
) {
296 glamor_finish_access(&gc
->tile
.pixmap
->drawable
);
299 case FillOpaqueStippled
:
300 glamor_finish_access(&gc
->stipple
->drawable
);