diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2015-05-29 18:53:50 +0900 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2015-06-15 17:20:43 +0900 |
commit | d3ea8a69b02b308f8f23662be6e0c7bd81c1a2c9 (patch) | |
tree | b22f4888c33ff48a06a980987bb87a42a9b21b36 /src/amdgpu_glamor_wrappers.c | |
parent | 895e4d73d5f042afa13065b64a78f5625ecb5612 (diff) |
glamor: Add wrappers for the X server rendering hooks
They can choose between using the GPU or CPU for the operation.
(cherry picked from radeon commits eea79472a84672ee4dc7adc4487cec6a4037048a
and e58fc380ccf2a581d28f041fd74b963626ca5404)
Signed-off-by: Darren Powell <darren.powell@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'src/amdgpu_glamor_wrappers.c')
-rw-r--r-- | src/amdgpu_glamor_wrappers.c | 992 |
1 files changed, 992 insertions, 0 deletions
diff --git a/src/amdgpu_glamor_wrappers.c b/src/amdgpu_glamor_wrappers.c new file mode 100644 index 0000000..8edfde0 --- /dev/null +++ b/src/amdgpu_glamor_wrappers.c @@ -0,0 +1,992 @@ +/* + * Copyright © 2001 Keith Packard + * 2010 Intel Corporation + * 2012,2015 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_CONFIG_H +#include <config.h> +#endif + +#ifdef USE_GLAMOR + +#include "amdgpu_drv.h" +#include "amdgpu_glamor.h" +#include "amdgpu_pixmap.h" + + +/** + * get_drawable_pixmap() returns the 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. + */ +static PixmapPtr +get_drawable_pixmap(DrawablePtr pDrawable) +{ + if (pDrawable->type == DRAWABLE_WINDOW) + return pDrawable->pScreen-> + GetWindowPixmap((WindowPtr) pDrawable); + else + return (PixmapPtr) pDrawable; +} + +/* Are there any outstanding GPU operations for this pixmap? */ +static Bool +amdgpu_glamor_gpu_pending(uint_fast32_t gpu_synced, uint_fast32_t gpu_access) +{ + return (int_fast32_t)(gpu_access - gpu_synced) > 0; +} + +/* + * Pixmap CPU access wrappers + */ + +static Bool +amdgpu_glamor_prepare_access_cpu(ScrnInfoPtr scrn, AMDGPUInfoPtr info, + PixmapPtr pixmap, struct amdgpu_pixmap *priv, + Bool need_sync) +{ + struct amdgpu_buffer *bo = priv->bo; + int ret; + + /* When falling back to swrast, flush all pending operations */ + if (need_sync) + amdgpu_glamor_flush(scrn); + + if (!pixmap->devPrivate.ptr) { + ret = amdgpu_bo_map(scrn, bo); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "%s: bo map failed: %s\n", __FUNCTION__, + strerror(-ret)); + return FALSE; + } + + pixmap->devPrivate.ptr = bo->cpu_ptr; + info->gpu_synced = info->gpu_flushed; + } else if (need_sync) { + char pixel[4]; + + info->glamor.SavedGetImage(&pixmap->drawable, 0, 0, 1, 1, + ZPixmap, ~0, pixel); + info->gpu_synced = info->gpu_flushed; + } + + return TRUE; +} + +static Bool +amdgpu_glamor_prepare_access_cpu_ro(ScrnInfoPtr scrn, PixmapPtr pixmap, + struct amdgpu_pixmap *priv) +{ + AMDGPUInfoPtr info; + Bool need_sync; + + if (!priv) + return TRUE; + + info = AMDGPUPTR(scrn); + need_sync = amdgpu_glamor_gpu_pending(info->gpu_synced, priv->gpu_write); + return amdgpu_glamor_prepare_access_cpu(scrn, AMDGPUPTR(scrn), pixmap, + priv, need_sync); +} + +static Bool +amdgpu_glamor_prepare_access_cpu_rw(ScrnInfoPtr scrn, PixmapPtr pixmap, + struct amdgpu_pixmap *priv) +{ + AMDGPUInfoPtr info; + uint_fast32_t gpu_synced; + Bool need_sync; + + if (!priv) + return TRUE; + + info = AMDGPUPTR(scrn); + gpu_synced = info->gpu_synced; + need_sync = amdgpu_glamor_gpu_pending(gpu_synced, priv->gpu_write) | + amdgpu_glamor_gpu_pending(gpu_synced, priv->gpu_read); + return amdgpu_glamor_prepare_access_cpu(scrn, info, pixmap, priv, + need_sync); +} + +static void +amdgpu_glamor_finish_access_cpu(PixmapPtr pixmap) +{ + /* Nothing to do */ +} + +/* + * Pixmap GPU access wrappers + */ + +static Bool +amdgpu_glamor_use_gpu(PixmapPtr pixmap) +{ + return (pixmap->usage_hint & + (AMDGPU_CREATE_PIXMAP_SCANOUT | AMDGPU_CREATE_PIXMAP_DRI2)) != 0; +} + +static Bool +amdgpu_glamor_prepare_access_gpu(struct amdgpu_pixmap *priv) +{ + return priv != NULL; +} + +static void +amdgpu_glamor_finish_access_gpu_ro(AMDGPUInfoPtr info, + struct amdgpu_pixmap *priv) +{ + priv->gpu_read = info->gpu_flushed + 1; +} + +static void +amdgpu_glamor_finish_access_gpu_rw(AMDGPUInfoPtr info, + struct amdgpu_pixmap *priv) +{ + priv->gpu_write = priv->gpu_read = info->gpu_flushed + 1; +} + +/* + * GC CPU access wrappers + */ + +static Bool +amdgpu_glamor_prepare_access_gc(ScrnInfoPtr scrn, GCPtr pGC) +{ + struct amdgpu_pixmap *priv; + + if (pGC->stipple) { + priv = amdgpu_get_pixmap_private(pGC->stipple); + if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pGC->stipple, priv)) + return FALSE; + } + if (pGC->fillStyle == FillTiled) { + priv = amdgpu_get_pixmap_private(pGC->tile.pixmap); + if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pGC->tile.pixmap, + priv)) { + if (pGC->stipple) + amdgpu_glamor_finish_access_cpu(pGC->stipple); + return FALSE; + } + } + return TRUE; +} + +static void +amdgpu_glamor_finish_access_gc(GCPtr pGC) +{ + if (pGC->fillStyle == FillTiled) + amdgpu_glamor_finish_access_cpu(pGC->tile.pixmap); + if (pGC->stipple) + amdgpu_glamor_finish_access_cpu(pGC->stipple); +} + +/* + * Picture CPU access wrappers + */ + +static void +amdgpu_glamor_picture_finish_access_cpu(PicturePtr picture) +{ + /* Nothing to do */ +} + +static Bool +amdgpu_glamor_picture_prepare_access_cpu_ro(ScrnInfoPtr scrn, + PicturePtr picture) +{ + PixmapPtr pixmap; + struct amdgpu_pixmap *priv; + + if (picture->pDrawable == NULL) + return TRUE; + + pixmap = get_drawable_pixmap(picture->pDrawable); + priv = amdgpu_get_pixmap_private(pixmap); + if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) + return FALSE; + + if (picture->alphaMap) { + pixmap = get_drawable_pixmap(picture->alphaMap->pDrawable); + priv = amdgpu_get_pixmap_private(pixmap); + if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) { + amdgpu_glamor_picture_finish_access_cpu(picture); + return FALSE; + } + } + + return TRUE; +} + +static Bool +amdgpu_glamor_picture_prepare_access_cpu_rw(ScrnInfoPtr scrn, + PicturePtr picture) +{ + PixmapPtr pixmap; + struct amdgpu_pixmap *priv; + + pixmap = get_drawable_pixmap(picture->pDrawable); + priv = amdgpu_get_pixmap_private(pixmap); + if (!amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) + return FALSE; + + if (picture->alphaMap) { + pixmap = get_drawable_pixmap(picture->alphaMap->pDrawable); + priv = amdgpu_get_pixmap_private(pixmap); + if (!amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + amdgpu_glamor_picture_finish_access_cpu(picture); + return FALSE; + } + } + + return TRUE; +} + +/* + * GC rendering wrappers + */ + +static void +amdgpu_glamor_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) { + fbFillSpans(pDrawable, pGC, nspans, ppt, pwidth, + fSorted); + amdgpu_glamor_finish_access_gc(pGC); + } + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +static void +amdgpu_glamor_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + fbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +static void +amdgpu_glamor_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, int format, + char *bits) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + fbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, + bits); + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +static RegionPtr +amdgpu_glamor_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int w, int h, int dstx, int dsty, + unsigned long bitPlane) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pScreen); + PixmapPtr dst_pix = get_drawable_pixmap(pDst); + struct amdgpu_pixmap *dst_priv = amdgpu_get_pixmap_private(dst_pix); + RegionPtr ret = NULL; + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, dst_pix, dst_priv)) { + PixmapPtr src_pix = get_drawable_pixmap(pSrc); + struct amdgpu_pixmap *src_priv = amdgpu_get_pixmap_private(src_pix); + if (amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pix, src_priv)) { + ret = + fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, + dsty, bitPlane); + amdgpu_glamor_finish_access_cpu(src_pix); + } + amdgpu_glamor_finish_access_cpu(dst_pix); + } + return ret; +} + +static RegionPtr +amdgpu_glamor_copy_plane_nodstbo(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int w, int h, + int dstx, int dsty, unsigned long bitPlane) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pScreen); + PixmapPtr src_pix = get_drawable_pixmap(pSrc); + struct amdgpu_pixmap *src_priv = amdgpu_get_pixmap_private(src_pix); + RegionPtr ret = NULL; + + if (amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pix, src_priv)) { + ret = fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty, bitPlane); + amdgpu_glamor_finish_access_cpu(src_pix); + } + return ret; +} + +static void +amdgpu_glamor_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr pptInit) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + fbPolyPoint(pDrawable, pGC, mode, npt, pptInit); + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +static void +amdgpu_glamor_poly_lines(DrawablePtr pDrawable, GCPtr pGC, + int mode, int npt, DDXPointPtr ppt) +{ + if (pGC->lineWidth == 0) { + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) { + fbPolyLine(pDrawable, pGC, mode, npt, ppt); + amdgpu_glamor_finish_access_gc(pGC); + } + amdgpu_glamor_finish_access_cpu(pixmap); + } + return; + } + /* fb calls mi functions in the lineWidth != 0 case. */ + fbPolyLine(pDrawable, pGC, mode, npt, ppt); +} + +static void +amdgpu_glamor_poly_segment(DrawablePtr pDrawable, GCPtr pGC, + int nsegInit, xSegment *pSegInit) +{ + if (pGC->lineWidth == 0) { + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) { + fbPolySegment(pDrawable, pGC, nsegInit, + pSegInit); + amdgpu_glamor_finish_access_gc(pGC); + } + amdgpu_glamor_finish_access_cpu(pixmap); + } + return; + } + /* fb calls mi functions in the lineWidth != 0 case. */ + fbPolySegment(pDrawable, pGC, nsegInit, pSegInit); +} + +static void +amdgpu_glamor_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC, + int nrect, xRectangle *prect) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) { + fbPolyFillRect(pDrawable, pGC, nrect, prect); + amdgpu_glamor_finish_access_gc(pGC); + } + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +static void +amdgpu_glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) { + fbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + amdgpu_glamor_finish_access_gc(pGC); + } + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +static void +amdgpu_glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) { + fbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + amdgpu_glamor_finish_access_gc(pGC); + } + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +static void +amdgpu_glamor_push_pixels(GCPtr pGC, PixmapPtr pBitmap, + DrawablePtr pDrawable, int w, int h, int x, int y) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + priv = amdgpu_get_pixmap_private(pBitmap); + if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pBitmap, priv)) { + if (amdgpu_glamor_prepare_access_gc(scrn, pGC)) { + fbPushPixels(pGC, pBitmap, pDrawable, w, h, x, + y); + amdgpu_glamor_finish_access_gc(pGC); + } + amdgpu_glamor_finish_access_cpu(pBitmap); + } + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +static void +amdgpu_glamor_push_pixels_nodstbo(GCPtr pGC, PixmapPtr pBitmap, + DrawablePtr pDrawable, int w, int h, + int x, int y) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pBitmap); + + if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pBitmap, priv)) { + fbPushPixels(pGC, pBitmap, pDrawable, w, h, x, y); + amdgpu_glamor_finish_access_cpu(pBitmap); + } +} + +static RegionPtr +amdgpu_glamor_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, int srcx, int srcy, int width, int height, + int dstx, int dsty) +{ + ScreenPtr screen = pDstDrawable->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + AMDGPUInfoPtr info = AMDGPUPTR(scrn); + PixmapPtr src_pixmap = get_drawable_pixmap(pSrcDrawable); + PixmapPtr dst_pixmap = get_drawable_pixmap(pDstDrawable); + struct amdgpu_pixmap *src_priv = amdgpu_get_pixmap_private(src_pixmap); + struct amdgpu_pixmap *dst_priv = amdgpu_get_pixmap_private(dst_pixmap); + RegionPtr ret = NULL; + + if (amdgpu_glamor_use_gpu(dst_pixmap) || + amdgpu_glamor_use_gpu(src_pixmap)) { + if (!amdgpu_glamor_prepare_access_gpu(dst_priv)) + goto fallback; + if (src_priv != dst_priv && + !amdgpu_glamor_prepare_access_gpu(src_priv)) + goto fallback; + + ret = info->glamor.SavedCopyArea(pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, + width, height, dstx, dsty); + amdgpu_glamor_finish_access_gpu_rw(info, dst_priv); + if (src_priv != dst_priv) + amdgpu_glamor_finish_access_gpu_ro(info, src_priv); + + return ret; + } + +fallback: + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, dst_pixmap, dst_priv)) { + if (pSrcDrawable == pDstDrawable || + amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pixmap, + src_priv)) { + ret = fbCopyArea(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, dstx, dsty); + if (pSrcDrawable != pDstDrawable) + amdgpu_glamor_finish_access_cpu(src_pixmap); + } + amdgpu_glamor_finish_access_cpu(dst_pixmap); + } + + return ret; +} + +static RegionPtr +amdgpu_glamor_copy_area_nodstbo(DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, GCPtr pGC, + int srcx, int srcy, int width, int height, + int dstx, int dsty) +{ + ScreenPtr screen = pDstDrawable->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + PixmapPtr src_pixmap = get_drawable_pixmap(pSrcDrawable); + PixmapPtr dst_pixmap = get_drawable_pixmap(pDstDrawable); + struct amdgpu_pixmap *src_priv; + RegionPtr ret = NULL; + + if (src_pixmap != dst_pixmap) { + src_priv = amdgpu_get_pixmap_private(src_pixmap); + + if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, src_pixmap, + src_priv)) + return ret; + } + + ret = fbCopyArea(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, + width, height, dstx, dsty); + + if (src_pixmap != dst_pixmap) + amdgpu_glamor_finish_access_cpu(src_pixmap); + + return ret; +} + +static const GCOps amdgpu_glamor_ops = { + amdgpu_glamor_fill_spans, + amdgpu_glamor_set_spans, + amdgpu_glamor_put_image, + amdgpu_glamor_copy_area, + amdgpu_glamor_copy_plane, + amdgpu_glamor_poly_point, + amdgpu_glamor_poly_lines, + amdgpu_glamor_poly_segment, + miPolyRectangle, + miPolyArc, + miFillPolygon, + amdgpu_glamor_poly_fill_rect, + miPolyFillArc, + miPolyText8, + miPolyText16, + miImageText8, + miImageText16, + amdgpu_glamor_image_glyph_blt, + amdgpu_glamor_poly_glyph_blt, + amdgpu_glamor_push_pixels, +}; + +static GCOps amdgpu_glamor_nodstbo_ops; + +/** + * amdgpu_glamor_validate_gc() sets the ops to our implementations, which may be + * accelerated or may sync the card and fall back to fb. + */ +static void +amdgpu_glamor_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pGC->pScreen); + AMDGPUInfoPtr info = AMDGPUPTR(scrn); + + glamor_validate_gc(pGC, changes, pDrawable); + info->glamor.SavedCopyArea = pGC->ops->CopyArea; + + if (amdgpu_get_pixmap_private(get_drawable_pixmap(pDrawable)) || + (pGC->stipple && amdgpu_get_pixmap_private(pGC->stipple)) || + (pGC->fillStyle == FillTiled && + amdgpu_get_pixmap_private(pGC->tile.pixmap))) + pGC->ops = (GCOps *)&amdgpu_glamor_ops; + else + pGC->ops = &amdgpu_glamor_nodstbo_ops; +} + +static GCFuncs glamorGCFuncs = { + amdgpu_glamor_validate_gc, + miChangeGC, + miCopyGC, + miDestroyGC, + miChangeClip, + miDestroyClip, + miCopyClip +}; + +/** + * amdgpu_glamor_create_gc makes a new GC and hooks up its funcs handler, so that + * amdgpu_glamor_validate_gc() will get called. + */ +static int +amdgpu_glamor_create_gc(GCPtr pGC) +{ + static Bool nodstbo_ops_initialized; + + if (!fbCreateGC(pGC)) + return FALSE; + + if (!nodstbo_ops_initialized) { + amdgpu_glamor_nodstbo_ops = amdgpu_glamor_ops; + + amdgpu_glamor_nodstbo_ops.FillSpans = pGC->ops->FillSpans; + amdgpu_glamor_nodstbo_ops.SetSpans = pGC->ops->SetSpans; + amdgpu_glamor_nodstbo_ops.PutImage = pGC->ops->PutImage; + amdgpu_glamor_nodstbo_ops.CopyArea = amdgpu_glamor_copy_area_nodstbo; + amdgpu_glamor_nodstbo_ops.CopyPlane = amdgpu_glamor_copy_plane_nodstbo; + amdgpu_glamor_nodstbo_ops.PolyPoint = pGC->ops->PolyPoint; + amdgpu_glamor_nodstbo_ops.Polylines = pGC->ops->Polylines; + amdgpu_glamor_nodstbo_ops.PolySegment = pGC->ops->PolySegment; + amdgpu_glamor_nodstbo_ops.PolyFillRect = pGC->ops->PolyFillRect; + amdgpu_glamor_nodstbo_ops.ImageGlyphBlt = pGC->ops->ImageGlyphBlt; + amdgpu_glamor_nodstbo_ops.PolyGlyphBlt = pGC->ops->PolyGlyphBlt; + amdgpu_glamor_nodstbo_ops.PushPixels = amdgpu_glamor_push_pixels_nodstbo; + + nodstbo_ops_initialized = TRUE; + } + + pGC->funcs = &glamorGCFuncs; + + return TRUE; +} + +/* + * Screen rendering wrappers + */ + +static RegionPtr +amdgpu_glamor_bitmap_to_region(PixmapPtr pPix) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pPix->drawable.pScreen); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pPix); + RegionPtr ret; + + if (!amdgpu_glamor_prepare_access_cpu_ro(scrn, pPix, priv)) + return NULL; + ret = fbPixmapToRegion(pPix); + amdgpu_glamor_finish_access_cpu(pPix); + return ret; +} + +static void +amdgpu_glamor_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pWin->drawable.pScreen); + PixmapPtr pixmap = get_drawable_pixmap(&pWin->drawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + fbCopyWindow(pWin, ptOldOrg, prgnSrc); + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +static void +amdgpu_glamor_get_image(DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) { + fbGetImage(pDrawable, x, y, w, h, format, planeMask, d); + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +static void +amdgpu_glamor_get_spans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, + int *pwidth, int nspans, char *pdstStart) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); + + if (amdgpu_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) { + fbGetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + amdgpu_glamor_finish_access_cpu(pixmap); + } +} + +/* + * Picture screen rendering wrappers + */ + +#ifdef RENDER + +static void +amdgpu_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) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pDrawable->pScreen); + AMDGPUInfoPtr info; + PixmapPtr pixmap; + struct amdgpu_pixmap *dst_priv, *src_priv = NULL, *mask_priv = NULL; + Bool gpu_done = FALSE; + + if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap)) + goto fallback; + + pixmap = get_drawable_pixmap(pDst->pDrawable); + if (&pixmap->drawable != pDst->pDrawable || + pixmap->usage_hint != AMDGPU_CREATE_PIXMAP_SCANOUT) + goto fallback; + + dst_priv = amdgpu_get_pixmap_private(pixmap); + if (!amdgpu_glamor_prepare_access_gpu(dst_priv)) + goto fallback; + + info = AMDGPUPTR(scrn); + if (!pSrc->pDrawable || + ((pixmap = get_drawable_pixmap(pSrc->pDrawable)) && + (src_priv = amdgpu_get_pixmap_private(pixmap)) && + amdgpu_glamor_prepare_access_gpu(src_priv))) { + if (!pMask || !pMask->pDrawable || + ((pixmap = get_drawable_pixmap(pMask->pDrawable)) && + (mask_priv = amdgpu_get_pixmap_private(pixmap)) && + amdgpu_glamor_prepare_access_gpu(mask_priv))) { + info->glamor.SavedComposite(op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + gpu_done = TRUE; + + if (mask_priv) + amdgpu_glamor_finish_access_gpu_ro(info, mask_priv); + } + + if (src_priv) + amdgpu_glamor_finish_access_gpu_ro(info, src_priv); + } + amdgpu_glamor_finish_access_gpu_rw(info, dst_priv); + + if (gpu_done) + return; + +fallback: + if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, pDst)) { + if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, pSrc)) { + if (!pMask || + amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, pMask)) { + fbComposite(op, pSrc, pMask, pDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst, + width, height); + if (pMask) + amdgpu_glamor_picture_finish_access_cpu(pMask); + } + amdgpu_glamor_picture_finish_access_cpu(pSrc); + } + amdgpu_glamor_picture_finish_access_cpu(pDst); + } +} + +static void +amdgpu_glamor_add_traps(PicturePtr pPicture, + INT16 x_off, INT16 y_off, int ntrap, xTrap *traps) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pPicture->pDrawable->pScreen); + + if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, pPicture)) { + fbAddTraps(pPicture, x_off, y_off, ntrap, traps); + amdgpu_glamor_picture_finish_access_cpu(pPicture); + } +} + +static void +amdgpu_glamor_glyphs(CARD8 op, + PicturePtr src, + PicturePtr dst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr *glyphs) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen); + + if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, dst)) { + if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, src)) { + AMDGPUInfoPtr info = AMDGPUPTR(scrn); + + info->glamor.SavedGlyphs(op, src, dst, maskFormat, xSrc, + ySrc, nlist, list, glyphs); + amdgpu_glamor_picture_finish_access_cpu(src); + } + amdgpu_glamor_picture_finish_access_cpu(dst); + } +} + +static void +amdgpu_glamor_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen); + + if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, dst)) { + if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, src)) { + AMDGPUInfoPtr info = AMDGPUPTR(scrn); + + info->glamor.SavedTrapezoids(op, src, dst, maskFormat, + xSrc, ySrc, ntrap, traps); + amdgpu_glamor_picture_finish_access_cpu(src); + } + amdgpu_glamor_picture_finish_access_cpu(dst); + } +} + +static void +amdgpu_glamor_triangles(CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tri) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen); + + if (amdgpu_glamor_picture_prepare_access_cpu_rw(scrn, dst)) { + if (amdgpu_glamor_picture_prepare_access_cpu_ro(scrn, src)) { + AMDGPUInfoPtr info = AMDGPUPTR(scrn); + + info->glamor.SavedTriangles(op, src, dst, maskFormat, + xSrc, ySrc, ntri, tri); + amdgpu_glamor_picture_finish_access_cpu(src); + } + amdgpu_glamor_picture_finish_access_cpu(dst); + } +} + +#endif /* RENDER */ + + +/** + * amdgpu_glamor_close_screen() unwraps its wrapped screen functions and tears + * down our screen private, before calling down to the next CloseScreen. + */ +static Bool +amdgpu_glamor_close_screen(CLOSE_SCREEN_ARGS_DECL) +{ + AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(pScreen)); +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); +#endif + + pScreen->CreateGC = info->glamor.SavedCreateGC; + pScreen->CloseScreen = info->glamor.SavedCloseScreen; + pScreen->GetImage = info->glamor.SavedGetImage; + pScreen->GetSpans = info->glamor.SavedGetSpans; + pScreen->CreatePixmap = info->glamor.SavedCreatePixmap; + pScreen->DestroyPixmap = info->glamor.SavedDestroyPixmap; + pScreen->CopyWindow = info->glamor.SavedCopyWindow; + pScreen->ChangeWindowAttributes = + info->glamor.SavedChangeWindowAttributes; + pScreen->BitmapToRegion = info->glamor.SavedBitmapToRegion; +#ifdef RENDER + if (ps) { + ps->Composite = info->glamor.SavedComposite; + ps->Glyphs = info->glamor.SavedGlyphs; + ps->UnrealizeGlyph = info->glamor.SavedUnrealizeGlyph; + ps->Trapezoids = info->glamor.SavedTrapezoids; + ps->AddTraps = info->glamor.SavedAddTraps; + ps->Triangles = info->glamor.SavedTriangles; + + ps->UnrealizeGlyph = info->glamor.SavedUnrealizeGlyph; + } +#endif + + return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS); +} + +/** + * @param screen screen being initialized + */ +void +amdgpu_glamor_screen_init(ScreenPtr screen) +{ + AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(screen)); + + /* + * Replace various fb screen functions + */ + info->glamor.SavedCloseScreen = screen->CloseScreen; + screen->CloseScreen = amdgpu_glamor_close_screen; + + info->glamor.SavedCreateGC = screen->CreateGC; + screen->CreateGC = amdgpu_glamor_create_gc; + + info->glamor.SavedGetImage = screen->GetImage; + screen->GetImage = amdgpu_glamor_get_image; + + info->glamor.SavedGetSpans = screen->GetSpans; + screen->GetSpans = amdgpu_glamor_get_spans; + + info->glamor.SavedCreatePixmap = screen->CreatePixmap; + info->glamor.SavedDestroyPixmap = screen->DestroyPixmap; + + info->glamor.SavedCopyWindow = screen->CopyWindow; + screen->CopyWindow = amdgpu_glamor_copy_window; + + info->glamor.SavedBitmapToRegion = screen->BitmapToRegion; + screen->BitmapToRegion = amdgpu_glamor_bitmap_to_region; + +#ifdef RENDER + { + PictureScreenPtr ps = GetPictureScreenIfSet(screen); + if (ps) { + info->glamor.SavedComposite = ps->Composite; + ps->Composite = amdgpu_glamor_composite; + + info->glamor.SavedUnrealizeGlyph = ps->UnrealizeGlyph; + + ps->Glyphs = amdgpu_glamor_glyphs; + ps->Triangles = amdgpu_glamor_triangles; + ps->Trapezoids = amdgpu_glamor_trapezoids; + + info->glamor.SavedAddTraps = ps->AddTraps; + ps->AddTraps = amdgpu_glamor_add_traps; + } + } +#endif +} + +#endif /* USE_GLAMOR */ |