From 761fffbb759fe8a3f2e6eacce6e5831f91025ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 10 Jan 2014 11:46:53 +0900 Subject: [PATCH] glamor: Reinstate wrappers to make software fallbacks a little less inefficient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michel Dänzer --- src/Makefile.am | 2 + src/radeon_glamor.c | 64 +- src/radeon_glamor.h | 5 + src/radeon_glamor_wrappers.c | 1870 ++++++++++++++++++++++++++++++++++++++++++ src/radeon_glamor_wrappers.h | 178 ++++ 5 files changed, 2117 insertions(+), 2 deletions(-) create mode 100644 src/radeon_glamor_wrappers.c create mode 100644 src/radeon_glamor_wrappers.h diff --git a/src/Makefile.am b/src/Makefile.am index e23dc1d..4c88e86 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,6 +64,7 @@ if GLAMOR AM_CFLAGS += @LIBGLAMOR_CFLAGS@ radeon_drv_la_LIBADD += @LIBGLAMOR_LIBS@ radeon_drv_la_SOURCES += \ + radeon_glamor_wrappers.c \ radeon_glamor.c endif @@ -93,6 +94,7 @@ EXTRA_DIST = \ radeon_exa_funcs.c \ radeon_exa_shared.h \ radeon_glamor.h \ + radeon_glamor_wrappers.h \ radeon.h \ radeon_probe.h \ radeon_reg.h \ diff --git a/src/radeon_glamor.c b/src/radeon_glamor.c index bd731a8..c86f32d 100644 --- a/src/radeon_glamor.c +++ b/src/radeon_glamor.c @@ -165,6 +165,61 @@ Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap) return priv && priv->bo; } +Bool radeon_glamor_prepare_access(PixmapPtr pixmap, glamor_access_t access) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen); + struct radeon_bo *bo; + int ret; + + if (access == GLAMOR_GPU_ACCESS_RW || access == GLAMOR_GPU_ACCESS_RO) + return TRUE; + + bo = radeon_get_pixmap_bo(pixmap); + if (bo) { + /* When falling back to swrast, flush all pending operations */ + radeon_glamor_flush(scrn); + + ret = radeon_bo_map(bo, 1); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "%s: bo map (tiling_flags %d, access %d) failed: %s\n", + __FUNCTION__, + radeon_get_pixmap_private(pixmap)->tiling_flags, + access, + strerror(-ret)); + return FALSE; + } + + pixmap->devPrivate.ptr = bo->ptr; + } + + return TRUE; +} + +void +radeon_glamor_finish_access(PixmapPtr pixmap, glamor_access_t access) +{ + struct radeon_bo *bo; + + switch(access) { + case GLAMOR_GPU_ACCESS_RW: + case GLAMOR_GPU_ACCESS_RO: + break; + case GLAMOR_CPU_ACCESS_RO: + case GLAMOR_CPU_ACCESS_RW: + bo = radeon_get_pixmap_bo(pixmap); + if (bo) { + radeon_bo_unmap(bo); + pixmap->devPrivate.ptr = NULL; + } + break; + default: + ErrorF("Invalid access mode %d\n", access); + } + + return; +} + #ifdef CREATE_PIXMAP_USAGE_SHARED #define RADEON_CREATE_PIXMAP_SHARED (CREATE_PIXMAP_USAGE_SHARED | RADEON_CREATE_PIXMAP_DRI2) #else @@ -315,8 +370,7 @@ radeon_glamor_init(ScreenPtr screen) { ScrnInfoPtr scrn = xf86ScreenToScrn(screen); - if (!glamor_init(screen, GLAMOR_INVERTED_Y_AXIS | GLAMOR_USE_EGL_SCREEN | - GLAMOR_USE_SCREEN | GLAMOR_USE_PICTURE_SCREEN)) { + if (!glamor_init(screen, GLAMOR_INVERTED_Y_AXIS | GLAMOR_USE_EGL_SCREEN)) { xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to initialize glamor.\n"); return FALSE; @@ -335,6 +389,12 @@ radeon_glamor_init(ScreenPtr screen) #endif return FALSE; + if (!glamor_screen_init(screen)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "GLAMOR initialization failed\n"); + return FALSE; + } + screen->CreatePixmap = radeon_glamor_create_pixmap; screen->DestroyPixmap = radeon_glamor_destroy_pixmap; #ifdef RADEON_PIXMAP_SHARING diff --git a/src/radeon_glamor.h b/src/radeon_glamor.h index 36addd7..3076d54 100644 --- a/src/radeon_glamor.h +++ b/src/radeon_glamor.h @@ -30,6 +30,7 @@ #include "xf86xv.h" #ifdef USE_GLAMOR +#include "radeon_glamor_wrappers.h" #include "radeon_surface.h" Bool radeon_glamor_pre_init(ScrnInfoPtr scrn); @@ -43,6 +44,8 @@ Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap); void radeon_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst); Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap); +Bool radeon_glamor_prepare_access(PixmapPtr pixmap, glamor_access_t access); +void radeon_glamor_finish_access(PixmapPtr pixmap, glamor_access_t access); XF86VideoAdaptorPtr radeon_glamor_xv_init(ScreenPtr pScreen, int num_adapt); @@ -88,6 +91,8 @@ static inline Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap) { retu static inline void radeon_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst) {} static inline Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap) { return FALSE; } +static inline Bool radeon_glamor_prepare_access(PixmapPtr pixmap, int access) { return FALSE; } +static inline void radeon_glamor_finish_access(PixmapPtr pixmap, int access) {} static inline struct radeon_pixmap *radeon_get_pixmap_private(PixmapPtr pixmap) { return NULL; } diff --git a/src/radeon_glamor_wrappers.c b/src/radeon_glamor_wrappers.c new file mode 100644 index 0000000..743b460 --- /dev/null +++ b/src/radeon_glamor_wrappers.c @@ -0,0 +1,1870 @@ +/* + * Copyright © 2001 Keith Packard + * 2010 Intel Corporation + * 2012 Advanced Micro Devices, Inc. + * + * Partly based on code Copyright © 2008 Red Hat, Inc. + * Partly based on code Copyright © 2000 SuSE, Inc. + * + * Partly based on code that is Copyright © The XFree86 Project Inc. + * + * 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 opyright 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. + */ + + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "radeon_glamor_wrappers.h" +#include "mipict.h" + + +#if HAS_DEVPRIVATEKEYREC +DevPrivateKeyRec glamor_screen_index; +#else +int glamor_screen_index; +#endif + +/** + * glamor_get_drawable_pixmap() returns a backing pixmap for a given drawable. + * + * @param pDrawable the drawable being requested. + * + * This function returns the backing pixmap for a drawable, whether it is a + * redirected window, unredirected window, or already a pixmap. Note that + * coordinate translation is needed when drawing to the backing pixmap of a + * redirected window, and the translation coordinates are provided by calling + * glamor_get_drawable_pixmap() on the drawable. + */ +static PixmapPtr glamor_get_drawable_pixmap(DrawablePtr pDrawable) +{ + if (pDrawable->type == DRAWABLE_WINDOW) + return pDrawable->pScreen-> + GetWindowPixmap((WindowPtr) pDrawable); + else + return (PixmapPtr) pDrawable; +} + +/** + * Sets the offsets to add to coordinates to make them address the same bits in + * the backing drawable. These coordinates are nonzero only for redirected + * windows. + */ +static void +glamor_get_drawable_deltas(DrawablePtr pDrawable, PixmapPtr pPixmap, + int *xp, int *yp) +{ +#ifdef COMPOSITE + if (pDrawable->type == DRAWABLE_WINDOW) { + *xp = -pPixmap->screen_x; + *yp = -pPixmap->screen_y; + return; + } +#endif + + *xp = 0; + *yp = 0; +} + +/** + * glamor_drawable_is_offscreen() is a convenience wrapper for + * radeon_glamor_pixmap_is_offscreen(). + */ +static Bool glamor_drawable_is_offscreen(DrawablePtr pDrawable) +{ + return radeon_glamor_pixmap_is_offscreen(glamor_get_drawable_pixmap(pDrawable)); +} + +/** + * glamor_prepare_access() is GLAMOR's wrapper for the driver's PrepareAccess() handler. + * + * It deals with waiting for synchronization with the card, determining if + * PrepareAccess() is necessary, and working around PrepareAccess() failure. + */ +static Bool glamor_prepare_access(DrawablePtr pDrawable, glamor_access_t access) +{ + PixmapPtr pPixmap = glamor_get_drawable_pixmap(pDrawable); + + return radeon_glamor_prepare_access(pPixmap, access); +} + +/** + * glamor_finish_access() is GLAMOR's wrapper for the driver's finish_access() handler. + * + * It deals with calling the driver's finish_access() only if necessary. + */ +static void glamor_finish_access(DrawablePtr pDrawable, glamor_access_t access) +{ + PixmapPtr pPixmap = glamor_get_drawable_pixmap(pDrawable); + + radeon_glamor_finish_access(pPixmap, access); +} + +static Bool glamor_prepare_access_window(WindowPtr pWin) +{ + if (pWin->backgroundState == BackgroundPixmap) { + if (!glamor_prepare_access + (&pWin->background.pixmap->drawable, GLAMOR_CPU_ACCESS_RO)) + return FALSE; + } + + if (pWin->borderIsPixel == FALSE) { + if (!glamor_prepare_access + (&pWin->border.pixmap->drawable, GLAMOR_CPU_ACCESS_RO)) { + if (pWin->backgroundState == BackgroundPixmap) + glamor_finish_access(&pWin->background.pixmap-> + drawable, GLAMOR_CPU_ACCESS_RO); + return FALSE; + } + } + return TRUE; +} + +static void glamor_finish_access_window(WindowPtr pWin) +{ + if (pWin->backgroundState == BackgroundPixmap) + glamor_finish_access(&pWin->background.pixmap->drawable, GLAMOR_CPU_ACCESS_RO); + + if (pWin->borderIsPixel == FALSE) + glamor_finish_access(&pWin->border.pixmap->drawable, GLAMOR_CPU_ACCESS_RO); +} + +static Bool glamor_change_window_attributes(WindowPtr pWin, unsigned long mask) +{ + Bool ret; + + if (!glamor_prepare_access_window(pWin)) + return FALSE; + ret = fbChangeWindowAttributes(pWin, mask); + glamor_finish_access_window(pWin); + return ret; +} + +static RegionPtr glamor_bitmap_to_region(PixmapPtr pPix) +{ + RegionPtr ret; + if (!glamor_prepare_access(&pPix->drawable, GLAMOR_CPU_ACCESS_RO)) + return NULL; + ret = fbPixmapToRegion(pPix); + glamor_finish_access(&pPix->drawable, GLAMOR_CPU_ACCESS_RO); + return ret; +} + +void glamor_set_fallback_debug(ScreenPtr screen, Bool enable) +{ + glamor_screen_t *glamor_screen = glamor_get_screen(screen); + + glamor_screen->fallback_debug = enable; +} + + +/* + * These functions wrap the low-level fb rendering functions and + * synchronize framebuffer/accelerated drawing by stalling until + * the accelerator is idle + */ + +/** + * Calls glamor_prepare_access with GLAMOR_PREPARE_SRC for the tile, if that is the + * current fill style. + * + * Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are + * 1bpp and never in fb, so we don't worry about them. + * We should worry about them for completeness sake and going forward. + */ +static Bool glamor_prepare_access_gc(GCPtr pGC) +{ + if (pGC->stipple) + if (!glamor_prepare_access(&pGC->stipple->drawable, GLAMOR_CPU_ACCESS_RO)) + return FALSE; + if (pGC->fillStyle == FillTiled) + if (!glamor_prepare_access + (&pGC->tile.pixmap->drawable, GLAMOR_CPU_ACCESS_RO)) { + if (pGC->stipple) + glamor_finish_access(&pGC->stipple->drawable, GLAMOR_CPU_ACCESS_RO); + return FALSE; + } + return TRUE; +} + +/** + * Finishes access to the tile in the GC, if used. + */ +static void glamor_finish_access_gc(GCPtr pGC) +{ + if (pGC->fillStyle == FillTiled) + glamor_finish_access(&pGC->tile.pixmap->drawable, GLAMOR_CPU_ACCESS_RO); + if (pGC->stipple) + glamor_finish_access(&pGC->stipple->drawable, GLAMOR_CPU_ACCESS_RO); +} + +static Bool glamor_picture_prepare_access(PicturePtr picture, int mode) +{ + if (picture->pDrawable == NULL) + return TRUE; + + if (!glamor_prepare_access(picture->pDrawable, mode)) + return FALSE; + + if (picture->alphaMap && + !glamor_prepare_access(picture->alphaMap->pDrawable, mode)) { + glamor_finish_access(picture->pDrawable, mode); + return FALSE; + } + + return TRUE; +} + +static void glamor_picture_finish_access(PicturePtr picture, int mode) +{ + if (picture->pDrawable == NULL) + return; + + glamor_finish_access(picture->pDrawable, mode); + if (picture->alphaMap) + glamor_finish_access(picture->alphaMap->pDrawable, mode); +} + + +static char glamor_drawable_location(DrawablePtr pDrawable) +{ + return glamor_drawable_is_offscreen(pDrawable) ? 's' : 'm'; +} + +static void +glamor_check_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable, + glamor_drawable_location(pDrawable))); + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + if (glamor_prepare_access_gc(pGC)) { + fbFillSpans(pDrawable, pGC, nspans, ppt, pwidth, + fSorted); + glamor_finish_access_gc(pGC); + } + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } +} + +static void +glamor_check_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable, + glamor_drawable_location(pDrawable))); + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + fbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } +} + +static void +glamor_check_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, int format, + char *bits) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable, + glamor_drawable_location(pDrawable))); + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + fbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, + bits); + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } +} + +static RegionPtr +glamor_check_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int w, int h, int dstx, int dsty, + unsigned long bitPlane) +{ + ScreenPtr screen = pSrc->pScreen; + RegionPtr ret = NULL; + + GLAMOR_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, + glamor_drawable_location(pSrc), + glamor_drawable_location(pDst))); + if (glamor_prepare_access(pDst, GLAMOR_CPU_ACCESS_RW)) { + if (glamor_prepare_access(pSrc, GLAMOR_CPU_ACCESS_RO)) { + ret = + fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, + dsty, bitPlane); + glamor_finish_access(pSrc, GLAMOR_CPU_ACCESS_RO); + } + glamor_finish_access(pDst, GLAMOR_CPU_ACCESS_RW); + } + return ret; +} + +static void +glamor_check_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr pptInit) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable, + glamor_drawable_location(pDrawable))); + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + fbPolyPoint(pDrawable, pGC, mode, npt, pptInit); + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } +} + +static void +glamor_check_poly_lines(DrawablePtr pDrawable, GCPtr pGC, + int mode, int npt, DDXPointPtr ppt) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n", + pDrawable, glamor_drawable_location(pDrawable), + pGC->lineWidth, mode, npt)); + + if (pGC->lineWidth == 0) { + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + if (glamor_prepare_access_gc(pGC)) { + fbPolyLine(pDrawable, pGC, mode, npt, ppt); + glamor_finish_access_gc(pGC); + } + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } + return; + } + /* fb calls mi functions in the lineWidth != 0 case. */ + fbPolyLine(pDrawable, pGC, mode, npt, ppt); +} + +static void +glamor_check_poly_segment(DrawablePtr pDrawable, GCPtr pGC, + int nsegInit, xSegment * pSegInit) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable, + glamor_drawable_location(pDrawable), pGC->lineWidth, + nsegInit)); + if (pGC->lineWidth == 0) { + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + if (glamor_prepare_access_gc(pGC)) { + fbPolySegment(pDrawable, pGC, nsegInit, + pSegInit); + glamor_finish_access_gc(pGC); + } + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } + return; + } + /* fb calls mi functions in the lineWidth != 0 case. */ + fbPolySegment(pDrawable, pGC, nsegInit, pSegInit); +} + +static void +glamor_check_poly_arc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable, + glamor_drawable_location(pDrawable))); + + /* Disable this as fbPolyArc can call miZeroPolyArc which in turn + * can call accelerated functions, that as yet, haven't been notified + * with glamor_finish_access(). + */ +#if 0 + if (pGC->lineWidth == 0) { + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + if (glamor_prepare_access_gc(pGC)) { + fbPolyArc(pDrawable, pGC, narcs, pArcs); + glamor_finish_access_gc(pGC); + } + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } + return; + } +#endif + miPolyArc(pDrawable, pGC, narcs, pArcs); +} + +static void +glamor_check_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC, + int nrect, xRectangle * prect) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable, + glamor_drawable_location(pDrawable))); + + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + if (glamor_prepare_access_gc(pGC)) { + fbPolyFillRect(pDrawable, pGC, nrect, prect); + glamor_finish_access_gc(pGC); + } + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } +} + +static void +glamor_check_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr * ppci, pointer pglyphBase) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("to %p (%c)\n", pDrawable, + glamor_drawable_location(pDrawable))); + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + if (glamor_prepare_access_gc(pGC)) { + fbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + glamor_finish_access_gc(pGC); + } + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } +} + +static void +glamor_check_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr * ppci, pointer pglyphBase) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable, + glamor_drawable_location(pDrawable), pGC->fillStyle, + pGC->alu)); + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + if (glamor_prepare_access_gc(pGC)) { + fbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + glamor_finish_access_gc(pGC); + } + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } +} + +static void +glamor_check_push_pixels(GCPtr pGC, PixmapPtr pBitmap, + DrawablePtr pDrawable, int w, int h, int x, int y) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable, + glamor_drawable_location(&pBitmap->drawable), + glamor_drawable_location(pDrawable))); + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RW)) { + if (glamor_prepare_access(&pBitmap->drawable, GLAMOR_CPU_ACCESS_RO)) { + if (glamor_prepare_access_gc(pGC)) { + fbPushPixels(pGC, pBitmap, pDrawable, w, h, x, + y); + glamor_finish_access_gc(pGC); + } + glamor_finish_access(&pBitmap->drawable, GLAMOR_CPU_ACCESS_RO); + } + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RW); + } +} + +static void +glamor_check_get_spans(DrawablePtr pDrawable, + int wMax, + DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart) +{ + ScreenPtr screen = pDrawable->pScreen; + + GLAMOR_FALLBACK(("from %p (%c)\n", pDrawable, + glamor_drawable_location(pDrawable))); + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RO)) { + fbGetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RO); + } +} + +static void +glamor_check_composite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) +{ + ScreenPtr screen = pDst->pDrawable->pScreen; + + GLAMOR_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst)); + + if (glamor_picture_prepare_access(pDst, GLAMOR_CPU_ACCESS_RW)) { + if (glamor_picture_prepare_access(pSrc, GLAMOR_CPU_ACCESS_RO)) { + if (!pMask || glamor_picture_prepare_access(pMask, GLAMOR_CPU_ACCESS_RO)) { + fbComposite(op, pSrc, pMask, pDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst, + width, height); + if (pMask) + glamor_picture_finish_access(pMask, GLAMOR_CPU_ACCESS_RO); + } + glamor_picture_finish_access(pSrc, GLAMOR_CPU_ACCESS_RO); + } + glamor_picture_finish_access(pDst, GLAMOR_CPU_ACCESS_RW); + } +} + +static void +glamor_check_add_traps(PicturePtr pPicture, + INT16 x_off, INT16 y_off, int ntrap, xTrap * traps) +{ + ScreenPtr screen = pPicture->pDrawable->pScreen; + + GLAMOR_FALLBACK(("to pict %p (%c)\n", pPicture, + glamor_drawable_location(pPicture->pDrawable))); + if (glamor_picture_prepare_access(pPicture, GLAMOR_CPU_ACCESS_RW)) { + fbAddTraps(pPicture, x_off, y_off, ntrap, traps); + glamor_picture_finish_access(pPicture, GLAMOR_CPU_ACCESS_RW); + } +} + + +static void +glamor_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + int ok; + + ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + if (ok) { + ok = glamor_fill_spans_nf(pDrawable, + pGC, n, ppt, pwidth, fSorted); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + } + + if (!ok) + glamor_check_fill_spans(pDrawable, pGC, n, ppt, pwidth, fSorted); +} + +static void +glamor_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, + int w, int h, int leftPad, int format, char *bits) +{ + int ok; + + ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + if (ok) { + ok = glamor_put_image_nf(pDrawable, + pGC, depth, x, y, w, h, + leftPad, format, bits); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + } + + if (!ok) + glamor_check_put_image(pDrawable, pGC, depth, x, y, w, h, leftPad, + format, bits); +} + +static void +glamor_copy_n_to_n(DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, Bool upsidedown, Pixel bitplane, void *closure) +{ + ScreenPtr screen = pDstDrawable->pScreen; + int ok; + + if (!glamor_prepare_access(pSrcDrawable, GLAMOR_GPU_ACCESS_RO)) + goto fallback; + ok = glamor_prepare_access(pDstDrawable, GLAMOR_GPU_ACCESS_RW); + if (!ok) + goto finish_src; + ok = glamor_copy_n_to_n_nf(pSrcDrawable, pDstDrawable, + pGC, pbox, nbox, dx, dy, + reverse, upsidedown, bitplane, + closure); + glamor_finish_access(pDstDrawable, GLAMOR_GPU_ACCESS_RW); +finish_src: + glamor_finish_access(pSrcDrawable, GLAMOR_GPU_ACCESS_RO); + + if (ok) + return; + +fallback: + GLAMOR_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable, + glamor_drawable_location(pSrcDrawable), + glamor_drawable_location(pDstDrawable))); + if (glamor_prepare_access(pDstDrawable, GLAMOR_CPU_ACCESS_RW)) { + if (pSrcDrawable == pDstDrawable || + glamor_prepare_access(pSrcDrawable, GLAMOR_CPU_ACCESS_RO)) { + fbCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, + dx, dy, reverse, upsidedown, bitplane, + closure); + if (pSrcDrawable != pDstDrawable) + glamor_finish_access(pSrcDrawable, GLAMOR_CPU_ACCESS_RO); + } + glamor_finish_access(pDstDrawable, GLAMOR_CPU_ACCESS_RW); + } +} + +static RegionPtr +glamor_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, + int srcx, int srcy, int width, int height, int dstx, int dsty) +{ + return miDoCopy(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, + dstx, dsty, glamor_copy_n_to_n, 0, NULL); +} + +static void +glamor_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr ppt) +{ + int i; + xRectangle *prect; + int ok; + + ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + if (ok) { + ok = glamor_poly_point_nf(pDrawable, pGC, mode, npt, ppt); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + } + + if (ok) + return; + + /* If we can't reuse the current GC as is, don't bother accelerating the + * points. + */ + if (pGC->fillStyle != FillSolid) { + glamor_check_poly_point(pDrawable, pGC, mode, npt, ppt); + return; + } + + prect = malloc(sizeof(xRectangle) * npt); + if (!prect) + return; + for (i = 0; i < npt; i++) { + prect[i].x = ppt[i].x; + prect[i].y = ppt[i].y; + if (i > 0 && mode == CoordModePrevious) { + prect[i].x += prect[i - 1].x; + prect[i].y += prect[i - 1].y; + } + prect[i].width = 1; + prect[i].height = 1; + } + pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); + free(prect); +} + +/** + * glamor_poly_lines() checks if it can accelerate the lines as a group of + * horizontal or vertical lines (rectangles), and uses existing rectangle fill + * acceleration if so. + */ +static void +glamor_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr ppt) +{ + xRectangle *prect; + int x1, x2, y1, y2; + int i; + int ok; + + if (!glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW)) + goto fallback; + ok = glamor_poly_lines_nf(pDrawable, pGC, mode, npt, ppt); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + + if (ok) + return; + +fallback: + /* Don't try to do wide lines or non-solid fill style. */ + if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || + pGC->fillStyle != FillSolid) { + glamor_check_poly_lines(pDrawable, pGC, mode, npt, ppt); + return; + } + + prect = malloc(sizeof(xRectangle) * (npt - 1)); + if (!prect) + return; + x1 = ppt[0].x; + y1 = ppt[0].y; + /* If we have any non-horizontal/vertical, fall back. */ + for (i = 0; i < npt - 1; i++) { + if (mode == CoordModePrevious) { + x2 = x1 + ppt[i + 1].x; + y2 = y1 + ppt[i + 1].y; + } else { + x2 = ppt[i + 1].x; + y2 = ppt[i + 1].y; + } + + if (x1 != x2 && y1 != y2) { + free(prect); + glamor_check_poly_lines(pDrawable, pGC, mode, npt, ppt); + return; + } + + if (x1 < x2) { + prect[i].x = x1; + prect[i].width = x2 - x1 + 1; + } else { + prect[i].x = x2; + prect[i].width = x1 - x2 + 1; + } + if (y1 < y2) { + prect[i].y = y1; + prect[i].height = y2 - y1 + 1; + } else { + prect[i].y = y2; + prect[i].height = y1 - y2 + 1; + } + + x1 = x2; + y1 = y2; + } + pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); + free(prect); +} + +/** + * glamor_poly_segment() checks if it can accelerate the lines as a group of + * horizontal or vertical lines (rectangles), and uses existing rectangle fill + * acceleration if so. + */ +static void +glamor_poly_segment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg) +{ + xRectangle *prect; + int i; + int ok; + + if (!glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW)) + goto fallback; + ok = glamor_poly_segment_nf(pDrawable, pGC, nseg, pSeg); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + + if (ok) + return; + +fallback: + /* Don't try to do wide lines or non-solid fill style. */ + if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || + pGC->fillStyle != FillSolid) { + glamor_check_poly_segment(pDrawable, pGC, nseg, pSeg); + return; + } + + /* If we have any non-horizontal/vertical, fall back. */ + for (i = 0; i < nseg; i++) { + if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { + glamor_check_poly_segment(pDrawable, pGC, nseg, pSeg); + return; + } + } + + prect = malloc(sizeof(xRectangle) * nseg); + if (!prect) + return; + for (i = 0; i < nseg; i++) { + if (pSeg[i].x1 < pSeg[i].x2) { + prect[i].x = pSeg[i].x1; + prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; + } else { + prect[i].x = pSeg[i].x2; + prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; + } + if (pSeg[i].y1 < pSeg[i].y2) { + prect[i].y = pSeg[i].y1; + prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; + } else { + prect[i].y = pSeg[i].y2; + prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; + } + + /* don't paint last pixel */ + if (pGC->capStyle == CapNotLast) { + if (prect[i].width == 1) + prect[i].height--; + else + prect[i].width--; + } + } + pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); + free(prect); +} + +static void +glamor_poly_fill_rect(DrawablePtr pDrawable, + GCPtr pGC, int nrect, xRectangle * prect) +{ + int ok; + + ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + if (ok) { + ok = glamor_poly_fill_rect_nf(pDrawable, pGC, nrect, prect); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + } + + if (!ok) + glamor_check_poly_fill_rect(pDrawable, pGC, nrect, prect); +} + +static void +glamor_get_spans(DrawablePtr pDrawable, + int wMax, + DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart) +{ + int ok; + + ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + if (ok) { + ok = glamor_get_spans_nf(pDrawable, wMax, ppt, + pwidth, nspans, pdstStart); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + } + + if (!ok) + glamor_check_get_spans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart); +} + +static void +glamor_set_spans(DrawablePtr pDrawable, GCPtr gc, char *src, + DDXPointPtr points, int *widths, int n, int sorted) +{ + int ok; + + ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + if (ok) { + ok = glamor_set_spans_nf(pDrawable, gc, src, + points, widths, n, sorted); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + } + + if (!ok) + glamor_check_set_spans(pDrawable, gc, src, points, widths, n, sorted); +} + +static RegionPtr +glamor_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int w, int h, int dstx, int dsty, + unsigned long bitPlane) +{ + int ok; + RegionPtr region; + + if (!glamor_prepare_access(pDst, GLAMOR_GPU_ACCESS_RW)) + goto fallback; + ok = glamor_prepare_access(pSrc, GLAMOR_GPU_ACCESS_RO); + if (!ok) + goto finish_dst; + ok = glamor_copy_plane_nf(pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty, bitPlane, ®ion); + glamor_finish_access(pSrc, GLAMOR_GPU_ACCESS_RO); +finish_dst: + glamor_finish_access(pDst, GLAMOR_GPU_ACCESS_RW); + + if (ok) + return region; + +fallback: + return glamor_check_copy_plane(pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty, bitPlane); +} + +static void +glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr * ppci, pointer pglyphBase) +{ + int ok; + + ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + if (ok) { + ok = glamor_image_glyph_blt_nf(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + } + + if (!ok) + glamor_check_image_glyph_blt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); +} + +static void +glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr * ppci, pointer pglyphBase) +{ + int ok; + + ok = glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + if (ok) { + ok = glamor_poly_glyph_blt_nf(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + } + + if (!ok) + glamor_check_poly_glyph_blt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); +} + +static void +glamor_push_pixels(GCPtr pGC, PixmapPtr pBitmap, + DrawablePtr pDrawable, int w, int h, int x, int y) +{ + int ok; + + if (!glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW)) + goto fallback; + ok = glamor_prepare_access(&pBitmap->drawable, GLAMOR_GPU_ACCESS_RO); + if (!ok) + goto finish_drawable; + ok = glamor_push_pixels_nf(pGC, pBitmap, pDrawable, w, h, x, y); + glamor_finish_access(&pBitmap->drawable, GLAMOR_GPU_ACCESS_RO); +finish_drawable: + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + + if (ok) + return; + +fallback: + glamor_check_push_pixels(pGC, pBitmap, pDrawable, w, h, x, y); +} + +const GCOps glamor_ops = { + glamor_fill_spans, + glamor_set_spans, + glamor_put_image, + glamor_copy_area, + glamor_copy_plane, + glamor_poly_point, + glamor_poly_lines, + glamor_poly_segment, + miPolyRectangle, + glamor_check_poly_arc, + miFillPolygon, + glamor_poly_fill_rect, + miPolyFillArc, + miPolyText8, + miPolyText16, + miImageText8, + miImageText16, + glamor_image_glyph_blt, + glamor_poly_glyph_blt, + glamor_push_pixels, +}; + +/** + * glamor_validate_gc() sets the ops to GLAMOR's implementations, which may be + * accelerated or may sync the card and fall back to fb. + */ +static void +radeon_glamor_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + glamor_validate_gc(pGC, changes, pDrawable); + pGC->ops = (GCOps *) & glamor_ops; +} + +static GCFuncs glamorGCFuncs = { + radeon_glamor_validate_gc, + miChangeGC, + miCopyGC, + miDestroyGC, + miChangeClip, + miDestroyClip, + miCopyClip +}; + +/** + * radeon_glamor_create_gc makes a new GC and hooks up its funcs handler, so that + * radeon_glamor_validate_gc() will get called. + */ +static int radeon_glamor_create_gc(GCPtr pGC) +{ + if (!fbCreateGC(pGC)) + return FALSE; + + pGC->funcs = &glamorGCFuncs; + + return TRUE; +} + +static void glamor_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + RegionRec rgnDst; + int dx, dy; + PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); + + REGION_INIT(pWin->drawable.pScreen, &rgnDst, NullBox, 0); + + REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, + prgnSrc); +#ifdef COMPOSITE + if (pPixmap->screen_x || pPixmap->screen_y) + REGION_TRANSLATE(pWin->drawable.pScreen, &rgnDst, + -pPixmap->screen_x, -pPixmap->screen_y); +#endif + + miCopyRegion(&pPixmap->drawable, &pPixmap->drawable, + NULL, &rgnDst, dx, dy, glamor_copy_n_to_n, 0, NULL); + + REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); +} + +/** + * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. + * + * This is probably the only case we actually care about. The rest fall through + * to migration and fbGetImage, which hopefully will result in migration pushing + * the pixmap out of framebuffer. + */ +void +static glamor_get_image(DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d) +{ + ScreenPtr screen = pDrawable->pScreen; + BoxRec Box; + PixmapPtr pPix = glamor_get_drawable_pixmap(pDrawable); + int xoff, yoff; + Bool ok; + + if (!glamor_prepare_access(pDrawable, GLAMOR_GPU_ACCESS_RW)) + goto fallback; + + glamor_get_drawable_deltas(pDrawable, pPix, &xoff, &yoff); + + Box.x1 = pDrawable->y + x + xoff; + Box.y1 = pDrawable->y + y + yoff; + Box.x2 = Box.x1 + w; + Box.y2 = Box.y1 + h; + + ok = glamor_get_image_nf(pDrawable, x, y, w, h, + format, planeMask, d); + glamor_finish_access(pDrawable, GLAMOR_GPU_ACCESS_RW); + + if (ok) + return; + +fallback: + GLAMOR_FALLBACK(("from %p (%c)\n", pDrawable, + glamor_drawable_location(pDrawable))); + + if (glamor_prepare_access(pDrawable, GLAMOR_CPU_ACCESS_RO)) { + fbGetImage(pDrawable, x, y, w, h, format, planeMask, d); + glamor_finish_access(pDrawable, GLAMOR_CPU_ACCESS_RO); + } + + return; +} + + +/* Cut and paste from render/glyph.c - probably should export it instead */ +static void +glamor_glyph_extents(int nlist, + GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents) +{ + int x1, x2, y1, y2; + int x, y, n; + + x1 = y1 = MAXSHORT; + x2 = y2 = MINSHORT; + x = y = 0; + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + list++; + while (n--) { + GlyphPtr glyph = *glyphs++; + int v; + + v = x - glyph->info.x; + if (v < x1) + x1 = v; + v += glyph->info.width; + if (v > x2) + x2 = v; + + v = y - glyph->info.y; + if (v < y1) + y1 = v; + v += glyph->info.height; + if (v > y2) + y2 = v; + + x += glyph->info.xOff; + y += glyph->info.yOff; + } + } + + extents->x1 = x1 < MINSHORT ? MINSHORT : x1; + extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2; + extents->y1 = y1 < MINSHORT ? MINSHORT : y1; + extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2; +} + +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) + +static void +glamor_check_glyphs(CARD8 op, + PicturePtr src, + PicturePtr dst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) +{ + pixman_image_t *image = NULL; + PixmapPtr scratch = NULL; + PicturePtr mask; + int width = 0, height = 0; + int x, y, n; + int xDst = list->xOff, yDst = list->yOff; + BoxRec extents = { 0, 0, 0, 0 }; + + if (maskFormat) { + pixman_format_code_t format; + CARD32 component_alpha; + int error; + + glamor_glyph_extents(nlist, list, glyphs, &extents); + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) + return; + + width = extents.x2 - extents.x1; + height = extents.y2 - extents.y1; + + format = maskFormat->format | + (BitsPerPixel(maskFormat->depth) << 24); + image = + pixman_image_create_bits(format, width, height, NULL, 0); + if (!image) + return; + + scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height, + PIXMAN_FORMAT_DEPTH(format), + PIXMAN_FORMAT_BPP(format), + pixman_image_get_stride(image), + pixman_image_get_data(image)); + + if (!scratch) { + pixman_image_unref(image); + return; + } + + component_alpha = NeedsComponent(maskFormat->format); + mask = CreatePicture(0, &scratch->drawable, + maskFormat, CPComponentAlpha, + &component_alpha, serverClient, &error); + if (!mask) { + FreeScratchPixmapHeader(scratch); + pixman_image_unref(image); + return; + } + ValidatePicture(mask); + + x = -extents.x1; + y = -extents.y1; + } else { + mask = dst; + x = 0; + y = 0; + } + + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) { + GlyphPtr glyph = *glyphs++; + PicturePtr g = GetGlyphPicture(glyph, dst->pDrawable->pScreen); + if (g) { + if (maskFormat) { + CompositePicture(PictOpAdd, g, NULL, mask, + 0, 0, + 0, 0, + x - glyph->info.x, + y - glyph->info.y, + glyph->info.width, + glyph->info.height); + } else { + CompositePicture(op, src, g, dst, + xSrc + (x - glyph->info.x) - xDst, + ySrc + (y - glyph->info.y) - yDst, + 0, 0, + x - glyph->info.x, + y - glyph->info.y, + glyph->info.width, + glyph->info.height); + } + } + + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + + if (maskFormat) { + x = extents.x1; + y = extents.y1; + CompositePicture(op, src, mask, dst, + xSrc + x - xDst, + ySrc + y - yDst, + 0, 0, + x, y, + width, height); + FreePicture(mask, 0); + FreeScratchPixmapHeader(scratch); + pixman_image_unref(image); + } +} + +void +glamor_glyphs(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, + int nlist, GlyphListPtr list, GlyphPtr * glyphs) +{ + int ok; + + if (!glamor_picture_prepare_access(pDst, GLAMOR_GPU_ACCESS_RW)) + goto fallback; + ok = glamor_picture_prepare_access(pSrc, GLAMOR_GPU_ACCESS_RO); + if (!ok) + goto finish_dst; + ok = glamor_glyphs_nf(op, + pSrc, pDst, maskFormat, + xSrc, ySrc, nlist, list, glyphs); + glamor_picture_finish_access(pSrc, GLAMOR_GPU_ACCESS_RO); +finish_dst: + glamor_picture_finish_access(pDst, GLAMOR_GPU_ACCESS_RW); + + if (ok) + return; + +fallback: + glamor_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); +} + + +#ifdef RENDER + +/* Note: when using glamor we can not fail through to the ordinary GLAMOR + * code paths, as glamor keeps an internal texture which will become + * inconsistent with the original bo. (The texture is replaced whenever + * the format changes, e.g. switching between xRGB and ARGB, for which mesa + * will allocate its own bo.) + * + * Ergo it is unsafe to fall through to the original backend operations if + * glamor is enabled. + * + * XXX This has some serious implications for mixing Render, DRI, scanout... + */ + +static void glamor_composite_fallback_pict_desc(PicturePtr pict, char *string, + int n) +{ + char format[20]; + char size[20]; + char loc; + + if (!pict) { + snprintf(string, n, "None"); + return; + } + + if (pict->pDrawable == NULL) { + snprintf(string, n, "source-only"); + return; + } + + switch (pict->format) { + case PICT_a8r8g8b8: + snprintf(format, 20, "ARGB8888"); + break; + case PICT_x8r8g8b8: + snprintf(format, 20, "XRGB8888"); + break; + case PICT_r5g6b5: + snprintf(format, 20, "RGB565 "); + break; + case PICT_x1r5g5b5: + snprintf(format, 20, "RGB555 "); + break; + case PICT_a8: + snprintf(format, 20, "A8 "); + break; + case PICT_a1: + snprintf(format, 20, "A1 "); + break; + default: + snprintf(format, 20, "0x%x", (int)pict->format); + break; + } + + loc = glamor_drawable_is_offscreen(pict->pDrawable) ? 's' : 'm'; + + snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, + pict->pDrawable->height, pict->repeat ? " R" : ""); + + snprintf(string, n, "%p:%c fmt %s (%s)%s", + pict->pDrawable, loc, format, size, + pict->alphaMap ? " with alpha map" :""); +} + +static const char * +op_to_string(CARD8 op) +{ + switch (op) { +#define C(x) case PictOp##x: return #x + C(Clear); + C(Src); + C(Dst); + C(Over); + C(OverReverse); + C(In); + C(InReverse); + C(Out); + C(OutReverse); + C(Atop); + C(AtopReverse); + C(Xor); + C(Add); + C(Saturate); + + /* + * Operators only available in version 0.2 + */ +#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 2 + C(DisjointClear); + C(DisjointSrc); + C(DisjointDst); + C(DisjointOver); + C(DisjointOverReverse); + C(DisjointIn); + C(DisjointInReverse); + C(DisjointOut); + C(DisjointOutReverse); + C(DisjointAtop); + C(DisjointAtopReverse); + C(DisjointXor); + + C(ConjointClear); + C(ConjointSrc); + C(ConjointDst); + C(ConjointOver); + C(ConjointOverReverse); + C(ConjointIn); + C(ConjointInReverse); + C(ConjointOut); + C(ConjointOutReverse); + C(ConjointAtop); + C(ConjointAtopReverse); + C(ConjointXor); +#endif + + /* + * Operators only available in version 0.11 + */ +#if RENDER_MAJOR >= 1 || RENDER_MINOR >= 11 + C(Multiply); + C(Screen); + C(Overlay); + C(Darken); + C(Lighten); + C(ColorDodge); + C(ColorBurn); + C(HardLight); + C(SoftLight); + C(Difference); + C(Exclusion); + C(HSLHue); + C(HSLSaturation); + C(HSLColor); + C(HSLLuminosity); +#endif + default: return "garbage"; +#undef C + } +} + +static void +glamor_print_composite_fallback(const char *func, CARD8 op, + PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst) +{ + glamor_screen_t *glamor_screen = glamor_get_screen(pDst->pDrawable->pScreen); + char srcdesc[40], maskdesc[40], dstdesc[40]; + + if (! glamor_screen->fallback_debug) + return; + + glamor_composite_fallback_pict_desc(pSrc, srcdesc, 40); + glamor_composite_fallback_pict_desc(pMask, maskdesc, 40); + glamor_composite_fallback_pict_desc(pDst, dstdesc, 40); + + ErrorF("Composite fallback at %s:\n" + " op %s, \n" + " src %s, \n" + " mask %s, \n" + " dst %s, \n", + func, op_to_string (op), srcdesc, maskdesc, dstdesc); +} + + +static void +glamor_composite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) +{ + int ok; + + if (!glamor_picture_prepare_access(pDst, GLAMOR_GPU_ACCESS_RW)) + goto fallback; + ok = glamor_picture_prepare_access(pSrc, GLAMOR_GPU_ACCESS_RO); + if (!ok) + goto finish_dst; + if (pMask) { + ok = glamor_picture_prepare_access(pMask, GLAMOR_GPU_ACCESS_RO); + if (!ok) + goto finish_src; + } + + ok = glamor_composite_nf(op, + pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, + width, height); + + if (pMask) + glamor_picture_finish_access(pMask, GLAMOR_GPU_ACCESS_RO); +finish_src: + glamor_picture_finish_access(pSrc, GLAMOR_GPU_ACCESS_RO); +finish_dst: + glamor_picture_finish_access(pDst, GLAMOR_GPU_ACCESS_RW); + + if (ok) + return; + +fallback: + glamor_print_composite_fallback("glamor_composite", + op, pSrc, pMask, pDst); + + glamor_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); +} + + +static void +glamor_check_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid * traps) +{ + ScreenPtr screen = dst->pDrawable->pScreen; + + if (maskFormat) { + PixmapPtr scratch = NULL; + PicturePtr mask; + INT16 xDst, yDst; + INT16 xRel, yRel; + BoxRec bounds; + int width, height; + pixman_image_t *image; + pixman_format_code_t format; + int error; + + xDst = traps[0].left.p1.x >> 16; + yDst = traps[0].left.p1.y >> 16; + + miTrapezoidBounds (ntrap, traps, &bounds); + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return; + + width = bounds.x2 - bounds.x1; + height = bounds.y2 - bounds.y1; + + format = maskFormat->format | + (BitsPerPixel(maskFormat->depth) << 24); + image = + pixman_image_create_bits(format, width, height, NULL, 0); + if (!image) + return; + + for (; ntrap; ntrap--, traps++) + pixman_rasterize_trapezoid(image, + (pixman_trapezoid_t *) traps, + -bounds.x1, -bounds.y1); + + + scratch = GetScratchPixmapHeader(screen, width, height, + PIXMAN_FORMAT_DEPTH(format), + PIXMAN_FORMAT_BPP(format), + pixman_image_get_stride(image), + pixman_image_get_data(image)); + if (!scratch) { + pixman_image_unref(image); + return; + } + + mask = CreatePicture(0, &scratch->drawable, + PictureMatchFormat(screen, + PIXMAN_FORMAT_DEPTH(format), + format), + 0, 0, serverClient, &error); + if (!mask) { + FreeScratchPixmapHeader(scratch); + pixman_image_unref(image); + return; + } + + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + CompositePicture(op, src, mask, dst, + xRel, yRel, + 0, 0, + bounds.x1, bounds.y1, + width, height); + FreePicture(mask, 0); + + FreeScratchPixmapHeader(scratch); + pixman_image_unref(image); + } else { + if (dst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat(screen, 1, PICT_a1); + else + maskFormat = PictureMatchFormat(screen, 8, PICT_a8); + + for (; ntrap; ntrap--, traps++) + glamor_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, 1, traps); + } +} + +/** + * glamor_trapezoids is essentially a copy of miTrapezoids that uses + * glamor_create_alpha_picture instead of miCreateAlphaPicture. + * + * The problem with miCreateAlphaPicture is that it calls PolyFillRect + * to initialize the contents after creating the pixmap, which + * causes the pixmap to be moved in for acceleration. The subsequent + * call to RasterizeTrapezoid won't be accelerated however, which + * forces the pixmap to be moved out again. + * + * glamor_create_alpha_picture avoids this roundtrip by using + * glamor_check_poly_fill_rect to initialize the contents. + */ +static void +glamor_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid * traps) +{ + int ok; + + if (!glamor_picture_prepare_access(dst, GLAMOR_GPU_ACCESS_RW)) + goto fallback; + ok = glamor_picture_prepare_access(src, GLAMOR_GPU_ACCESS_RO); + if (!ok) + goto finish_dst; + ok = glamor_trapezoids_nf(op, + src, dst, maskFormat, xSrc, + ySrc, ntrap, traps); + glamor_picture_finish_access(src, GLAMOR_GPU_ACCESS_RO); +finish_dst: + glamor_picture_finish_access(dst, GLAMOR_GPU_ACCESS_RW); + + if (ok) + return; + +fallback: + glamor_check_trapezoids(op, src, dst, maskFormat, xSrc, ySrc, ntrap, traps); +} + +static void +glamor_check_triangles(CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tri) +{ + ScreenPtr screen = dst->pDrawable->pScreen; + + if (maskFormat) { + PixmapPtr scratch = NULL; + PicturePtr mask; + INT16 xDst, yDst; + INT16 xRel, yRel; + BoxRec bounds; + int width, height; + pixman_image_t *image; + pixman_format_code_t format; + int error; + + xDst = pixman_fixed_to_int(tri[0].p1.x); + yDst = pixman_fixed_to_int(tri[0].p1.y); + + miTriangleBounds (ntri, tri, &bounds); + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return; + + width = bounds.x2 - bounds.x1; + height = bounds.y2 - bounds.y1; + + format = maskFormat->format | + (BitsPerPixel(maskFormat->depth) << 24); + image = + pixman_image_create_bits(format, width, height, NULL, 0); + if (!image) + return; + + pixman_add_triangles(image, + -bounds.x1, -bounds.y1, + ntri, (pixman_triangle_t *)tri); + + scratch = GetScratchPixmapHeader(screen, width, height, + PIXMAN_FORMAT_DEPTH(format), + PIXMAN_FORMAT_BPP(format), + pixman_image_get_stride(image), + pixman_image_get_data(image)); + if (!scratch) { + pixman_image_unref(image); + return; + } + + mask = CreatePicture(0, &scratch->drawable, + PictureMatchFormat(screen, + PIXMAN_FORMAT_DEPTH(format), + format), + 0, 0, serverClient, &error); + if (!mask) { + FreeScratchPixmapHeader(scratch); + pixman_image_unref(image); + return; + } + + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + CompositePicture(op, src, mask, dst, + xRel, yRel, + 0, 0, + bounds.x1, bounds.y1, + width, height); + FreePicture(mask, 0); + + FreeScratchPixmapHeader(scratch); + pixman_image_unref(image); + } else { + if (dst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat(screen, 1, PICT_a1); + else + maskFormat = PictureMatchFormat(screen, 8, PICT_a8); + + for (; ntri; ntri--, tri++) + glamor_check_triangles(op, src, dst, maskFormat, xSrc, ySrc, 1, tri); + } +} + +/** + * glamor_triangles is essentially a copy of miTriangles that uses + * glamor_create_alpha_picture instead of miCreateAlphaPicture. + * + * The problem with miCreateAlphaPicture is that it calls PolyFillRect + * to initialize the contents after creating the pixmap, which + * causes the pixmap to be moved in for acceleration. The subsequent + * call to AddTriangles won't be accelerated however, which forces the pixmap + * to be moved out again. + * + * glamor_create_alpha_picture avoids this roundtrip by using + * glamor_check_poly_fill_rect to initialize the contents. + */ +static void +glamor_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle * tris) +{ + int ok; + + if (!glamor_picture_prepare_access(pDst, GLAMOR_GPU_ACCESS_RW)) + goto fallback; + ok = glamor_picture_prepare_access(pSrc, GLAMOR_GPU_ACCESS_RO); + if (!ok) + goto finish_dst; + ok = glamor_triangles_nf(op, + pSrc, pDst, maskFormat, xSrc, + ySrc, ntri, tris); + glamor_picture_finish_access(pSrc, GLAMOR_GPU_ACCESS_RO); +finish_dst: + glamor_picture_finish_access(pDst, GLAMOR_GPU_ACCESS_RW); + + if (ok) + return; + +fallback: + glamor_check_triangles(op, pSrc, pDst, maskFormat, + xSrc, ySrc, ntri, tris); +} + +void +glamor_add_traps(PicturePtr pPicture, + INT16 x_off, INT16 y_off, int ntrap, xTrap * traps) +{ + int ok; + + ok = glamor_picture_prepare_access(pPicture, GLAMOR_GPU_ACCESS_RW); + if (ok) { + ok = glamor_add_traps_nf(pPicture, + x_off, y_off, ntrap, traps); + glamor_picture_finish_access(pPicture, GLAMOR_GPU_ACCESS_RW); + } + + if (!ok) + glamor_check_add_traps(pPicture, x_off, y_off, ntrap, traps); +} + +#endif /* RENDER */ + + +/** + * radeon_glamor_close_screen() unwraps its wrapped screen functions and tears down GLAMOR's + * screen private, before calling down to the next CloseSccreen. + */ +static Bool radeon_glamor_close_screen(CLOSE_SCREEN_ARGS_DECL) +{ + glamor_screen_t *glamor_screen = glamor_get_screen(pScreen); +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); +#endif + + pScreen->CreateGC = glamor_screen->SavedCreateGC; + pScreen->CloseScreen = glamor_screen->SavedCloseScreen; + pScreen->GetImage = glamor_screen->SavedGetImage; + pScreen->GetSpans = glamor_screen->SavedGetSpans; + pScreen->CreatePixmap = glamor_screen->SavedCreatePixmap; + pScreen->DestroyPixmap = glamor_screen->SavedDestroyPixmap; + pScreen->CopyWindow = glamor_screen->SavedCopyWindow; + pScreen->ChangeWindowAttributes = + glamor_screen->SavedChangeWindowAttributes; + pScreen->BitmapToRegion = glamor_screen->SavedBitmapToRegion; +#ifdef RENDER + if (ps) { + ps->Composite = glamor_screen->SavedComposite; + ps->Glyphs = glamor_screen->SavedGlyphs; + ps->Trapezoids = glamor_screen->SavedTrapezoids; + ps->AddTraps = glamor_screen->SavedAddTraps; + ps->Triangles = glamor_screen->SavedTriangles; + + ps->UnrealizeGlyph = glamor_screen->SavedUnrealizeGlyph; + } +#endif + + free(glamor_screen); + + return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS); +} + +/** + * @param screen screen being initialized + */ +Bool glamor_screen_init(ScreenPtr screen) +{ + glamor_screen_t *glamor_screen; + +#if HAS_DIXREGISTERPRIVATEKEY + if (!dixRegisterPrivateKey(&glamor_screen_index, PRIVATE_SCREEN, 0)) + return FALSE; +#endif + glamor_screen = calloc(sizeof(glamor_screen_t), 1); + + if (!glamor_screen) { + LogMessage(X_WARNING, + "GLAMOR(%d): Failed to allocate screen private\n", + screen->myNum); + return FALSE; + } + + dixSetPrivate(&screen->devPrivates, &glamor_screen_index, glamor_screen); + + /* + * Replace various fb screen functions + */ + glamor_screen->SavedCloseScreen = screen->CloseScreen; + screen->CloseScreen = radeon_glamor_close_screen; + + glamor_screen->SavedCreateGC = screen->CreateGC; + screen->CreateGC = radeon_glamor_create_gc; + + glamor_screen->SavedGetImage = screen->GetImage; + screen->GetImage = glamor_get_image; + + glamor_screen->SavedGetSpans = screen->GetSpans; + screen->GetSpans = glamor_get_spans; + + glamor_screen->SavedCreatePixmap = screen->CreatePixmap; + glamor_screen->SavedDestroyPixmap = screen->DestroyPixmap; + + glamor_screen->SavedCopyWindow = screen->CopyWindow; + screen->CopyWindow = glamor_copy_window; + + glamor_screen->SavedChangeWindowAttributes = + screen->ChangeWindowAttributes; + screen->ChangeWindowAttributes = glamor_change_window_attributes; + + glamor_screen->SavedBitmapToRegion = screen->BitmapToRegion; + screen->BitmapToRegion = glamor_bitmap_to_region; + +#ifdef RENDER + { + PictureScreenPtr ps = GetPictureScreenIfSet(screen); + if (ps) { + glamor_screen->SavedComposite = ps->Composite; + ps->Composite = glamor_composite; + + glamor_screen->SavedGlyphs = ps->Glyphs; + ps->Glyphs = glamor_glyphs; + + glamor_screen->SavedTriangles = ps->Triangles; + ps->Triangles = glamor_triangles; + + glamor_screen->SavedTrapezoids = ps->Trapezoids; + ps->Trapezoids = glamor_trapezoids; + + glamor_screen->SavedAddTraps = ps->AddTraps; + ps->AddTraps = glamor_add_traps; + } + } +#endif + + return TRUE; +} diff --git a/src/radeon_glamor_wrappers.h b/src/radeon_glamor_wrappers.h new file mode 100644 index 0000000..53ce969 --- /dev/null +++ b/src/radeon_glamor_wrappers.h @@ -0,0 +1,178 @@ +/* + * Copyright © 2000,2008 Keith Packard + * 2004 Eric Anholt + * 2005 Zack Rusin, Trolltech + * 2012 Advanced Micro Devices, Inc. + * + * 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. + */ + +#ifndef RADEON_GLAMOR_WRAPPERS_H +#define RADEON_GLAMOR_WRAPPERS_H + +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_DIX_CONFIG_H +#include +#endif +#include +#include "xf86.h" + +#include +#include +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "servermd.h" +#include "colormapst.h" +#include "gcstruct.h" +#include "input.h" +#include "mipointer.h" +#include "mi.h" +#include "dix.h" +#include "fb.h" +#include "fboverlay.h" +#ifdef RENDER +//#include "fbpict.h" +#include "glyphstr.h" +#include "picturestr.h" +#endif +#include "damage.h" + +#include "../src/compat-api.h" + +/* Provide substitutes for gcc's __FUNCTION__ on other compilers */ +#if !defined(__GNUC__) && !defined(__FUNCTION__) +# if defined(__STDC__) && (__STDC_VERSION__>=199901L) /* C99 */ +# define __FUNCTION__ __func__ +# else +# define __FUNCTION__ "" +# endif +#endif + +/* 1.6 and earlier server compat */ +#ifndef miGetCompositeClip +#define miCopyRegion fbCopyRegion +#define miDoCopy fbDoCopy +#endif + +typedef enum { + GLAMOR_CPU_ACCESS_RO, + GLAMOR_CPU_ACCESS_RW, + GLAMOR_GPU_ACCESS_RO, + GLAMOR_GPU_ACCESS_RW +} glamor_access_t; + +#include "radeon.h" +#include "glamor.h" + + +Bool glamor_screen_init(ScreenPtr screen); + +void glamor_set_fallback_debug(ScreenPtr screen, Bool enable); + +#define DEBUG_MIGRATE 0 +#define DEBUG_PIXMAP 0 +#define DEBUG_OFFSCREEN 0 +#define DEBUG_GLYPH_CACHE 0 + +#define GLAMOR_FALLBACK(x) \ +if (glamor_get_screen(screen)->fallback_debug) { \ + ErrorF("GLAMOR fallback at %s: ", __FUNCTION__); \ + ErrorF x; \ +} + +#if DEBUG_PIXMAP +#define DBG_PIXMAP(a) ErrorF a +#else +#define DBG_PIXMAP(a) +#endif + +typedef void (*EnableDisableFBAccessProcPtr) (int, Bool); +typedef struct { + CreateGCProcPtr SavedCreateGC; + CloseScreenProcPtr SavedCloseScreen; + GetImageProcPtr SavedGetImage; + GetSpansProcPtr SavedGetSpans; + CreatePixmapProcPtr SavedCreatePixmap; + DestroyPixmapProcPtr SavedDestroyPixmap; + CopyWindowProcPtr SavedCopyWindow; + ChangeWindowAttributesProcPtr SavedChangeWindowAttributes; + BitmapToRegionProcPtr SavedBitmapToRegion; +#ifdef RENDER + CompositeProcPtr SavedComposite; + TrianglesProcPtr SavedTriangles; + GlyphsProcPtr SavedGlyphs; + TrapezoidsProcPtr SavedTrapezoids; + AddTrapsProcPtr SavedAddTraps; + UnrealizeGlyphProcPtr SavedUnrealizeGlyph; +#endif + + Bool fallback_debug; +} glamor_screen_t; + +/* + * This is the only completely portable way to + * compute this info. + */ +#ifndef BitsPerPixel +#define BitsPerPixel(d) (\ + PixmapWidthPaddingInfo[d].notPower2 ? \ + (PixmapWidthPaddingInfo[d].bytesPerPixel * 8) : \ + ((1 << PixmapWidthPaddingInfo[d].padBytesLog2) * 8 / \ + (PixmapWidthPaddingInfo[d].padRoundUp+1))) +#endif + +#if HAS_DEVPRIVATEKEYREC +extern DevPrivateKeyRec glamor_screen_index; +#else +extern int glamor_screen_index; +#endif + +static inline glamor_screen_t *glamor_get_screen(ScreenPtr screen) +{ +#if HAS_DEVPRIVATEKEYREC + return dixGetPrivate(&screen->devPrivates, &glamor_screen_index); +#else + return dixLookupPrivate(&screen->devPrivates, &glamor_screen_index); +#endif +} + +#ifdef RENDER + +/* XXX these are in fbpict.h, which is not installed */ +void +fbComposite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); + +void +fbAddTraps(PicturePtr pPicture, + INT16 xOff, INT16 yOff, int ntrap, xTrap * traps); + +#endif + +#endif /* RADEON_GLAMOR_WRAPPERS_H */ -- 1.8.5.2