summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJerome Glisse <jglisse@redhat.com>2009-08-04 21:09:25 +0200
committerJerome Glisse <jglisse@redhat.com>2009-08-04 21:09:25 +0200
commit22074cf0e58fddba743924532625e6fca49b6bdc (patch)
treef93185c453c6723893e5b0be2ea1121d2ec6a4ff /src
parentfce31b61a88522733863a9b4e9f1c935c439cb4e (diff)
radeon/kms: add simple DownloadFromScreen implementation
What we want to do is add userspace object support to radeon kernel modesetting. Also this DFS is dumb and might endup doing blit from GTT to GTT.
Diffstat (limited to 'src')
-rw-r--r--src/radeon_exa_funcs.c94
1 files changed, 86 insertions, 8 deletions
diff --git a/src/radeon_exa_funcs.c b/src/radeon_exa_funcs.c
index 19adffbd..5d2391fe 100644
--- a/src/radeon_exa_funcs.c
+++ b/src/radeon_exa_funcs.c
@@ -402,14 +402,22 @@ RADEONUploadToScreenCP(PixmapPtr pDst, int x, int y, int w, int h,
/* Emit blit with arbitrary source and destination offsets and pitches */
static void
-RADEONBlitChunk(ScrnInfoPtr pScrn, uint32_t datatype, uint32_t src_pitch_offset,
- uint32_t dst_pitch_offset, int srcX, int srcY, int dstX, int dstY,
- int w, int h)
+RADEONBlitChunk(ScrnInfoPtr pScrn, struct radeon_bo *src_bo,
+ struct radeon_bo *dst_bo, uint32_t datatype,
+ uint32_t src_pitch_offset, uint32_t dst_pitch_offset,
+ int srcX, int srcY, int dstX, int dstY, int w, int h,
+ uint32_t src_domain, uint32_t dst_domain)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
ACCEL_PREAMBLE();
- BEGIN_ACCEL(6);
+ if (src_bo && dst_bo) {
+ BEGIN_ACCEL_RELOC(6, 2);
+ } else if (src_bo && dst_bo == NULL) {
+ BEGIN_ACCEL_RELOC(6, 1);
+ } else {
+ BEGIN_ACCEL(6);
+ }
OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL,
RADEON_GMC_DST_PITCH_OFFSET_CNTL |
RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
@@ -421,7 +429,13 @@ RADEONBlitChunk(ScrnInfoPtr pScrn, uint32_t datatype, uint32_t src_pitch_offset,
RADEON_GMC_CLR_CMP_CNTL_DIS |
RADEON_GMC_WR_MSK_DIS);
OUT_ACCEL_REG(RADEON_SRC_PITCH_OFFSET, src_pitch_offset);
+ if (src_bo) {
+ OUT_RELOC(src_bo, src_domain, 0);
+ }
OUT_ACCEL_REG(RADEON_DST_PITCH_OFFSET, dst_pitch_offset);
+ if (dst_bo) {
+ OUT_RELOC(dst_bo, 0, dst_domain);
+ }
OUT_ACCEL_REG(RADEON_SRC_Y_X, (srcY << 16) | srcX);
OUT_ACCEL_REG(RADEON_DST_Y_X, (dstY << 16) | dstX);
OUT_ACCEL_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | w);
@@ -433,6 +447,67 @@ RADEONBlitChunk(ScrnInfoPtr pScrn, uint32_t datatype, uint32_t src_pitch_offset,
FINISH_ACCEL();
}
+static Bool
+RADEONDownloadFromScreenCS(PixmapPtr pSrc, int x, int y, int w,
+ int h, char *dst, int dst_pitch)
+{
+ RINFO_FROM_SCREEN(pSrc->drawable.pScreen);
+ struct radeon_exa_pixmap_priv *driver_priv;
+ struct radeon_bo *scratch;
+ unsigned size;
+ uint32_t datatype = 0;
+ uint32_t src_pitch_offset;
+ unsigned bpp = pSrc->drawable.bitsPerPixel;
+ uint32_t scratch_pitch = (w * bpp / 8 + 63) & ~63;
+ int r;
+
+ driver_priv = exaGetPixmapDriverPrivate(pSrc);
+ /* if we have more refs than just the BO then flush */
+ if (driver_priv->bo->cref)
+ radeon_cs_flush_indirect(pScrn);
+ radeon_bo_wait(driver_priv->bo);
+ size = scratch_pitch * h;
+ scratch = radeon_bo_open(info->bufmgr, 0, size, 0, RADEON_GEM_DOMAIN_GTT, 0);
+ if (scratch == NULL) {
+ return FALSE;
+ }
+ radeon_cs_space_reset_bos(info->cs);
+ radeon_add_pixmap(info->cs, pSrc, RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM, 0);
+ radeon_cs_space_add_persistent_bo(info->cs, scratch, 0, RADEON_GEM_DOMAIN_GTT);
+ r = radeon_cs_space_check(info->cs);
+ if (r) {
+ r = FALSE;
+ goto out;
+ }
+ RADEONGetDatatypeBpp(pSrc->drawable.bitsPerPixel, &datatype);
+ RADEONGetPixmapOffsetPitch(pSrc, &src_pitch_offset);
+ ACCEL_PREAMBLE();
+ RADEON_SWITCH_TO_2D();
+ RADEONBlitChunk(pScrn, driver_priv->bo, scratch, datatype, src_pitch_offset,
+ scratch_pitch << 16, x, y, 0, 0, w, h,
+ RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT,
+ RADEON_GEM_DOMAIN_GTT);
+ FLUSH_RING();
+
+ radeon_bo_wait(scratch);
+ r = radeon_bo_map(scratch, 0);
+ if (r) {
+ r = FALSE;
+ goto out;
+ }
+ r = TRUE;
+ w *= bpp / 8;
+ size = 0;
+ while (h--) {
+ memcpy(dst, scratch->ptr + size, w);
+ size += scratch_pitch;
+ dst += dst_pitch;
+ }
+ radeon_bo_unmap(scratch);
+out:
+ radeon_bo_unref(scratch);
+ return r;
+}
static Bool
RADEONDownloadFromScreenCP(PixmapPtr pSrc, int x, int y, int w, int h,
@@ -466,8 +541,8 @@ RADEONDownloadFromScreenCP(PixmapPtr pSrc, int x, int y, int w, int h,
RADEON_SWITCH_TO_2D();
/* Kick the first blit as early as possible */
- RADEONBlitChunk(pScrn, datatype, src_pitch_offset, scratch_pitch_offset,
- x, y, 0, 0, w, hpass);
+ RADEONBlitChunk(pScrn, NULL, NULL, datatype, src_pitch_offset,
+ scratch_pitch_offset, x, y, 0, 0, w, hpass, 0, 0);
FLUSH_RING();
#if X_BYTE_ORDER == X_BIG_ENDIAN
@@ -493,8 +568,9 @@ RADEONDownloadFromScreenCP(PixmapPtr pSrc, int x, int y, int w, int h,
/* Prepare next blit if anything's left */
if (hpass) {
scratch_off = scratch->total/2 - scratch_off;
- RADEONBlitChunk(pScrn, datatype, src_pitch_offset, scratch_pitch_offset + (scratch_off >> 10),
- x, y, 0, 0, w, hpass);
+ RADEONBlitChunk(pScrn, NULL, NULL, datatype, src_pitch_offset,
+ scratch_pitch_offset + (scratch_off >> 10),
+ x, y, 0, 0, w, hpass, 0, 0);
}
/*
@@ -571,6 +647,8 @@ Bool FUNC_NAME(RADEONDrawInit)(ScreenPtr pScreen)
info->accel_state->exa->UploadToScreen = RADEONUploadToScreenCP;
if (info->accelDFS)
info->accel_state->exa->DownloadFromScreen = RADEONDownloadFromScreenCP;
+ } else {
+ info->accel_state->exa->DownloadFromScreen = &RADEONDownloadFromScreenCS;
}
#endif