sync code with last improvements from OpenBSD
This commit is contained in:
commit
88965415ff
26235 changed files with 29195616 additions and 0 deletions
303
xserver/glamor/glamor_prepare.c
Normal file
303
xserver/glamor/glamor_prepare.c
Normal file
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* Copyright © 2014 Keith Packard
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "glamor_priv.h"
|
||||
#include "glamor_prepare.h"
|
||||
#include "glamor_transfer.h"
|
||||
|
||||
/*
|
||||
* Make a pixmap ready to draw with fb by
|
||||
* creating a PBO large enough for the whole object
|
||||
* and downloading all of the FBOs into it.
|
||||
*/
|
||||
|
||||
static Bool
|
||||
glamor_prep_pixmap_box(PixmapPtr pixmap, glamor_access_t access, BoxPtr box)
|
||||
{
|
||||
ScreenPtr screen = pixmap->drawable.pScreen;
|
||||
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
|
||||
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
|
||||
int gl_access, gl_usage;
|
||||
RegionRec region;
|
||||
|
||||
if (priv->type == GLAMOR_DRM_ONLY)
|
||||
return FALSE;
|
||||
|
||||
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
|
||||
return TRUE;
|
||||
|
||||
glamor_make_current(glamor_priv);
|
||||
|
||||
RegionInit(®ion, box, 1);
|
||||
|
||||
/* See if it's already mapped */
|
||||
if (pixmap->devPrivate.ptr) {
|
||||
/*
|
||||
* Someone else has mapped this pixmap;
|
||||
* we'll assume that it's directly mapped
|
||||
* by a lower level driver
|
||||
*/
|
||||
if (!priv->prepared)
|
||||
return TRUE;
|
||||
|
||||
/* In X, multiple Drawables can be stored in the same Pixmap (such as
|
||||
* each individual window in a non-composited screen pixmap, or the
|
||||
* reparented window contents inside the window-manager-decorated window
|
||||
* pixmap on a composited screen).
|
||||
*
|
||||
* As a result, when doing a series of mappings for a fallback, we may
|
||||
* need to add more boxes to the set of data we've downloaded, as we go.
|
||||
*/
|
||||
RegionSubtract(®ion, ®ion, &priv->prepare_region);
|
||||
if (!RegionNotEmpty(®ion))
|
||||
return TRUE;
|
||||
|
||||
if (access == GLAMOR_ACCESS_RW)
|
||||
FatalError("attempt to remap buffer as writable");
|
||||
|
||||
if (priv->pbo) {
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
|
||||
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
||||
pixmap->devPrivate.ptr = NULL;
|
||||
}
|
||||
} else {
|
||||
RegionInit(&priv->prepare_region, box, 1);
|
||||
|
||||
if (glamor_priv->has_rw_pbo) {
|
||||
if (priv->pbo == 0)
|
||||
glGenBuffers(1, &priv->pbo);
|
||||
|
||||
gl_usage = GL_STREAM_READ;
|
||||
|
||||
glamor_priv->suppress_gl_out_of_memory_logging = true;
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER,
|
||||
pixmap->devKind * pixmap->drawable.height, NULL,
|
||||
gl_usage);
|
||||
|
||||
glamor_priv->suppress_gl_out_of_memory_logging = false;
|
||||
|
||||
if (glGetError() == GL_OUT_OF_MEMORY) {
|
||||
if (!glamor_priv->logged_any_pbo_allocation_failure) {
|
||||
LogMessageVerb(X_WARNING, 0, "glamor: Failed to allocate %d "
|
||||
"bytes PBO due to GL_OUT_OF_MEMORY.\n",
|
||||
pixmap->devKind * pixmap->drawable.height);
|
||||
glamor_priv->logged_any_pbo_allocation_failure = true;
|
||||
}
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
glDeleteBuffers(1, &priv->pbo);
|
||||
priv->pbo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!priv->pbo) {
|
||||
pixmap->devPrivate.ptr = xallocarray(pixmap->devKind,
|
||||
pixmap->drawable.height);
|
||||
if (!pixmap->devPrivate.ptr)
|
||||
return FALSE;
|
||||
}
|
||||
priv->map_access = access;
|
||||
}
|
||||
|
||||
glamor_download_boxes(pixmap, RegionRects(®ion), RegionNumRects(®ion),
|
||||
0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
|
||||
|
||||
RegionUninit(®ion);
|
||||
|
||||
if (priv->pbo) {
|
||||
if (priv->map_access == GLAMOR_ACCESS_RW)
|
||||
gl_access = GL_READ_WRITE;
|
||||
else
|
||||
gl_access = GL_READ_ONLY;
|
||||
|
||||
pixmap->devPrivate.ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, gl_access);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
priv->prepared = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we're done with the drawable, unmap the PBO, reupload
|
||||
* if we were writing to it and then unbind it to release the memory
|
||||
*/
|
||||
|
||||
static void
|
||||
glamor_fini_pixmap(PixmapPtr pixmap)
|
||||
{
|
||||
glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
|
||||
|
||||
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
|
||||
return;
|
||||
|
||||
if (!priv->prepared)
|
||||
return;
|
||||
|
||||
if (priv->pbo) {
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, priv->pbo);
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
pixmap->devPrivate.ptr = NULL;
|
||||
}
|
||||
|
||||
if (priv->map_access == GLAMOR_ACCESS_RW) {
|
||||
glamor_upload_boxes(pixmap,
|
||||
RegionRects(&priv->prepare_region),
|
||||
RegionNumRects(&priv->prepare_region),
|
||||
0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind);
|
||||
}
|
||||
|
||||
RegionUninit(&priv->prepare_region);
|
||||
|
||||
if (priv->pbo) {
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glDeleteBuffers(1, &priv->pbo);
|
||||
priv->pbo = 0;
|
||||
} else {
|
||||
free(pixmap->devPrivate.ptr);
|
||||
pixmap->devPrivate.ptr = NULL;
|
||||
}
|
||||
|
||||
priv->prepared = FALSE;
|
||||
}
|
||||
|
||||
Bool
|
||||
glamor_prepare_access(DrawablePtr drawable, glamor_access_t access)
|
||||
{
|
||||
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
|
||||
BoxRec box;
|
||||
int off_x, off_y;
|
||||
|
||||
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
|
||||
|
||||
box.x1 = drawable->x + off_x;
|
||||
box.x2 = box.x1 + drawable->width;
|
||||
box.y1 = drawable->y + off_y;
|
||||
box.y2 = box.y1 + drawable->height;
|
||||
return glamor_prep_pixmap_box(pixmap, access, &box);
|
||||
}
|
||||
|
||||
Bool
|
||||
glamor_prepare_access_box(DrawablePtr drawable, glamor_access_t access,
|
||||
int x, int y, int w, int h)
|
||||
{
|
||||
PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
|
||||
BoxRec box;
|
||||
int off_x, off_y;
|
||||
|
||||
glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
|
||||
box.x1 = drawable->x + x + off_x;
|
||||
box.x2 = box.x1 + w;
|
||||
box.y1 = drawable->y + y + off_y;
|
||||
box.y2 = box.y1 + h;
|
||||
return glamor_prep_pixmap_box(pixmap, access, &box);
|
||||
}
|
||||
|
||||
void
|
||||
glamor_finish_access(DrawablePtr drawable)
|
||||
{
|
||||
glamor_fini_pixmap(glamor_get_drawable_pixmap(drawable));
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a picture ready to use with fb.
|
||||
*/
|
||||
|
||||
Bool
|
||||
glamor_prepare_access_picture(PicturePtr picture, glamor_access_t access)
|
||||
{
|
||||
if (!picture || !picture->pDrawable)
|
||||
return TRUE;
|
||||
|
||||
return glamor_prepare_access(picture->pDrawable, access);
|
||||
}
|
||||
|
||||
Bool
|
||||
glamor_prepare_access_picture_box(PicturePtr picture, glamor_access_t access,
|
||||
int x, int y, int w, int h)
|
||||
{
|
||||
if (!picture || !picture->pDrawable)
|
||||
return TRUE;
|
||||
|
||||
/* If a transform is set, we don't know what the bounds is on the
|
||||
* source, so just prepare the whole pixmap. XXX: We could
|
||||
* potentially work out where in the source would be sampled based
|
||||
* on the transform, and we don't need do do this for destination
|
||||
* pixmaps at all.
|
||||
*/
|
||||
if (picture->transform) {
|
||||
return glamor_prepare_access_box(picture->pDrawable, access,
|
||||
0, 0,
|
||||
picture->pDrawable->width,
|
||||
picture->pDrawable->height);
|
||||
} else {
|
||||
return glamor_prepare_access_box(picture->pDrawable, access,
|
||||
x, y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
glamor_finish_access_picture(PicturePtr picture)
|
||||
{
|
||||
if (!picture || !picture->pDrawable)
|
||||
return;
|
||||
|
||||
glamor_finish_access(picture->pDrawable);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a GC ready to use with fb. This just
|
||||
* means making sure the appropriate fill pixmap is
|
||||
* in CPU memory again
|
||||
*/
|
||||
|
||||
Bool
|
||||
glamor_prepare_access_gc(GCPtr gc)
|
||||
{
|
||||
switch (gc->fillStyle) {
|
||||
case FillTiled:
|
||||
return glamor_prepare_access(&gc->tile.pixmap->drawable,
|
||||
GLAMOR_ACCESS_RO);
|
||||
case FillStippled:
|
||||
case FillOpaqueStippled:
|
||||
return glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RO);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free any temporary CPU pixmaps for the GC
|
||||
*/
|
||||
void
|
||||
glamor_finish_access_gc(GCPtr gc)
|
||||
{
|
||||
switch (gc->fillStyle) {
|
||||
case FillTiled:
|
||||
glamor_finish_access(&gc->tile.pixmap->drawable);
|
||||
break;
|
||||
case FillStippled:
|
||||
case FillOpaqueStippled:
|
||||
glamor_finish_access(&gc->stipple->drawable);
|
||||
break;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue