os: if inet_ntop() is available, use it for IPv4 addresses as well
[xserver.git] / glamor / glamor_prepare.c
blobfba875e28e7fdcf9cd28263aba4e5d204f30b6df
1 /*
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
20 * OF THIS SOFTWARE.
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.
33 static Bool
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;
41 RegionRec region;
42 int off_x, off_y;
44 if (priv->type == GLAMOR_DRM_ONLY)
45 return FALSE;
47 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
48 return TRUE;
50 glamor_make_current(glamor_priv);
52 glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
53 box->x1 += off_x;
54 box->x2 += off_x;
55 box->y1 += off_y;
56 box->y2 += off_y;
57 RegionInit(&region, 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
66 if (!priv->prepared)
67 return TRUE;
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(&region, &region, &priv->prepare_region);
78 if (!RegionNotEmpty(&region))
79 return TRUE;
81 if (access == GLAMOR_ACCESS_RW)
82 FatalError("attempt to remap buffer as writable");
84 if (priv->pbo) {
85 glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
86 glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
87 pixmap->devPrivate.ptr = NULL;
89 } else {
90 RegionInit(&priv->prepare_region, box, 1);
92 if (glamor_priv->has_rw_pbo) {
93 if (priv->pbo == 0)
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,
103 gl_usage);
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);
116 priv->pbo = 0;
120 if (!priv->pbo) {
121 pixmap->devPrivate.ptr = xallocarray(pixmap->devKind,
122 pixmap->drawable.height);
123 if (!pixmap->devPrivate.ptr)
124 return FALSE;
126 priv->map_access = access;
129 glamor_download_boxes(drawable, RegionRects(&region), RegionNumRects(&region),
130 0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
132 RegionUninit(&region);
134 if (priv->pbo) {
135 if (priv->map_access == GLAMOR_ACCESS_RW)
136 gl_access = GL_READ_WRITE;
137 else
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;
145 return 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
153 void
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))
160 return;
162 if (!priv->prepared)
163 return;
165 if (priv->pbo &&
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);
181 if (priv->pbo) {
182 if (glamor_drawable_effective_depth(drawable) == 24 && pixmap->drawable.depth == 32)
183 pixmap->devPrivate.ptr = NULL;
184 else
185 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
187 glDeleteBuffers(1, &priv->pbo);
188 priv->pbo = 0;
189 } else {
190 free(pixmap->devPrivate.ptr);
191 pixmap->devPrivate.ptr = NULL;
194 priv->prepared = FALSE;
197 Bool
198 glamor_prepare_access(DrawablePtr drawable, glamor_access_t access)
200 BoxRec box;
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);
209 Bool
210 glamor_prepare_access_box(DrawablePtr drawable, glamor_access_t access,
211 int x, int y, int w, int h)
213 BoxRec box;
215 box.x1 = drawable->x + x;
216 box.x2 = box.x1 + w;
217 box.y1 = drawable->y + y;
218 box.y2 = box.y1 + h;
219 return glamor_prep_drawable_box(drawable, access, &box);
223 * Make a picture ready to use with fb.
226 Bool
227 glamor_prepare_access_picture(PicturePtr picture, glamor_access_t access)
229 if (!picture || !picture->pDrawable)
230 return TRUE;
232 return glamor_prepare_access(picture->pDrawable, access);
235 Bool
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)
240 return TRUE;
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
246 * pixmaps at all.
248 if (picture->transform) {
249 return glamor_prepare_access_box(picture->pDrawable, access,
250 0, 0,
251 picture->pDrawable->width,
252 picture->pDrawable->height);
253 } else {
254 return glamor_prepare_access_box(picture->pDrawable, access,
255 x, y, w, h);
259 void
260 glamor_finish_access_picture(PicturePtr picture)
262 if (!picture || !picture->pDrawable)
263 return;
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
274 Bool
275 glamor_prepare_access_gc(GCPtr gc)
277 switch (gc->fillStyle) {
278 case FillTiled:
279 return glamor_prepare_access(&gc->tile.pixmap->drawable,
280 GLAMOR_ACCESS_RO);
281 case FillStippled:
282 case FillOpaqueStippled:
283 return glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RO);
285 return TRUE;
289 * Free any temporary CPU pixmaps for the GC
291 void
292 glamor_finish_access_gc(GCPtr gc)
294 switch (gc->fillStyle) {
295 case FillTiled:
296 glamor_finish_access(&gc->tile.pixmap->drawable);
297 break;
298 case FillStippled:
299 case FillOpaqueStippled:
300 glamor_finish_access(&gc->stipple->drawable);
301 break;