diff --git a/src/radeon_exa_funcs.c b/src/radeon_exa_funcs.c index 6a2b25c..3de063b 100644 --- a/src/radeon_exa_funcs.c +++ b/src/radeon_exa_funcs.c @@ -231,7 +231,7 @@ FUNC_NAME(RADEONCopy)(PixmapPtr pDst, dstY += h - 1; } - if (info->accel_state->vsync) + if (info->accel_state->vsync) FUNC_NAME(RADEONWaitForVLine)(pScrn, pDst, RADEONBiggerCrtcArea(pDst), dstY, dstY + h); BEGIN_ACCEL(3); @@ -336,8 +336,8 @@ RADEONBlitChunk(ScrnInfoPtr pScrn, uint32_t datatype, uint32_t src_pitch_offset, static Bool -RADEONDownloadFromScreenCP(PixmapPtr pSrc, int x, int y, int w, int h, - char *dst, int dst_pitch) +RADEONDownloadFromScreenCPBlit(PixmapPtr pSrc, int x, int y, int w, int h, + char *dst, int dst_pitch) { RINFO_FROM_SCREEN(pSrc->drawable.pScreen); uint8_t *src = info->FB + exaGetPixmapOffset(pSrc); @@ -442,6 +442,102 @@ RADEONDownloadFromScreenCP(PixmapPtr pSrc, int x, int y, int w, int h, return FALSE; } +static Bool +RADEONDownloadFromScreenCPDMA(PixmapPtr pSrc, int x, int y, int w, int h, + char *dst, int dst_pitch) +{ + ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + uint32_t src_mc_addr = exaGetPixmapOffset(pSrc) + info->fbLocation + pScrn->fbOffset; + uint32_t src_pitch = exaGetPixmapPitch(pSrc); + int cpp = pSrc->drawable.bitsPerPixel / 8; + drmBufPtr scratch = NULL; + drm_radeon_indirect_t indirect; + uint32_t scratch_mc_addr; + int i, hpass; + uint8_t *src; + int swap = RADEON_HOST_DATA_SWAP_NONE; + ACCEL_PREAMBLE(); + + scratch = RADEONCPGetBuffer(pScrn); + if (scratch == NULL) + return FALSE; + +#if X_BYTE_ORDER == X_BIG_ENDIAN + switch (pSrc->drawable.bitsPerPixel) { + case 16: + swap = RADEON_HOST_DATA_SWAP_16BIT; + break; + case 32: + swap = RADEON_HOST_DATA_SWAP_32BIT; + break; + } +#endif + + w *= cpp; + src_mc_addr += (x * cpp) + (y * src_pitch); + + RADEON_SWITCH_TO_2D(); + while (h) { + hpass = min(h, scratch->total / w); + scratch_mc_addr = info->gartLocation + info->dri->bufStart + (scratch->idx * scratch->total); + src = (uint8_t *)scratch->address; + BEGIN_ACCEL(2 + (hpass * 3)); + OUT_ACCEL_REG(RADEON_WAIT_UNTIL, + RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_DMA_GUI_IDLE); + for (i = 0; i < hpass; i++) { + OUT_ACCEL_REG(R200_CP_GUI_SRC_ADDR, src_mc_addr); + OUT_ACCEL_REG(R200_CP_GUI_DST_ADDR, scratch_mc_addr); + /* XXX: use DMA endian swapper */ + OUT_ACCEL_REG(R200_CP_GUI_COMMAND, (RADEON_CP_GUI_EOL | + RADEON_CP_GUI_INTDIS | + /*RADEON_CP_GUI_SRC_SWAP(swap) |*/ + w)); + src_mc_addr += src_pitch; + scratch_mc_addr += w; + } + OUT_ACCEL_REG(RADEON_WAIT_UNTIL, RADEON_WAIT_DMA_GUI_IDLE); + FINISH_ACCEL(); + FLUSH_RING(); + + while ((drmCommandNone(info->dri->drmFD, DRM_RADEON_CP_IDLE) == -EBUSY) + && (i++ < RADEON_TIMEOUT)) + ; + + for (i = 0; i < hpass; i++) { + RADEONCopySwap((uint8_t*)dst, src, w, swap); + src += w; + dst += dst_pitch; + } + h -= hpass; + } + + indirect.idx = scratch->idx; + indirect.start = indirect.end = 0; + indirect.discard = 1; + + drmCommandWriteRead(info->dri->drmFD, DRM_RADEON_INDIRECT, + &indirect, sizeof(drm_radeon_indirect_t)); + + info->accel_state->exaMarkerSynced = info->accel_state->exaSyncMarker; + + return TRUE; +} + +static Bool +RADEONDownloadFromScreenCP(PixmapPtr pSrc, int x, int y, int w, int h, + char *dst, int dst_pitch) +{ + ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + + /* R1xx only support descriptor table based gui dma */ + if (info->ChipFamily >= CHIP_FAMILY_R200) + return RADEONDownloadFromScreenCPDMA(pSrc, x, y, w, h, dst, dst_pitch); + else + return RADEONDownloadFromScreenCPBlit(pSrc, x, y, w, h, dst, dst_pitch); +} + #endif /* def ACCEL_CP */ diff --git a/src/radeon_reg.h b/src/radeon_reg.h index d230a20..2ea4eeb 100644 --- a/src/radeon_reg.h +++ b/src/radeon_reg.h @@ -1712,6 +1712,18 @@ #define RADEON_VIPH_REG_DATA 0x0084 #define RADEON_VIPH_REG_ADDR 0x0080 +#define R200_CP_GUI_SRC_ADDR 0x0720 +#define R200_CP_GUI_DST_ADDR 0x0724 +#define R200_CP_GUI_COMMAND 0x0728 +# define RADEON_CP_GUI_BYTE_COUNT_MASK 0x1fffff +# define RADEON_CP_GUI_SRC_SWAP(x) ((x) << 22) +# define RADEON_CP_GUI_DST_SWAP(x) ((x) << 24) +# define RADEON_CP_GUI_SAS_REG (1 << 26) +# define RADEON_CP_GUI_DAS_REG (1 << 27) +# define RADEON_CP_GUI_SAIC (1 << 28) +# define RADEON_CP_GUI_DAIC (1 << 29) +# define RADEON_CP_GUI_INTDIS (1 << 30) +# define RADEON_CP_GUI_EOL (1 << 31) #define RADEON_WAIT_UNTIL 0x1720 # define RADEON_WAIT_CRTC_PFLIP (1 << 0)