135c4bbdfSmrg/* 235c4bbdfSmrg * Copyright © 2014 Keith Packard 335c4bbdfSmrg * 435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its 535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that 635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright 735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and 835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or 935c4bbdfSmrg * publicity pertaining to distribution of the software without specific, 1035c4bbdfSmrg * written prior permission. The copyright holders make no representations 1135c4bbdfSmrg * about the suitability of this software for any purpose. It is provided "as 1235c4bbdfSmrg * is" without express or implied warranty. 1335c4bbdfSmrg * 1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2035c4bbdfSmrg * OF THIS SOFTWARE. 2135c4bbdfSmrg */ 2235c4bbdfSmrg 2335c4bbdfSmrg#include "glamor_priv.h" 2435c4bbdfSmrg#include "glamor_prepare.h" 2535c4bbdfSmrg#include "glamor_transfer.h" 2635c4bbdfSmrg 2735c4bbdfSmrg/* 2835c4bbdfSmrg * Make a pixmap ready to draw with fb by 2935c4bbdfSmrg * creating a PBO large enough for the whole object 3035c4bbdfSmrg * and downloading all of the FBOs into it. 3135c4bbdfSmrg */ 3235c4bbdfSmrg 3335c4bbdfSmrgstatic Bool 3435c4bbdfSmrgglamor_prep_pixmap_box(PixmapPtr pixmap, glamor_access_t access, BoxPtr box) 3535c4bbdfSmrg{ 3635c4bbdfSmrg ScreenPtr screen = pixmap->drawable.pScreen; 3735c4bbdfSmrg glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 3835c4bbdfSmrg glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 3935c4bbdfSmrg int gl_access, gl_usage; 4035c4bbdfSmrg RegionRec region; 4135c4bbdfSmrg 4235c4bbdfSmrg if (priv->type == GLAMOR_DRM_ONLY) 4335c4bbdfSmrg return FALSE; 4435c4bbdfSmrg 4535c4bbdfSmrg if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv)) 4635c4bbdfSmrg return TRUE; 4735c4bbdfSmrg 4835c4bbdfSmrg glamor_make_current(glamor_priv); 4935c4bbdfSmrg 5035c4bbdfSmrg RegionInit(®ion, box, 1); 5135c4bbdfSmrg 5235c4bbdfSmrg /* See if it's already mapped */ 5335c4bbdfSmrg if (pixmap->devPrivate.ptr) { 5435c4bbdfSmrg /* 5535c4bbdfSmrg * Someone else has mapped this pixmap; 5635c4bbdfSmrg * we'll assume that it's directly mapped 5735c4bbdfSmrg * by a lower level driver 5835c4bbdfSmrg */ 5935c4bbdfSmrg if (!priv->prepared) 6035c4bbdfSmrg return TRUE; 6135c4bbdfSmrg 6235c4bbdfSmrg /* In X, multiple Drawables can be stored in the same Pixmap (such as 6335c4bbdfSmrg * each individual window in a non-composited screen pixmap, or the 6435c4bbdfSmrg * reparented window contents inside the window-manager-decorated window 6535c4bbdfSmrg * pixmap on a composited screen). 6635c4bbdfSmrg * 6735c4bbdfSmrg * As a result, when doing a series of mappings for a fallback, we may 6835c4bbdfSmrg * need to add more boxes to the set of data we've downloaded, as we go. 6935c4bbdfSmrg */ 7035c4bbdfSmrg RegionSubtract(®ion, ®ion, &priv->prepare_region); 7135c4bbdfSmrg if (!RegionNotEmpty(®ion)) 7235c4bbdfSmrg return TRUE; 7335c4bbdfSmrg 7435c4bbdfSmrg if (access == GLAMOR_ACCESS_RW) 7535c4bbdfSmrg FatalError("attempt to remap buffer as writable"); 7635c4bbdfSmrg 7735c4bbdfSmrg if (priv->pbo) { 7835c4bbdfSmrg glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo); 7935c4bbdfSmrg glUnmapBuffer(GL_PIXEL_PACK_BUFFER); 8035c4bbdfSmrg pixmap->devPrivate.ptr = NULL; 8135c4bbdfSmrg } 8235c4bbdfSmrg } else { 8335c4bbdfSmrg RegionInit(&priv->prepare_region, box, 1); 8435c4bbdfSmrg 8535c4bbdfSmrg if (glamor_priv->has_rw_pbo) { 8635c4bbdfSmrg if (priv->pbo == 0) 8735c4bbdfSmrg glGenBuffers(1, &priv->pbo); 8835c4bbdfSmrg 8935c4bbdfSmrg gl_usage = GL_STREAM_READ; 9035c4bbdfSmrg 915a7dfde8Smrg glamor_priv->suppress_gl_out_of_memory_logging = true; 925a7dfde8Smrg 9335c4bbdfSmrg glBindBuffer(GL_PIXEL_PACK_BUFFER, priv->pbo); 9435c4bbdfSmrg glBufferData(GL_PIXEL_PACK_BUFFER, 9535c4bbdfSmrg pixmap->devKind * pixmap->drawable.height, NULL, 9635c4bbdfSmrg gl_usage); 975a7dfde8Smrg 985a7dfde8Smrg glamor_priv->suppress_gl_out_of_memory_logging = false; 995a7dfde8Smrg 1005a7dfde8Smrg if (glGetError() == GL_OUT_OF_MEMORY) { 1015a7dfde8Smrg if (!glamor_priv->logged_any_pbo_allocation_failure) { 1025a7dfde8Smrg LogMessageVerb(X_WARNING, 0, "glamor: Failed to allocate %d " 1035a7dfde8Smrg "bytes PBO due to GL_OUT_OF_MEMORY.\n", 1045a7dfde8Smrg pixmap->devKind * pixmap->drawable.height); 1055a7dfde8Smrg glamor_priv->logged_any_pbo_allocation_failure = true; 1065a7dfde8Smrg } 1075a7dfde8Smrg glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 1085a7dfde8Smrg glDeleteBuffers(1, &priv->pbo); 1095a7dfde8Smrg priv->pbo = 0; 1105a7dfde8Smrg } 1115a7dfde8Smrg } 1125a7dfde8Smrg 1135a7dfde8Smrg if (!priv->pbo) { 11435c4bbdfSmrg pixmap->devPrivate.ptr = xallocarray(pixmap->devKind, 11535c4bbdfSmrg pixmap->drawable.height); 11635c4bbdfSmrg if (!pixmap->devPrivate.ptr) 11735c4bbdfSmrg return FALSE; 11835c4bbdfSmrg } 11935c4bbdfSmrg priv->map_access = access; 12035c4bbdfSmrg } 12135c4bbdfSmrg 12235c4bbdfSmrg glamor_download_boxes(pixmap, RegionRects(®ion), RegionNumRects(®ion), 12335c4bbdfSmrg 0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind); 12435c4bbdfSmrg 12535c4bbdfSmrg RegionUninit(®ion); 12635c4bbdfSmrg 1275a7dfde8Smrg if (priv->pbo) { 12835c4bbdfSmrg if (priv->map_access == GLAMOR_ACCESS_RW) 12935c4bbdfSmrg gl_access = GL_READ_WRITE; 13035c4bbdfSmrg else 13135c4bbdfSmrg gl_access = GL_READ_ONLY; 13235c4bbdfSmrg 13335c4bbdfSmrg pixmap->devPrivate.ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, gl_access); 13435c4bbdfSmrg glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 13535c4bbdfSmrg } 13635c4bbdfSmrg 13735c4bbdfSmrg priv->prepared = TRUE; 13835c4bbdfSmrg return TRUE; 13935c4bbdfSmrg} 14035c4bbdfSmrg 14135c4bbdfSmrg/* 14235c4bbdfSmrg * When we're done with the drawable, unmap the PBO, reupload 14335c4bbdfSmrg * if we were writing to it and then unbind it to release the memory 14435c4bbdfSmrg */ 14535c4bbdfSmrg 14635c4bbdfSmrgstatic void 14735c4bbdfSmrgglamor_fini_pixmap(PixmapPtr pixmap) 14835c4bbdfSmrg{ 14935c4bbdfSmrg glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap); 15035c4bbdfSmrg 15135c4bbdfSmrg if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv)) 15235c4bbdfSmrg return; 15335c4bbdfSmrg 15435c4bbdfSmrg if (!priv->prepared) 15535c4bbdfSmrg return; 15635c4bbdfSmrg 1575a7dfde8Smrg if (priv->pbo) { 15835c4bbdfSmrg glBindBuffer(GL_PIXEL_UNPACK_BUFFER, priv->pbo); 15935c4bbdfSmrg glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); 16035c4bbdfSmrg pixmap->devPrivate.ptr = NULL; 16135c4bbdfSmrg } 16235c4bbdfSmrg 16335c4bbdfSmrg if (priv->map_access == GLAMOR_ACCESS_RW) { 16435c4bbdfSmrg glamor_upload_boxes(pixmap, 16535c4bbdfSmrg RegionRects(&priv->prepare_region), 16635c4bbdfSmrg RegionNumRects(&priv->prepare_region), 16735c4bbdfSmrg 0, 0, 0, 0, pixmap->devPrivate.ptr, pixmap->devKind); 16835c4bbdfSmrg } 16935c4bbdfSmrg 17035c4bbdfSmrg RegionUninit(&priv->prepare_region); 17135c4bbdfSmrg 1725a7dfde8Smrg if (priv->pbo) { 17335c4bbdfSmrg glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 17435c4bbdfSmrg glDeleteBuffers(1, &priv->pbo); 17535c4bbdfSmrg priv->pbo = 0; 17635c4bbdfSmrg } else { 17735c4bbdfSmrg free(pixmap->devPrivate.ptr); 17835c4bbdfSmrg pixmap->devPrivate.ptr = NULL; 17935c4bbdfSmrg } 18035c4bbdfSmrg 18135c4bbdfSmrg priv->prepared = FALSE; 18235c4bbdfSmrg} 18335c4bbdfSmrg 18435c4bbdfSmrgBool 18535c4bbdfSmrgglamor_prepare_access(DrawablePtr drawable, glamor_access_t access) 18635c4bbdfSmrg{ 18735c4bbdfSmrg PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); 18835c4bbdfSmrg BoxRec box; 18935c4bbdfSmrg int off_x, off_y; 19035c4bbdfSmrg 19135c4bbdfSmrg glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); 19235c4bbdfSmrg 19335c4bbdfSmrg box.x1 = drawable->x + off_x; 19435c4bbdfSmrg box.x2 = box.x1 + drawable->width; 19535c4bbdfSmrg box.y1 = drawable->y + off_y; 19635c4bbdfSmrg box.y2 = box.y1 + drawable->height; 19735c4bbdfSmrg return glamor_prep_pixmap_box(pixmap, access, &box); 19835c4bbdfSmrg} 19935c4bbdfSmrg 20035c4bbdfSmrgBool 20135c4bbdfSmrgglamor_prepare_access_box(DrawablePtr drawable, glamor_access_t access, 20235c4bbdfSmrg int x, int y, int w, int h) 20335c4bbdfSmrg{ 20435c4bbdfSmrg PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); 20535c4bbdfSmrg BoxRec box; 20635c4bbdfSmrg int off_x, off_y; 20735c4bbdfSmrg 20835c4bbdfSmrg glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); 20935c4bbdfSmrg box.x1 = drawable->x + x + off_x; 21035c4bbdfSmrg box.x2 = box.x1 + w; 21135c4bbdfSmrg box.y1 = drawable->y + y + off_y; 21235c4bbdfSmrg box.y2 = box.y1 + h; 21335c4bbdfSmrg return glamor_prep_pixmap_box(pixmap, access, &box); 21435c4bbdfSmrg} 21535c4bbdfSmrg 21635c4bbdfSmrgvoid 21735c4bbdfSmrgglamor_finish_access(DrawablePtr drawable) 21835c4bbdfSmrg{ 21935c4bbdfSmrg glamor_fini_pixmap(glamor_get_drawable_pixmap(drawable)); 22035c4bbdfSmrg} 22135c4bbdfSmrg 22235c4bbdfSmrg/* 22335c4bbdfSmrg * Make a picture ready to use with fb. 22435c4bbdfSmrg */ 22535c4bbdfSmrg 22635c4bbdfSmrgBool 22735c4bbdfSmrgglamor_prepare_access_picture(PicturePtr picture, glamor_access_t access) 22835c4bbdfSmrg{ 22935c4bbdfSmrg if (!picture || !picture->pDrawable) 23035c4bbdfSmrg return TRUE; 23135c4bbdfSmrg 23235c4bbdfSmrg return glamor_prepare_access(picture->pDrawable, access); 23335c4bbdfSmrg} 23435c4bbdfSmrg 23535c4bbdfSmrgBool 23635c4bbdfSmrgglamor_prepare_access_picture_box(PicturePtr picture, glamor_access_t access, 23735c4bbdfSmrg int x, int y, int w, int h) 23835c4bbdfSmrg{ 23935c4bbdfSmrg if (!picture || !picture->pDrawable) 24035c4bbdfSmrg return TRUE; 24135c4bbdfSmrg 24235c4bbdfSmrg /* If a transform is set, we don't know what the bounds is on the 24335c4bbdfSmrg * source, so just prepare the whole pixmap. XXX: We could 24435c4bbdfSmrg * potentially work out where in the source would be sampled based 24535c4bbdfSmrg * on the transform, and we don't need do do this for destination 24635c4bbdfSmrg * pixmaps at all. 24735c4bbdfSmrg */ 24835c4bbdfSmrg if (picture->transform) { 24935c4bbdfSmrg return glamor_prepare_access_box(picture->pDrawable, access, 25035c4bbdfSmrg 0, 0, 25135c4bbdfSmrg picture->pDrawable->width, 25235c4bbdfSmrg picture->pDrawable->height); 25335c4bbdfSmrg } else { 25435c4bbdfSmrg return glamor_prepare_access_box(picture->pDrawable, access, 25535c4bbdfSmrg x, y, w, h); 25635c4bbdfSmrg } 25735c4bbdfSmrg} 25835c4bbdfSmrg 25935c4bbdfSmrgvoid 26035c4bbdfSmrgglamor_finish_access_picture(PicturePtr picture) 26135c4bbdfSmrg{ 26235c4bbdfSmrg if (!picture || !picture->pDrawable) 26335c4bbdfSmrg return; 26435c4bbdfSmrg 26535c4bbdfSmrg glamor_finish_access(picture->pDrawable); 26635c4bbdfSmrg} 26735c4bbdfSmrg 26835c4bbdfSmrg/* 26935c4bbdfSmrg * Make a GC ready to use with fb. This just 27035c4bbdfSmrg * means making sure the appropriate fill pixmap is 27135c4bbdfSmrg * in CPU memory again 27235c4bbdfSmrg */ 27335c4bbdfSmrg 27435c4bbdfSmrgBool 27535c4bbdfSmrgglamor_prepare_access_gc(GCPtr gc) 27635c4bbdfSmrg{ 27735c4bbdfSmrg switch (gc->fillStyle) { 27835c4bbdfSmrg case FillTiled: 27935c4bbdfSmrg return glamor_prepare_access(&gc->tile.pixmap->drawable, 28035c4bbdfSmrg GLAMOR_ACCESS_RO); 28135c4bbdfSmrg case FillStippled: 28235c4bbdfSmrg case FillOpaqueStippled: 28335c4bbdfSmrg return glamor_prepare_access(&gc->stipple->drawable, GLAMOR_ACCESS_RO); 28435c4bbdfSmrg } 28535c4bbdfSmrg return TRUE; 28635c4bbdfSmrg} 28735c4bbdfSmrg 28835c4bbdfSmrg/* 28935c4bbdfSmrg * Free any temporary CPU pixmaps for the GC 29035c4bbdfSmrg */ 29135c4bbdfSmrgvoid 29235c4bbdfSmrgglamor_finish_access_gc(GCPtr gc) 29335c4bbdfSmrg{ 29435c4bbdfSmrg switch (gc->fillStyle) { 29535c4bbdfSmrg case FillTiled: 29635c4bbdfSmrg glamor_finish_access(&gc->tile.pixmap->drawable); 29735c4bbdfSmrg break; 29835c4bbdfSmrg case FillStippled: 29935c4bbdfSmrg case FillOpaqueStippled: 30035c4bbdfSmrg glamor_finish_access(&gc->stipple->drawable); 30135c4bbdfSmrg break; 30235c4bbdfSmrg } 30335c4bbdfSmrg} 304