diff options
author | Jerome Glisse <jglisse@redhat.com> | 2009-08-04 21:09:25 +0200 |
---|---|---|
committer | Jerome Glisse <jglisse@redhat.com> | 2009-08-04 21:09:25 +0200 |
commit | 22074cf0e58fddba743924532625e6fca49b6bdc (patch) | |
tree | f93185c453c6723893e5b0be2ea1121d2ec6a4ff /src/radeon_exa_funcs.c | |
parent | fce31b61a88522733863a9b4e9f1c935c439cb4e (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/radeon_exa_funcs.c')
-rw-r--r-- | src/radeon_exa_funcs.c | 94 |
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 |