diff --git a/src/radeon_bo_helper.c b/src/radeon_bo_helper.c index 593c690..0c447c5 100644 --- a/src/radeon_bo_helper.c +++ b/src/radeon_bo_helper.c @@ -25,6 +25,7 @@ #endif #include "radeon.h" +#include "radeon_bo_gem.h" static const unsigned MicroBlockTable[5][3][2] = { @@ -181,3 +182,66 @@ radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth, *new_pitch = pitch; return bo; } + +#ifdef RADEON_PIXMAP_SHARING + +Bool RADEONSharePixmapBacking(struct radeon_bo *bo, void **handle_p) +{ + int handle; + + if (radeon_gem_prime_share_bo(bo, &handle) != 0) + return FALSE; + + *handle_p = (void *)(long)handle; + return TRUE; +} + +Bool RADEONSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle, + struct radeon_surface *surface) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen); + RADEONInfoPtr info = RADEONPTR(pScrn); + struct radeon_bo *bo; + int ihandle = (int)(long)fd_handle; + uint32_t size = ppix->devKind * ppix->drawable.height; + + bo = radeon_gem_bo_open_prime(info->bufmgr, ihandle, size); + if (!bo) + return FALSE; + + memset(surface, 0, sizeof(struct radeon_surface)); + + if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { + + surface->npix_x = ppix->drawable.width; + surface->npix_y = ppix->drawable.height; + surface->npix_z = 1; + surface->blk_w = 1; + surface->blk_h = 1; + surface->blk_d = 1; + surface->array_size = 1; + surface->bpe = ppix->drawable.bitsPerPixel / 8; + surface->nsamples = 1; + surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); + surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE); + if (radeon_surface_best(info->surf_man, surface)) { + return FALSE; + } + if (radeon_surface_init(info->surf_man, surface)) { + return FALSE; + } + /* we have to post hack the surface to reflect the actual size + of the shared pixmap */ + surface->level[0].pitch_bytes = ppix->devKind; + surface->level[0].nblk_x = ppix->devKind / surface->bpe; + } + radeon_set_pixmap_bo(ppix, bo); + + close(ihandle); + /* we have a reference from the alloc and one from set pixmap bo, + drop one */ + radeon_bo_unref(bo); + return TRUE; +} + +#endif /* RADEON_PIXMAP_SHARING */ diff --git a/src/radeon_bo_helper.h b/src/radeon_bo_helper.h index 0f6fffb..c3d80a3 100644 --- a/src/radeon_bo_helper.h +++ b/src/radeon_bo_helper.h @@ -28,4 +28,11 @@ radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth, int usage_hint, int bitsPerPixel, int *new_pitch, struct radeon_surface *new_surface, uint32_t *new_tiling); +extern Bool +RADEONSharePixmapBacking(struct radeon_bo *bo, void **handle_p); + +extern Bool +RADEONSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle, + struct radeon_surface *surface); + #endif /* RADEON_BO_HELPER_H */ diff --git a/src/radeon_exa.c b/src/radeon_exa.c index 22e2cef..1264108 100644 --- a/src/radeon_exa.c +++ b/src/radeon_exa.c @@ -315,72 +315,24 @@ void RADEONEXADestroyPixmap(ScreenPtr pScreen, void *driverPriv) #ifdef RADEON_PIXMAP_SHARING Bool RADEONEXASharePixmapBacking(PixmapPtr ppix, ScreenPtr slave, void **fd_handle) { - struct radeon_exa_pixmap_priv *driver_priv; - int ret; - int handle; + struct radeon_exa_pixmap_priv *driver_priv = exaGetPixmapDriverPrivate(ppix); - driver_priv = exaGetPixmapDriverPrivate(ppix); - - ret = radeon_gem_prime_share_bo(driver_priv->bo, &handle); - if (ret) + if (!RADEONSharePixmapBacking(driver_priv->bo, fd_handle)) return FALSE; driver_priv->shared = TRUE; - *fd_handle = (void *)(long)handle; return TRUE; } Bool RADEONEXASetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle) { - ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen); - RADEONInfoPtr info = RADEONPTR(pScrn); - struct radeon_exa_pixmap_priv *driver_priv; - struct radeon_bo *bo; - int ihandle = (int)(long)fd_handle; - uint32_t size = ppix->devKind * ppix->drawable.height; - struct radeon_surface surface; - - driver_priv = exaGetPixmapDriverPrivate(ppix); - - bo = radeon_gem_bo_open_prime(info->bufmgr, ihandle, size); - if (!bo) - return FALSE; - - memset(&surface, 0, sizeof(struct radeon_surface)); - - if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { - - surface.npix_x = ppix->drawable.width; - surface.npix_y = ppix->drawable.height; - surface.npix_z = 1; - surface.blk_w = 1; - surface.blk_h = 1; - surface.blk_d = 1; - surface.array_size = 1; - surface.bpe = ppix->drawable.bitsPerPixel / 8; - surface.nsamples = 1; - surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); - surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE); - if (radeon_surface_best(info->surf_man, &surface)) { - return FALSE; - } - if (radeon_surface_init(info->surf_man, &surface)) { - return FALSE; - } - /* we have to post hack the surface to reflect the actual size - of the shared pixmap */ - surface.level[0].pitch_bytes = ppix->devKind; - surface.level[0].nblk_x = ppix->devKind / surface.bpe; - } - driver_priv->surface = surface; + struct radeon_exa_pixmap_priv *driver_priv = exaGetPixmapDriverPrivate(ppix); + + if (!RADEONSetSharedPixmapBacking(ppix, fd_handle, &driver_priv->surface)) + return FALSE; + driver_priv->shared = TRUE; driver_priv->tiling_flags = 0; - radeon_set_pixmap_bo(ppix, bo); - - close(ihandle); - /* we have a reference from the alloc and one from set pixmap bo, - drop one */ - radeon_bo_unref(bo); return TRUE; } #endif diff --git a/src/radeon_glamor.c b/src/radeon_glamor.c index 5ee193c..5041215 100644 --- a/src/radeon_glamor.c +++ b/src/radeon_glamor.c @@ -244,6 +244,71 @@ static Bool radeon_glamor_destroy_pixmap(PixmapPtr pixmap) return TRUE; } +#ifdef RADEON_PIXMAP_SHARING + +static Bool +radeon_glamor_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, + void **handle_p) +{ + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (!priv->bo) { + ScreenPtr screen = pixmap->drawable.pScreen; + PixmapPtr bo_pixmap; + GCPtr gc; + + bo_pixmap = screen->CreatePixmap(screen, + pixmap->drawable.width, + pixmap->drawable.height, + pixmap->drawable.depth, + pixmap->usage_hint | + CREATE_PIXMAP_USAGE_SHARED | + RADEON_CREATE_PIXMAP_DRI2); + if (!bo_pixmap) + return FALSE; + + priv = radeon_get_pixmap_private(bo_pixmap); + + /* Copy the current contents of the pixmap to the bo. */ + gc = GetScratchGC(pixmap->drawable.depth, screen); + if (!gc || !priv->bo) { + screen->DestroyPixmap(bo_pixmap); + return FALSE; + } + + ValidateGC(&bo_pixmap->drawable, gc); + gc->ops->CopyArea(&pixmap->drawable, &bo_pixmap->drawable, + gc, + 0, 0, + pixmap->drawable.width, + pixmap->drawable.height, + 0, 0); + FreeScratchGC(gc); + + radeon_set_pixmap_private(bo_pixmap, NULL); + screen->DestroyPixmap(bo_pixmap); + + /* And redirect the pixmap to the new bo (for 3D). */ + radeon_set_pixmap_private(pixmap, priv); + } + + return RADEONSharePixmapBacking(priv->bo, handle_p); +} + +static Bool +radeon_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle) +{ + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (!RADEONSetSharedPixmapBacking(pixmap, handle, &priv->surface)) + return FALSE; + + priv->tiling_flags = 0; + return TRUE; +} + +#endif /* RADEON_PIXMAP_SHARING */ + Bool radeon_glamor_init(ScreenPtr screen) { @@ -271,6 +336,10 @@ radeon_glamor_init(ScreenPtr screen) screen->CreatePixmap = radeon_glamor_create_pixmap; screen->DestroyPixmap = radeon_glamor_destroy_pixmap; +#ifdef RADEON_PIXMAP_SHARING + screen->SharePixmapBacking = radeon_glamor_share_pixmap_backing; + screen->SetSharedPixmapBacking = radeon_glamor_set_shared_pixmap_backing; +#endif xf86DrvMsg(scrn->scrnIndex, X_INFO, "Use GLAMOR acceleration.\n");