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 pixmap 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_pixmap_box(PixmapPtr pixmap, glamor_access_t access, BoxPtr box)
36
ScreenPtr screen = pixmap->drawable.pScreen;
37
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
38
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
39
int gl_access, gl_usage;
42
if (priv->type == GLAMOR_DRM_ONLY)
45
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
48
glamor_make_current(glamor_priv);
50
RegionInit(®ion, box, 1);
52
/* See if it's already mapped */
53
if (pixmap->devPrivate.ptr) {
55
* Someone else has mapped this pixmap;
56
* we'll assume that it's directly mapped
57
* by a lower level driver
62
/* In X, multiple Drawables can be stored in the same Pixmap (such as
63
* each individual window in a non-composited screen pixmap, or the
64
* reparented window contents inside the window-manager-decorated window
65
* pixmap on a composited screen).
67
* As a result, when doing a series of mappings for a fallback, we may
68
* need to add more boxes to the set of data we've downloaded, as we go.
70
RegionSubtract(®ion, ®ion, &priv->prepare_region);
71
if (!RegionNotEmpty(®ion))
74
if (access == GLAMOR_ACCESS_RW)
75
FatalError("attempt to remap buffer as writable");
78
glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
79
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
80
pixmap->devPrivate.ptr = NULL;
83
RegionInit(&priv->prepare_region, box, 1);
85
if (glamor_priv->has_rw_pbo) {
87
glGenBuffers(1, &priv->pbo);
89
gl_usage = GL_STREAM_READ;
91
glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
92
glBufferData(GL_PIXEL_PACK_BUFFER,
93
pixmap->devKind * pixmap->drawable.height, NULL,
96
pixmap->devPrivate.ptr = xallocarray(pixmap->devKind,
97
pixmap->drawable.height);
98
if (!pixmap->devPrivate.ptr)
101
priv->map_access = access;
104
glamor_download_boxes(pixmap, RegionRects(®ion), RegionNumRects(®ion),
105
0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
107
RegionUninit(®ion);
109
if (glamor_priv->has_rw_pbo) {
110
if (priv->map_access == GLAMOR_ACCESS_RW)
111
gl_access = GL_READ_WRITE;
113
gl_access = GL_READ_ONLY;
115
pixmap->devPrivate.ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, gl_access);
116
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
119
priv->prepared = TRUE;
124
* When we're done with the drawable, unmap the PBO, reupload
125
* if we were writing to it and then unbind it to release the memory
129
glamor_fini_pixmap(PixmapPtr pixmap)
131
ScreenPtr screen = pixmap->drawable.pScreen;
132
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
133
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
135
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
141
if (glamor_priv->has_rw_pbo) {
142
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, priv->pbo);
143
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
144
pixmap->devPrivate.ptr = NULL;
147
if (priv->map_access == GLAMOR_ACCESS_RW) {
148
glamor_upload_boxes(pixmap,
149
RegionRects(&priv->prepare_region),
150
RegionNumRects(&priv->prepare_region),
151
0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
154
RegionUninit(&priv->prepare_region);
156
if (glamor_priv->has_rw_pbo) {
157
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
158
glDeleteBuffers(1, &priv->pbo);
161
free(pixmap->devPrivate.ptr);
162
pixmap->devPrivate.ptr = NULL;
165
priv->prepared = FALSE;
169
glamor_prepare_access(DrawablePtr drawable, glamor_access_t access)
171
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
175
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
177
box.x1 = drawable->x + off_x;
178
box.x2 = box.x1 + drawable->width;
179
box.y1 = drawable->y + off_y;
180
box.y2 = box.y1 + drawable->height;
181
return glamor_prep_pixmap_box(pixmap, access, &box);
185
glamor_prepare_access_box(DrawablePtr drawable, glamor_access_t access,
186
int x, int y, int w, int h)
188
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
192
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
193
box.x1 = drawable->x + x + off_x;
195
box.y1 = drawable->y + y + off_y;
197
return glamor_prep_pixmap_box(pixmap, access, &box);
201
glamor_finish_access(DrawablePtr drawable)
203
glamor_fini_pixmap(glamor_get_drawable_pixmap(drawable));
207
* Make a picture ready to use with fb.
211
glamor_prepare_access_picture(PicturePtr picture, glamor_access_t access)
213
if (!picture || !picture->pDrawable)
216
return glamor_prepare_access(picture->pDrawable, access);
220
glamor_prepare_access_picture_box(PicturePtr picture, glamor_access_t access,
221
int x, int y, int w, int h)
223
if (!picture || !picture->pDrawable)
226
/* If a transform is set, we don't know what the bounds is on the
227
* source, so just prepare the whole pixmap. XXX: We could
228
* potentially work out where in the source would be sampled based
229
* on the transform, and we don't need do do this for destination
232
if (picture->transform) {
233
return glamor_prepare_access_box(picture->pDrawable, access,
235
picture->pDrawable->width,
236
picture->pDrawable->height);
238
return glamor_prepare_access_box(picture->pDrawable, access,
244
glamor_finish_access_picture(PicturePtr picture)
246
if (!picture || !picture->pDrawable)
249
glamor_finish_access(picture->pDrawable);
253
* Make a GC ready to use with fb. This just
254
* means making sure the appropriate fill pixmap is
255
* in CPU memory again
259
glamor_prepare_access_gc(GCPtr gc)
261
switch (gc->fillStyle) {
263
return glamor_prepare_access(&gc->tile.pixmap->drawable,
266
case FillOpaqueStippled:
267
return glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RO);
273
* Free any temporary CPU pixmaps for the GC
276
glamor_finish_access_gc(GCPtr gc)
278
switch (gc->fillStyle) {
280
glamor_finish_access(&gc->tile.pixmap->drawable);
283
case FillOpaqueStippled:
284
glamor_finish_access(&gc->stipple->drawable);