From 271abfd0ec29851273d8ca5241d963be5c64e43c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 2 May 2008 10:06:13 -0700 Subject: [PATCH 01/45] Add initial GEM hacks to bring the server up. --- src/i830.h | 2 +- src/i830_dri.c | 2 ++ src/i830_driver.c | 13 +++----- src/i830_memory.c | 75 ++++++++++++++++++++++------------------------- 4 files changed, 42 insertions(+), 50 deletions(-) diff --git a/src/i830.h b/src/i830.h index 4e82036b..8bc0af4f 100644 --- a/src/i830.h +++ b/src/i830.h @@ -195,7 +195,7 @@ struct _i830_memory { /** @} */ #ifdef XF86DRI_MM - drmBO bo; + uint32_t gem_handle; Bool lifetime_fixed_offset; #endif }; diff --git a/src/i830_dri.c b/src/i830_dri.c index 4361ad0b..1c5de8f4 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -1542,6 +1542,7 @@ i830_update_sarea(ScrnInfoPtr pScrn, drmI830Sarea *sarea) sarea->third_bo_handle = -1; sarea->depth_bo_handle = -1; #ifdef XF86DRI_MM + /* XXX if (pI830->front_buffer->bo.size) sarea->front_bo_handle = pI830->front_buffer->bo.handle; if (pI830->back_buffer->bo.size) @@ -1550,6 +1551,7 @@ i830_update_sarea(ScrnInfoPtr pScrn, drmI830Sarea *sarea) sarea->third_bo_handle = pI830->third_buffer->bo.handle; if (pI830->depth_buffer->bo.size) sarea->depth_bo_handle = pI830->depth_buffer->bo.handle; + */ #endif /* The rotation is now handled entirely by the X Server, so just leave the diff --git a/src/i830_driver.c b/src/i830_driver.c index ea37e6d6..63fc8cb9 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -3184,9 +3184,10 @@ I830LeaveVT(int scrnIndex, int flags) */ #ifdef XF86DRI_MM if (pI830->directRenderingOpen) { + /* XXX: if (pI830->memory_manager != NULL && pScrn->vtSema) { drmMMLock(pI830->drmSubFD, DRM_BO_MEM_TT, 1, 0); - } + }*/ } #endif /* XF86DRI_MM */ @@ -3224,9 +3225,11 @@ I830EnterVT(int scrnIndex, int flags) /* Unlock the memory manager first of all so that we can pin our * buffer objects */ + /* if (pI830->memory_manager != NULL && pScrn->vtSema) { drmMMUnlock(pI830->drmSubFD, DRM_BO_MEM_TT, 1); } + */ } #endif /* XF86DRI_MM */ @@ -3353,14 +3356,6 @@ I830CloseScreen(int scrnIndex, ScreenPtr pScreen) if (pScrn->vtSema == TRUE) { I830LeaveVT(scrnIndex, 0); -#ifdef XF86DRI_MM - if (pI830->directRenderingEnabled) { - if (pI830->memory_manager != NULL) { - drmMMUnlock(pI830->drmSubFD, DRM_BO_MEM_TT, 1); - } - } -#endif /* XF86DRI_MM */ - } if (pI830->devicesTimer) diff --git a/src/i830_memory.c b/src/i830_memory.c index 84db0ef1..cee46a87 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -101,12 +101,16 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include #include "xf86.h" #include "xf86_OSproc.h" #include "i830.h" #include "i810_reg.h" +#ifdef XF86DRI_MM +#include "i915_drm.h" +#endif #define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1)) @@ -161,27 +165,19 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem) return TRUE; #ifdef XF86DRI_MM - if (mem->bo.size != 0) { + if (mem->gem_handle != 0) { I830Ptr pI830 = I830PTR(pScrn); + struct drm_i915_gem_pin pin; int ret; - ret = drmBOSetStatus(pI830->drmSubFD, &mem->bo, - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_READ | - DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_MASK_MEM | - DRM_BO_FLAG_READ | - DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_NO_EVICT, - 0, 0, 0); + pin.handle = mem->gem_handle; + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_PIN, &pin); if (ret != 0) return FALSE; mem->bound = TRUE; - mem->offset = mem->bo.offset; - mem->end = mem->bo.offset + mem->size; + mem->offset = pin.offset; + mem->end = mem->offset + mem->size; } #endif @@ -216,13 +212,13 @@ i830_unbind_memory(ScrnInfoPtr pScrn, i830_memory *mem) i830_clear_tiling(pScrn, mem->fence_nr); #ifdef XF86DRI_MM - if (mem->bo.size != 0) { + if (mem->gem_handle != 0) { I830Ptr pI830 = I830PTR(pScrn); + struct drm_i915_gem_unpin unpin; int ret; - ret = drmBOSetStatus(pI830->drmSubFD, &mem->bo, - 0, DRM_BO_FLAG_NO_EVICT, - 0, 0, 0); + unpin.handle = mem->gem_handle; + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_UNPIN, &unpin); if (ret == 0) { mem->bound = FALSE; @@ -254,10 +250,12 @@ i830_free_memory(ScrnInfoPtr pScrn, i830_memory *mem) i830_unbind_memory(pScrn, mem); #ifdef XF86DRI_MM - if (mem->bo.size != 0) { + if (mem->gem_handle != 0) { I830Ptr pI830 = I830PTR(pScrn); + struct drm_gem_unreference unref; - drmBOUnreference(pI830->drmSubFD, &mem->bo); + unref.handle = mem->gem_handle; + ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_UNREFERENCE, &unref); if (pI830->bo_list == mem) { pI830->bo_list = mem->next; if (mem->next) @@ -467,13 +465,15 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) ALIGN_BOTH_ENDS | NEED_NON_STOLEN); if (pI830->memory_manager != NULL) { + struct drm_i915_gem_init init; int ret; + init.gtt_start = pI830->memory_manager->offset; + init.gtt_end = pI830->memory_manager->offset + + pI830->memory_manager->size; + /* Tell the kernel to manage it */ - ret = drmMMInit(pI830->drmSubFD, - pI830->memory_manager->offset / GTT_PAGE_SIZE, - pI830->memory_manager->size / GTT_PAGE_SIZE, - DRM_BO_MEM_TT); + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_INIT, &init); if (ret != 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to initialize kernel memory manager\n"); @@ -503,7 +503,7 @@ i830_allocator_fini(ScrnInfoPtr pScrn) #ifdef XF86DRI_MM /* The memory manager is more special */ if (pI830->memory_manager) { - drmMMTakedown(pI830->drmSubFD, DRM_BO_MEM_TT); + /* XXX drmMMTakedown(pI830->drmSubFD, DRM_BO_MEM_TT);*/ i830_free_memory(pScrn, pI830->memory_manager); pI830->memory_manager = NULL; } @@ -723,8 +723,8 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, { I830Ptr pI830 = I830PTR(pScrn); i830_memory *mem; - unsigned long mask; int ret; + struct drm_gem_alloc alloc; assert((flags & NEED_PHYSICAL_ADDR) == 0); @@ -742,25 +742,17 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, return NULL; } - /* - * Create buffers in local memory to avoid having the creation order - * determine the TT offset. Driver acceleration - * cannot handle changed front buffer TT offsets yet , - * so let's keep our fingers crossed. - */ + memset(&alloc, 0, sizeof(alloc)); + alloc.size = size; - mask = DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_MAPPABLE | - DRM_BO_FLAG_MEM_LOCAL; - if (flags & ALLOW_SHARING) - mask |= DRM_BO_FLAG_SHAREABLE; - - ret = drmBOCreate(pI830->drmSubFD, size, align / GTT_PAGE_SIZE, NULL, - mask, 0, &mem->bo); + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_ALLOC, &alloc); if (ret) { xfree(mem->name); xfree(mem); return NULL; } + mem->gem_handle = alloc.handle; + /* Give buffer obviously wrong offset/end until it's pinned. */ mem->offset = -1; mem->end = -1; @@ -772,7 +764,10 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, /* Bind it if we currently control the VT */ if (pScrn->vtSema) { if (!i830_bind_memory(pScrn, mem)) { - drmBOUnreference(pI830->drmSubFD, &mem->bo); + struct drm_gem_unreference unref; + + unref.handle = mem->gem_handle; + ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_UNREFERENCE, &unref); xfree(mem->name); xfree(mem); return NULL; From 0741020f3725c32c48ad15535b9c0549e4092c23 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 5 May 2008 10:17:01 -0700 Subject: [PATCH 02/45] Set pin alignment for gem on non-965 non-965 tiled frame buffers have fairly strict alignment requirements, 512K on 8xx and 1MB on 9xx, plus they must be aligned to the size of the allocation. --- src/i830_memory.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/i830_memory.c b/src/i830_memory.c index cee46a87..550b4d85 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -171,6 +171,19 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem) int ret; pin.handle = mem->gem_handle; + pin.alignment = 0; + if (mem->tiling) { + if (IS_I965G(pI830)) + pin.alignment = 0; + else { + if (IS_I9XX (pI830)) + pin.alignment = 1024 * 1024; + else + pin.alignment = 512 * 1024; + if (pin.alignment < mem->size) + pin.alignment = mem->size; + } + } ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_PIN, &pin); if (ret != 0) return FALSE; From b9d12da91eb1afb05bd78a40e15f4333e697093d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 5 May 2008 10:44:09 -0700 Subject: [PATCH 03/45] Use GEM for buffer naming now. --- src/i830_dri.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/i830_dri.c b/src/i830_dri.c index 1c5de8f4..239ed6b0 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -65,6 +65,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include +#include +#include #include "xf86.h" #include "xf86_OSproc.h" @@ -1506,6 +1509,27 @@ I830DRIClipNotify(ScreenPtr pScreen, WindowPtr *ppWin, int num) } #endif /* DRI_SUPPORTS_CLIP_NOTIFY */ +static int +i830_name_buffer (ScrnInfoPtr pScrn, i830_memory *mem) +{ +#ifdef XF86DRI_MM + if (mem && mem->gem_handle) + { + I830Ptr pI830 = I830PTR(pScrn); + struct drm_gem_name name; + int ret; + + name.handle = mem->gem_handle; + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_NAME, &name); + if (ret == 0) + return name.name; + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[drm] failed to name buffer %d\n", -errno); + } +#endif + return -1; +} + /** * Update the SAREA fields with current buffer information. * @@ -1537,22 +1561,10 @@ i830_update_sarea(ScrnInfoPtr pScrn, drmI830Sarea *sarea) sarea->log_tex_granularity = pI830->TexGranularity; - sarea->front_bo_handle = -1; - sarea->back_bo_handle = -1; - sarea->third_bo_handle = -1; - sarea->depth_bo_handle = -1; -#ifdef XF86DRI_MM - /* XXX - if (pI830->front_buffer->bo.size) - sarea->front_bo_handle = pI830->front_buffer->bo.handle; - if (pI830->back_buffer->bo.size) - sarea->back_bo_handle = pI830->back_buffer->bo.handle; - if (pI830->third_buffer != NULL && pI830->third_buffer->bo.size) - sarea->third_bo_handle = pI830->third_buffer->bo.handle; - if (pI830->depth_buffer->bo.size) - sarea->depth_bo_handle = pI830->depth_buffer->bo.handle; - */ -#endif + sarea->front_bo_handle = i830_name_buffer (pScrn, pI830->front_buffer); + sarea->back_bo_handle = i830_name_buffer (pScrn, pI830->back_buffer); + sarea->third_bo_handle = i830_name_buffer (pScrn, pI830->third_buffer); + sarea->depth_bo_handle = i830_name_buffer (pScrn, pI830->depth_buffer); /* The rotation is now handled entirely by the X Server, so just leave the * DRI unaware. From 587dc5bfc4ef32942bd7511f932a3a2e2fcdccb0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 5 May 2008 13:35:22 -0700 Subject: [PATCH 04/45] Fix up ring dumping code for non-i965 --- src/i810_reg.h | 3 ++- src/i830_debug.c | 13 ++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/i810_reg.h b/src/i810_reg.h index 834b948c..837865da 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -375,7 +375,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* Current active ring head address: */ -#define ACTHD 0x2074 +#define ACTHD_I965 0x2074 +#define ACTHD 0x20C8 /* Current primary/secondary DMA fetch addresses: */ diff --git a/src/i830_debug.c b/src/i830_debug.c index 074e8b9c..e90ea22a 100644 --- a/src/i830_debug.c +++ b/src/i830_debug.c @@ -1442,13 +1442,12 @@ i830_dump_cmds (ScrnInfoPtr pScrn, /* check for MI_BATCH_BUFFER_START */ if ((data & batch_start_mask) == batch_start_cmd) { - uint32_t batch = ptr[1]; + uint32_t batch = ptr[1] & ~3; if (batch < pI830->FbMapSize) { ErrorF ("\t%08x: %08x\n", (ring + 4) & mask, batch); ErrorF ("Batch buffer at 0x%08x {\n", batch); i830_dump_cmds (pScrn, pI830->FbBase, batch, - pI830->FbMapSize - batch, - 0xffffffff, acthd); + batch + 256, 0xffffffff, acthd); ErrorF ("}\n"); ring = (ring + (count - 1) * 4) & mask; } @@ -1472,8 +1471,8 @@ i830_dump_ring(ScrnInfoPtr pScrn, uint32_t acthd) mask = pI830->LpRing->tail_mask; virt = pI830->LpRing->virtual_start; - ErrorF ("Ring at virtual %p head 0x%x tail 0x%x count %d\n", - virt, head, tail, (((tail + mask + 1) - head) & mask) >> 2); + ErrorF ("Ring at virtual %p head 0x%x tail 0x%x count %d acthd 0x%x\n", + virt, head, tail, (((tail + mask + 1) - head) & mask) >> 2, acthd); /* walk back by instructions */ for (cmd = (head - 256) & mask; @@ -1518,7 +1517,7 @@ i830_dump_error_state(ScrnInfoPtr pScrn) ErrorF("hwstam: 0x%04x ier: 0x%04x imr: 0x%04x iir: 0x%04x\n", INREG16(HWSTAM), INREG16(IER), INREG16(IMR), INREG16(IIR)); - i830_dump_ring (pScrn, 0); + i830_dump_ring (pScrn, INREG(ACTHD)); } void @@ -1555,7 +1554,7 @@ i965_dump_error_state(ScrnInfoPtr pScrn) "imr: 0x%08x iir: 0x%08x\n", INREG(HWSTAM), INREG(IER), INREG(IMR), INREG(IIR)); - acthd = INREG(ACTHD); + acthd = INREG(ACTHD_I965); ErrorF("acthd: 0x%08x dma_fadd_p: 0x%08x\n", acthd, INREG(DMA_FADD_P)); ErrorF("ecoskpd: 0x%08x excc: 0x%08x\n", From 417f86d80525d2f5038628afba8f70f8c0fecca3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 5 May 2008 13:36:19 -0700 Subject: [PATCH 05/45] Move a declaration under #ifndef HAVE_FREE_SHADOW --- src/i830_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i830_driver.c b/src/i830_driver.c index aca01dbb..6e5e92c4 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -3135,8 +3135,8 @@ I830LeaveVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; I830Ptr pI830 = I830PTR(pScrn); - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); #ifndef HAVE_FREE_SHADOW + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); int o; #endif From 10f1d835b8ac7bf3153ac39d295ad2a72c4aa076 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 12 May 2008 12:15:09 -0700 Subject: [PATCH 06/45] Record alignment requirements in mem structure for use by GEM. GEM needs memory alignment requirements sent at pin time, which is a bit after the allocation itself. Store the required alignment in the memory object for later use by pin. --- src/i830.h | 2 ++ src/i830_dri.c | 19 +++++++++++++------ src/i830_memory.c | 19 ++++++------------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/i830.h b/src/i830.h index 6cce0438..f694d606 100644 --- a/src/i830.h +++ b/src/i830.h @@ -196,6 +196,8 @@ struct _i830_memory { #ifdef XF86DRI_MM uint32_t gem_handle; + uint32_t alignment; + uint32_t gem_name; Bool lifetime_fixed_offset; #endif }; diff --git a/src/i830_dri.c b/src/i830_dri.c index 239ed6b0..1cd1732a 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -1519,12 +1519,19 @@ i830_name_buffer (ScrnInfoPtr pScrn, i830_memory *mem) struct drm_gem_name name; int ret; - name.handle = mem->gem_handle; - ret = ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_NAME, &name); - if (ret == 0) - return name.name; - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "[drm] failed to name buffer %d\n", -errno); + if (!mem->gem_name) + { + name.handle = mem->gem_handle; + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_NAME, &name); + if (ret != 0) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[drm] failed to name buffer %d\n", -errno); + return -1; + } + mem->gem_name = name.name; + } + return mem->gem_name; } #endif return -1; diff --git a/src/i830_memory.c b/src/i830_memory.c index 550b4d85..6f3c06b9 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -171,19 +171,10 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem) int ret; pin.handle = mem->gem_handle; - pin.alignment = 0; - if (mem->tiling) { - if (IS_I965G(pI830)) - pin.alignment = 0; - else { - if (IS_I9XX (pI830)) - pin.alignment = 1024 * 1024; - else - pin.alignment = 512 * 1024; - if (pin.alignment < mem->size) - pin.alignment = mem->size; - } - } + pin.alignment = mem->alignment; + xf86DrvMsg (pScrn->scrnIndex, X_ERROR, + "alignment %d size %d\n", mem->alignment, mem->size); + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_PIN, &pin); if (ret != 0) return FALSE; @@ -638,6 +629,7 @@ i830_allocate_aperture(ScrnInfoPtr pScrn, const char *name, size = ALIGN(size, GTT_PAGE_SIZE); mem->size = size; mem->allocated_size = size; + mem->alignment = alignment; if (alignment < GTT_PAGE_SIZE) alignment = GTT_PAGE_SIZE; @@ -771,6 +763,7 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, mem->end = -1; mem->size = size; mem->allocated_size = size; + mem->alignment = align; if (flags & NEED_LIFETIME_FIXED) mem->lifetime_fixed_offset = TRUE; From 089011daf3da8db3bd16d50e1d6a6457da82300e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 12 May 2008 12:18:19 -0700 Subject: [PATCH 07/45] Track name changes in GEM ioctls. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit allocate → create unreference → close name → flink --- src/i830_dri.c | 8 ++++---- src/i830_memory.c | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/i830_dri.c b/src/i830_dri.c index 1cd1732a..10d65edb 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -1516,20 +1516,20 @@ i830_name_buffer (ScrnInfoPtr pScrn, i830_memory *mem) if (mem && mem->gem_handle) { I830Ptr pI830 = I830PTR(pScrn); - struct drm_gem_name name; + struct drm_gem_flink flink; int ret; if (!mem->gem_name) { - name.handle = mem->gem_handle; - ret = ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_NAME, &name); + flink.handle = mem->gem_handle; + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_FLINK, &flink); if (ret != 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[drm] failed to name buffer %d\n", -errno); return -1; } - mem->gem_name = name.name; + mem->gem_name = flink.name; } return mem->gem_name; } diff --git a/src/i830_memory.c b/src/i830_memory.c index 6f3c06b9..0b172cfd 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -173,7 +173,7 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem) pin.handle = mem->gem_handle; pin.alignment = mem->alignment; xf86DrvMsg (pScrn->scrnIndex, X_ERROR, - "alignment %d size %d\n", mem->alignment, mem->size); + "alignment %d size %d\n", mem->alignment, (int) mem->size); ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_PIN, &pin); if (ret != 0) @@ -256,10 +256,10 @@ i830_free_memory(ScrnInfoPtr pScrn, i830_memory *mem) #ifdef XF86DRI_MM if (mem->gem_handle != 0) { I830Ptr pI830 = I830PTR(pScrn); - struct drm_gem_unreference unref; + struct drm_gem_close close; - unref.handle = mem->gem_handle; - ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_UNREFERENCE, &unref); + close.handle = mem->gem_handle; + ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_CLOSE, &close); if (pI830->bo_list == mem) { pI830->bo_list = mem->next; if (mem->next) @@ -729,7 +729,7 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, I830Ptr pI830 = I830PTR(pScrn); i830_memory *mem; int ret; - struct drm_gem_alloc alloc; + struct drm_gem_create create; assert((flags & NEED_PHYSICAL_ADDR) == 0); @@ -747,16 +747,16 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, return NULL; } - memset(&alloc, 0, sizeof(alloc)); - alloc.size = size; + memset(&create, 0, sizeof(create)); + create.size = size; - ret = ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_ALLOC, &alloc); + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_CREATE, &create); if (ret) { xfree(mem->name); xfree(mem); return NULL; } - mem->gem_handle = alloc.handle; + mem->gem_handle = create.handle; /* Give buffer obviously wrong offset/end until it's pinned. */ mem->offset = -1; @@ -770,10 +770,10 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, /* Bind it if we currently control the VT */ if (pScrn->vtSema) { if (!i830_bind_memory(pScrn, mem)) { - struct drm_gem_unreference unref; + struct drm_gem_close close; - unref.handle = mem->gem_handle; - ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_UNREFERENCE, &unref); + close.handle = mem->gem_handle; + ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_CLOSE, &close); xfree(mem->name); xfree(mem); return NULL; From 9c9a5d0e48c6e911574695fc417d2dc1a0fd1c20 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 13 May 2008 12:24:50 -0700 Subject: [PATCH 08/45] Add check for GEM, use that to enable driver GEM support --- configure.ac | 7 +++++++ src/i830_dri.c | 2 +- src/i830_memory.c | 14 +++++++------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 00f075e8..f814ade2 100644 --- a/configure.ac +++ b/configure.ac @@ -217,6 +217,13 @@ if test "$DRI" = yes; then [], [ #include #include +]) + AC_CHECK_DECL(DRM_IOCTL_GEM_CREATE, + [AC_DEFINE(HAVE_DRM_GEM, 1, + [Have DRM Graphics Execution Manager])], + [], [ +#include +#include ]) CFLAGS="$save_CFLAGS" fi diff --git a/src/i830_dri.c b/src/i830_dri.c index 10d65edb..95e1e724 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -1512,7 +1512,7 @@ I830DRIClipNotify(ScreenPtr pScreen, WindowPtr *ppWin, int num) static int i830_name_buffer (ScrnInfoPtr pScrn, i830_memory *mem) { -#ifdef XF86DRI_MM +#if HAVE_DRM_GEM if (mem && mem->gem_handle) { I830Ptr pI830 = I830PTR(pScrn); diff --git a/src/i830_memory.c b/src/i830_memory.c index 0b172cfd..e8ffce38 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -164,7 +164,7 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem) if (mem == NULL || mem->bound) return TRUE; -#ifdef XF86DRI_MM +#if HAVE_DRM_GEM if (mem->gem_handle != 0) { I830Ptr pI830 = I830PTR(pScrn); struct drm_i915_gem_pin pin; @@ -215,7 +215,7 @@ i830_unbind_memory(ScrnInfoPtr pScrn, i830_memory *mem) if (mem->tiling != TILE_NONE) i830_clear_tiling(pScrn, mem->fence_nr); -#ifdef XF86DRI_MM +#if HAVE_DRM_GEM if (mem->gem_handle != 0) { I830Ptr pI830 = I830PTR(pScrn); struct drm_i915_gem_unpin unpin; @@ -253,7 +253,7 @@ i830_free_memory(ScrnInfoPtr pScrn, i830_memory *mem) /* Free any AGP memory. */ i830_unbind_memory(pScrn, mem); -#ifdef XF86DRI_MM +#if HAVE_DRM_GEM if (mem->gem_handle != 0) { I830Ptr pI830 = I830PTR(pScrn); struct drm_gem_close close; @@ -379,7 +379,7 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) { I830Ptr pI830 = I830PTR(pScrn); i830_memory *start, *end; -#ifdef XF86DRI_MM +#if HAVE_DRM_GEM int dri_major, dri_minor, dri_patch; #endif @@ -418,7 +418,7 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) pI830->memory_list = start; -#ifdef XF86DRI_MM +#if HAVE_DRM_GEM DRIQueryVersion(&dri_major, &dri_minor, &dri_patch); /* Now that we have our manager set up, initialize the kernel MM if @@ -721,7 +721,7 @@ i830_allocate_agp_memory(ScrnInfoPtr pScrn, i830_memory *mem, int flags) return TRUE; } -#ifdef XF86DRI_MM +#if HAVE_DRM_GEM static i830_memory * i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, unsigned long size, unsigned long align, int flags) @@ -815,7 +815,7 @@ i830_allocate_memory(ScrnInfoPtr pScrn, const char *name, { i830_memory *mem; -#ifdef XF86DRI_MM +#if HAVE_DRM_GEM I830Ptr pI830 = I830PTR(pScrn); if (pI830->memory_manager && !(flags & NEED_PHYSICAL_ADDR) && From ced4b4bb0c44b55feb5e32ddb860f1c1dc3bbde5 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 22 May 2008 22:10:25 -0700 Subject: [PATCH 09/45] [gem] Reduce console spam from debugging. --- src/i830_memory.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/i830_memory.c b/src/i830_memory.c index e8ffce38..16ae23d2 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -172,9 +172,7 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem) pin.handle = mem->gem_handle; pin.alignment = mem->alignment; - xf86DrvMsg (pScrn->scrnIndex, X_ERROR, - "alignment %d size %d\n", mem->alignment, (int) mem->size); - + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_PIN, &pin); if (ret != 0) return FALSE; From 3a967b8359bd6c05a10111076cdb02df15cbf2e8 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 12 May 2008 13:51:11 -0700 Subject: [PATCH 10/45] [gem] Note if pinning a buffer fails. --- src/i830_memory.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/i830_memory.c b/src/i830_memory.c index 16ae23d2..2596e45d 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -174,8 +174,12 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem) pin.alignment = mem->alignment; ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_PIN, &pin); - if (ret != 0) + if (ret != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to pin %s: %s\n", + mem->name, strerror(errno)); return FALSE; + } mem->bound = TRUE; mem->offset = pin.offset; From cc98d41df63f1ee2561440fab3aa471a80a12920 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 9 Jun 2008 12:00:14 -0700 Subject: [PATCH 11/45] Add a little program to dump out the first 64 dwords of the status page. --- src/i810_reg.h | 1 + src/reg_dumper/Makefile.am | 8 +++- src/reg_dumper/reg_dumper.h | 1 + src/reg_dumper/statuspage.c | 81 ++++++++++++++++++++++++++++++++++ src/reg_dumper/util.c | 86 +++++++++++++++++++++++++++++++++++++ 5 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 src/reg_dumper/statuspage.c create mode 100644 src/reg_dumper/util.c diff --git a/src/i810_reg.h b/src/i810_reg.h index 279677c7..d8e0cb2c 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -491,6 +491,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - new bits for i810 * - new register hwstam (mask) */ +#define HWS_PGA 0x2080 #define PWRCTXA 0x2088 /* 965GM+ only */ #define PWRCTX_EN (1<<0) #define HWSTAM 0x2098 /* p290 */ diff --git a/src/reg_dumper/Makefile.am b/src/reg_dumper/Makefile.am index b840b244..1c8db204 100644 --- a/src/reg_dumper/Makefile.am +++ b/src/reg_dumper/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = intel_reg_dumper intel_idle intel_stepping +noinst_PROGRAMS = intel_reg_dumper intel_idle intel_stepping intel_statuspage intel_reg_dumper_SOURCES = \ main.c \ @@ -15,9 +15,15 @@ intel_idle_SOURCES = \ intel_stepping_SOURCES = \ stepping.c +intel_statuspage_SOURCES = \ + statuspage.c \ + reg_dumper.h \ + util.c + intel_reg_dumper_LDADD = $(PCIACCESS_LIBS) intel_idle_LDADD = $(PCIACCESS_LIBS) intel_stepping_LDADD = $(PCIACCESS_LIBS) +intel_statuspage_LDADD = $(PCIACCESS_LIBS) AM_CFLAGS = $(PCIACCESS_CFLAGS) $(WARN_CFLAGS) \ -I$(srcdir)/.. -DREG_DUMPER diff --git a/src/reg_dumper/reg_dumper.h b/src/reg_dumper/reg_dumper.h index 9a723b9b..241b2419 100644 --- a/src/reg_dumper/reg_dumper.h +++ b/src/reg_dumper/reg_dumper.h @@ -88,3 +88,4 @@ typedef struct _scrn { char *XNFprintf(const char *format, ...); void xf86DrvMsg(int scrnIndex, int severity, const char *format, ...); void i830DumpRegs(ScrnInfoPtr pScrn); +void intel_i830rec_init(I830Ptr pI830); diff --git a/src/reg_dumper/statuspage.c b/src/reg_dumper/statuspage.c new file mode 100644 index 00000000..d6106a5a --- /dev/null +++ b/src/reg_dumper/statuspage.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "reg_dumper.h" +#include "../i810_reg.h" + +int main(int argc, char **argv) +{ + I830Rec i830; + I830Ptr pI830 = &i830; + int devmem; + uint32_t hws_offset; + volatile uint32_t *hws; + + intel_i830rec_init(pI830); + + if (HWS_NEED_GFX(pI830)) + errx(1, "status page in graphics virtual unsupported.\n"); + + hws_offset = INREG(HWS_PGA); + + devmem = open("/dev/mem", O_RDWR, 0); + if (devmem == -1) + err(1, "Couldn't open /dev/mem"); + + hws = mmap(NULL, 4096, PROT_READ, MAP_SHARED, devmem, hws_offset); + if (hws == MAP_FAILED) + err(1, "Couldn't map /dev/mem at 0x%08x", hws_offset); + + close(devmem); + + for (;;) { + int i; + + printf("\n"); + + for (i = 0; i < 64; i += 4) { + printf("0x%04x: 0x%08x 0x%08x 0x%08x 0x%08x\n", i * 4, + hws[i], hws[i + 1], hws[i + 2], hws[i + 3]); + } + + sleep(1); + } + + return 0; +} diff --git a/src/reg_dumper/util.c b/src/reg_dumper/util.c new file mode 100644 index 00000000..6dd1e487 --- /dev/null +++ b/src/reg_dumper/util.c @@ -0,0 +1,86 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +/** @file util.c + * + * Utility functions for the various tools in the reg_dumper directory. + */ + +#include +#include + +#include "reg_dumper.h" + +/** + * Sets up the pI830 for use by common.h-style macros, particularly + * INREG/OUTERG. + */ +void intel_i830rec_init(I830Ptr pI830) +{ + struct pci_device *dev; + int err, mmio_bar; + void *mmio; + + err = pci_system_init(); + if (err != 0) { + fprintf(stderr, "Couldn't initialize PCI system: %s\n", strerror(err)); + exit(1); + } + + /* Grab the graphics card */ + dev = pci_device_find_by_slot(0, 0, 2, 0); + if (dev == NULL) + errx(1, "Couldn't find graphics card"); + + err = pci_device_probe(dev); + if (err != 0) { + fprintf(stderr, "Couldn't probe graphics card: %s\n", strerror(err)); + exit(1); + } + + if (dev->vendor_id != 0x8086) + errx(1, "Graphics card is non-intel"); + + pI830->PciInfo = &pI830->pci_info_rec; + pI830->PciInfo->chipType = dev->device_id; + + pI830->pci_dev = dev; + + mmio_bar = IS_I9XX(pI830) ? 0 : 1; + + err = pci_device_map_range (dev, + dev->regions[mmio_bar].base_addr, + dev->regions[mmio_bar].size, + PCI_DEV_MAP_FLAG_WRITABLE, + &mmio); + + if (err != 0) { + fprintf(stderr, "Couldn't map MMIO region: %s\n", strerror(err)); + exit(1); + } + pI830->mmio = mmio; +} From b2216e7bc2f1a35f9fc1794bad83208cd5c583d1 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 4 Jun 2008 16:31:16 -0700 Subject: [PATCH 12/45] Use batchbuffers instead of ring emits for general commands. The batchbuffers are managed using libdrm and bufmgr_fake, and dispatched from the ring from userland. --- src/Makefile.am | 2 + src/i810_reg.h | 7 +++ src/i830.h | 26 ++++++--- src/i830_accel.c | 18 ++----- src/i830_batchbuffer.c | 119 +++++++++++++++++++++++++++++++++++++++++ src/i830_batchbuffer.h | 106 ++++++++++++++++++++++++++++++++++++ src/i830_driver.c | 86 +++++++++++++++++++++++++---- src/i830_memory.c | 9 ++++ src/i830_ring.h | 5 -- src/i915_3d.h | 10 ++-- 10 files changed, 346 insertions(+), 42 deletions(-) create mode 100644 src/i830_batchbuffer.c create mode 100644 src/i830_batchbuffer.h diff --git a/src/Makefile.am b/src/Makefile.am index 0784c064..7ab1f086 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -89,6 +89,8 @@ intel_drv_la_SOURCES = \ i830_accel.c \ i830_bios.c \ i830_bios.h \ + i830_batchbuffer.c \ + i830_batchbuffer.h \ i830_common.h \ i830_crt.c \ i830_cursor.c \ diff --git a/src/i810_reg.h b/src/i810_reg.h index d8e0cb2c..6a82c19b 100644 --- a/src/i810_reg.h +++ b/src/i810_reg.h @@ -2379,6 +2379,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define STATE3D_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x01<<16)) +/* Batch */ +#define MI_BATCH_BUFFER ((0x30 << 23) | 1) +#define MI_BATCH_BUFFER_START (0x31 << 23) +#define MI_BATCH_BUFFER_END (0xA << 23) +#define MI_BATCH_NON_SECURE (1) +#define MI_BATCH_NON_SECURE_I965 (1 << 8) + /* STATE3D_FOG_MODE stuff */ #define ENABLE_FOG_SOURCE (1<<27) #define ENABLE_FOG_CONST (1<<24) diff --git a/src/i830.h b/src/i830.h index 9cce5bc9..ccf91a04 100644 --- a/src/i830.h +++ b/src/i830.h @@ -81,6 +81,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "damage.h" #endif #endif +#include "dri_bufmgr.h" +#include "intel_bufmgr.h" #ifdef I830_USE_EXA #include "exa.h" @@ -95,7 +97,6 @@ Bool I830XAAInit(ScreenPtr pScreen); typedef struct _I830OutputRec I830OutputRec, *I830OutputPtr; #include "common.h" -#include "i830_ring.h" #include "i830_sdvo.h" #include "i2c_vid.h" @@ -401,6 +402,8 @@ typedef struct _I830Rec { i830_memory *exa_offscreen; i830_memory *gen4_render_state_mem; #endif + i830_memory *fake_bufmgr_mem; + /* Regions allocated either from the above pools, or from agpgart. */ I830RingBuffer *LpRing; @@ -411,6 +414,17 @@ typedef struct _I830Rec { /** Offset in the ring for the next DWORD emit */ uint32_t ring_next; + dri_bufmgr *bufmgr; + + uint8_t *batch_ptr; + /** Byte offset in batch_ptr for the next dword to be emitted. */ + unsigned int batch_used; + /** Position in batch_ptr at the start of the current BEGIN_BATCH */ + unsigned int batch_emit_start; + /** Number of bytes to be emitted in the current BEGIN_BATCH. */ + uint32_t batch_emitting; + dri_bo *batch_bo; + #ifdef I830_XV /* For Xvideo */ i830_memory *overlay_regs; @@ -674,6 +688,9 @@ typedef struct _I830Rec { #define I830_SELECT_DEPTH 2 #define I830_SELECT_THIRD 3 +/* Batchbuffer support macros and functions */ +#include "i830_batchbuffer.h" + /* I830 specific functions */ extern int I830WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis); extern void I830SetPIOAccess(I830Ptr pI830); @@ -898,13 +915,6 @@ Bool i830_pixmap_tiled(PixmapPtr p); if (pitch > KB(8)) I830FALLBACK("pitch exceeds 3d limit 8K\n");\ } while(0) -/* Batchbuffer compatibility handling */ -#define BEGIN_BATCH(n) BEGIN_LP_RING(n) -#define ENSURE_BATCH(n) -#define OUT_BATCH(d) OUT_RING(d) -#define OUT_BATCH_F(x) OUT_RING_F(x) -#define ADVANCE_BATCH() ADVANCE_LP_RING() - extern const int I830PatternROP[16]; extern const int I830CopyROP[16]; diff --git a/src/i830_accel.c b/src/i830_accel.c index 7784c62a..a71ea475 100644 --- a/src/i830_accel.c +++ b/src/i830_accel.c @@ -59,6 +59,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "i830.h" #include "i810_reg.h" #include "i830_debug.h" +#include "i830_ring.h" unsigned long intel_get_pixmap_offset(PixmapPtr pPix) @@ -168,7 +169,6 @@ void I830Sync(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); - int flags = MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE; if (I810_DEBUG & (DEBUG_VERBOSE_ACCEL | DEBUG_VERBOSE_SYNC)) ErrorF("I830Sync\n"); @@ -186,24 +186,12 @@ I830Sync(ScrnInfoPtr pScrn) if (pI830->entityPrivate && !pI830->entityPrivate->RingRunning) return; - if (IS_I965G(pI830)) - flags = 0; + I830EmitFlush(pScrn); - /* Send a flush instruction and then wait till the ring is empty. - * This is stronger than waiting for the blitter to finish as it also - * flushes the internal graphics caches. - */ - - { - BEGIN_BATCH(2); - OUT_BATCH(MI_FLUSH | flags); - OUT_BATCH(MI_NOOP); /* pad to quadword */ - ADVANCE_BATCH(); - } + intel_batch_flush(pScrn); i830_wait_ring_idle(pScrn); - pI830->LpRing->space = pI830->LpRing->mem->size - 8; pI830->nextColorExpandBuf = 0; } diff --git a/src/i830_batchbuffer.c b/src/i830_batchbuffer.c new file mode 100644 index 00000000..19d642d5 --- /dev/null +++ b/src/i830_batchbuffer.c @@ -0,0 +1,119 @@ +/* -*- c-basic-offset: 4 -*- */ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "xf86.h" +#include "i830.h" +#include "i830_ring.h" + +static void +intel_next_batch(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + /* The 865 has issues with larger-than-page-sized batch buffers. */ + if (IS_I865G(pI830)) + pI830->batch_bo = dri_bo_alloc(pI830->bufmgr, "batch", 4096, 4096); + else + pI830->batch_bo = dri_bo_alloc(pI830->bufmgr, "batch", 4096 * 4, 4096); + + dri_bo_map(pI830->batch_bo, 1); + pI830->batch_used = 0; + pI830->batch_ptr = pI830->batch_bo->virtual; +} + +void +intel_batch_init(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + pI830->batch_emit_start = 0; + pI830->batch_emitting = 0; + + intel_next_batch(pScrn); +} + +void +intel_batch_teardown(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (pI830->batch_ptr != NULL) { + dri_bo_unmap(pI830->batch_bo); + pI830->batch_ptr = NULL; + } +} + +void +intel_batch_flush(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (pI830->batch_used == 0) + return; + + /* Emit a padding dword if we aren't going to be quad-word aligned. */ + if ((pI830->batch_used & 4) == 0) { + *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = MI_NOOP; + pI830->batch_used += 4; + } + + /* Mark the end of the batchbuffer. */ + *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = MI_BATCH_BUFFER_END; + pI830->batch_used += 4; + + dri_bo_unmap(pI830->batch_bo); + pI830->batch_ptr = NULL; + + dri_process_relocs(pI830->batch_bo); + + if (!IS_I830(pI830) && !IS_845G(pI830)) { + BEGIN_LP_RING(2); + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); + OUT_RING(pI830->batch_bo->offset); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(4); + OUT_RING(MI_BATCH_BUFFER); + OUT_RING(pI830->batch_bo->offset); + OUT_RING(pI830->batch_bo->offset + pI830->batch_used - 4); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } + + dri_post_submit(pI830->batch_bo); + + dri_bo_unreference(pI830->batch_bo); + intel_next_batch(pScrn); +} diff --git a/src/i830_batchbuffer.h b/src/i830_batchbuffer.h new file mode 100644 index 00000000..91793264 --- /dev/null +++ b/src/i830_batchbuffer.h @@ -0,0 +1,106 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright © 2002 David Dawes + +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#ifndef _INTEL_BATCHBUFFER_H +#define _INTEL_BATCHBUFFER_H + +#define BATCH_RESERVED 16 + +void intel_batch_init(ScrnInfoPtr pScrn); +void intel_batch_teardown(ScrnInfoPtr pScrn); +void intel_batch_flush(ScrnInfoPtr pScrn); + +static inline int +intel_batch_space(I830Ptr pI830) +{ + return (pI830->batch_bo->size - BATCH_RESERVED) - (pI830->batch_used); +} + +static inline void +intel_batch_require_space(ScrnInfoPtr pScrn, I830Ptr pI830, GLuint sz) +{ + assert(sz < pI830->batch_bo->size - 8); + if (intel_batch_space(pI830) < sz) + intel_batch_flush(pScrn); +} + +static inline void +intel_batch_emit_dword(I830Ptr pI830, uint32_t dword) +{ + assert(pI830->batch_ptr != NULL); + assert(intel_batch_space(pI830) >= 4); + *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = dword; + pI830->batch_used += 4; +} + +#define OUT_BATCH(dword) intel_batch_emit_dword(pI830, dword) + +union intfloat { + float f; + unsigned int ui; +}; + +#define OUT_BATCH_F(x) do { \ + union intfloat tmp; \ + tmp.f = (float)(x); \ + OUT_BATCH(tmp.ui); \ +} while(0) + +#define BEGIN_BATCH(n) \ +do { \ + if (pI830->batch_emitting != 0) \ + FatalError("%s: BEGIN_BATCH called without closing " \ + "ADVANCE_BATCH\n", __FUNCTION__); \ + pI830->batch_emitting = (n) * 4; \ + intel_batch_require_space(pScrn, pI830, pI830->batch_emitting); \ + pI830->batch_emit_start = pI830->batch_used; \ +} while (0) + +#define ADVANCE_BATCH() do { \ + if (pI830->batch_emitting == 0) \ + FatalError("%s: ADVANCE_BATCH called with no matching " \ + "BEGIN_BATCH\n", __FUNCTION__); \ + if (pI830->batch_used > pI830->batch_emit_start + pI830->batch_emitting) \ + FatalError("%s: ADVANCE_BATCH: exceeded allocation %d/%d\n ", \ + __FUNCTION__, \ + pI830->batch_used - pI830->batch_emit_start, \ + pI830->batch_emitting); \ + if (pI830->batch_used < pI830->batch_emit_start + pI830->batch_emitting) \ + FatalError("%s: ADVANCE_BATCH: under-used allocation %d/%d\n ", \ + __FUNCTION__, \ + pI830->batch_used - pI830->batch_emit_start, \ + pI830->batch_emitting); \ + if ((pI830->batch_emitting > 8) && (I810_DEBUG & DEBUG_ALWAYS_SYNC)) { \ + /* Note: not actually syncing, just flushing each batch. */ \ + intel_batch_flush(pScrn); \ + } \ + pI830->batch_emitting = 0; \ +} while (0) + +#endif /* _INTEL_BATCHBUFFER_H */ diff --git a/src/i830_driver.c b/src/i830_driver.c index 35df0c75..3a9d4252 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -1838,7 +1838,7 @@ i830_stop_ring(ScrnInfoPtr pScrn, Bool flush) temp = INREG(LP_RING + RING_LEN); if (temp & RING_VALID) { i830_refresh_ring(pScrn); - I830Sync(pScrn); + i830_wait_ring_idle(pScrn); } OUTREG(LP_RING + RING_LEN, 0); @@ -2493,14 +2493,21 @@ I830BlockHandler(int i, pI830->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = I830BlockHandler; - /* Emit a flush of the rendering cache, or on the 965 and beyond - * rendering results may not hit the framebuffer until significantly - * later. In the direct rendering case this is already done just - * after the page flipping updates, so there's no need to duplicate - * the effort here. - */ - if (pScrn->vtSema && !pI830->noAccel && !pI830->directRenderingEnabled) - I830EmitFlush(pScrn); + if (pScrn->vtSema && !pI830->noAccel) { + /* Emit a flush of the rendering cache, or on the 965 and beyond + * rendering results may not hit the framebuffer until significantly + * later. In the direct rendering case this is already done just + * after the page flipping updates, so there's no need to duplicate + * the effort here. + */ + if (!pI830->noAccel && !pI830->directRenderingEnabled) + I830EmitFlush(pScrn); + + /* Flush the batch, so that any rendering is executed in a timely + * fashion. + */ + intel_batch_flush(pScrn); + } /* * Check for FIFO underruns at block time (which amounts to just @@ -2704,6 +2711,55 @@ i830_memory_init(ScrnInfoPtr pScrn) return FALSE; } +/** + * Returns a cookie to be waited on. This is just a stub implementation, and + * should be hooked up to the emit/wait irq functions when available (DRI + * enabled). + */ +static unsigned int +i830_fake_fence_emit(void *priv) +{ + static unsigned int fence = 0; + + /* Match DRM in not using half the range. The fake bufmgr relies on this. */ + if (++fence >= 0x8000000) + fence = 1; + + return fence; +} + +/** + * Waits on a cookie representing a request to be passed. + * + * Stub implementation that should be replaced with DRM functions when + * available. + */ +static int +i830_fake_fence_wait(void *priv, unsigned int fence) +{ + ScrnInfoPtr pScrn = priv; + + i830_wait_ring_idle(pScrn); + + return 0; +} + +static void +i830_init_bufmgr(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + assert(pI830->FbBase != NULL); + pI830->bufmgr = intel_bufmgr_fake_init(pI830->fake_bufmgr_mem->offset, + pI830->FbBase + + pI830->fake_bufmgr_mem->offset, + pI830->fake_bufmgr_mem->size, + i830_fake_fence_emit, + i830_fake_fence_wait, + pScrn); +} + + static Bool I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { @@ -3033,6 +3089,8 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) pI830->xoffset = (pScrn->fbOffset / pI830->cpp) % pScrn->displayWidth; pI830->yoffset = (pScrn->fbOffset / pI830->cpp) / pScrn->displayWidth; + i830_init_bufmgr(pScrn); + vgaHWSetMmioFuncs(hwp, pI830->MMIOBase, 0); vgaHWGetIOBase(hwp); DPRINTF(PFX, "assert( if(!vgaHWMapMem(pScrn)) )\n"); @@ -3276,8 +3334,13 @@ I830LeaveVT(int scrnIndex, int flags) xf86_hide_cursors (pScrn); + I830Sync(pScrn); + RestoreHWState(pScrn); + intel_bufmgr_fake_evict_all(pI830->bufmgr); + intel_batch_teardown(pScrn); + i830_stop_ring(pScrn, TRUE); if (pI830->debug_modes) { @@ -3351,6 +3414,8 @@ I830EnterVT(int scrnIndex, int flags) /* Update the screen pixmap in case the buffer moved */ i830_update_front_offset(pScrn); + intel_batch_init(pScrn); + if (IS_I965G(pI830)) gen4_render_state_init(pScrn); @@ -3478,6 +3543,9 @@ I830CloseScreen(int scrnIndex, ScreenPtr pScreen) I830LeaveVT(scrnIndex, 0); } + dri_bufmgr_destroy(pI830->bufmgr); + pI830->bufmgr = NULL; + if (pI830->devicesTimer) TimerCancel(pI830->devicesTimer); pI830->devicesTimer = NULL; diff --git a/src/i830_memory.c b/src/i830_memory.c index dc48967f..57e4f2e2 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -350,6 +350,7 @@ i830_reset_allocations(ScrnInfoPtr pScrn) pI830->textures = NULL; #endif pI830->LpRing->mem = NULL; + pI830->fake_bufmgr_mem = NULL; } void @@ -1374,6 +1375,14 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn) return FALSE; } + pI830->fake_bufmgr_mem = i830_allocate_memory(pScrn, "fake bufmgr", + MB(1), GTT_PAGE_SIZE, 0); + if (pI830->fake_bufmgr_mem == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to allocate fake bufmgr space.\n"); + return FALSE; + } + /* even in XAA, 965G needs state mem buffer for rendering */ if (IS_I965G(pI830) && !pI830->noAccel && pI830->gen4_render_state_mem == NULL) diff --git a/src/i830_ring.h b/src/i830_ring.h index c2078fb4..c296d41a 100644 --- a/src/i830_ring.h +++ b/src/i830_ring.h @@ -42,11 +42,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pI830->ring_next &= pI830->LpRing->tail_mask; \ } while (0) -union intfloat { - float f; - unsigned int ui; -}; - #define OUT_RING_F(x) do { \ union intfloat tmp; \ tmp.f = (float)(x); \ diff --git a/src/i915_3d.h b/src/i915_3d.h index 1a0bd45b..d3330e5b 100644 --- a/src/i915_3d.h +++ b/src/i915_3d.h @@ -446,12 +446,12 @@ do { \ #define FS_END() \ do { \ int _i, _pad = (_cur_shader_commands & 0x1) ? 0 : 1; \ - BEGIN_LP_RING(_cur_shader_commands * 3 + 1 + _pad); \ - OUT_RING(_3DSTATE_PIXEL_SHADER_PROGRAM | \ + BEGIN_BATCH(_cur_shader_commands * 3 + 1 + _pad); \ + OUT_BATCH(_3DSTATE_PIXEL_SHADER_PROGRAM | \ (_cur_shader_commands * 3 - 1)); \ for (_i = 0; _i < _cur_shader_commands * 3; _i++) \ - OUT_RING(_shader_buf[_i]); \ + OUT_BATCH(_shader_buf[_i]); \ if (_pad != 0) \ - OUT_RING(MI_NOOP); \ - ADVANCE_LP_RING(); \ + OUT_BATCH(MI_NOOP); \ + ADVANCE_BATCH(); \ } while (0); From 6e94affcc2240e668bcf1aa41f3c8b19929d144b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 6 Jun 2008 14:01:05 -0700 Subject: [PATCH 13/45] Avoid needless flush emits in the blockhandler. The EmitFlush in i830_dri.c was added as a pageflipping workaround, and was noted to not even be sufficient then. There's no reason for it to be there, so it's removed. After that, we just have to not emit an MI_FLUSH if we already had, and cursor movement no longer bashes memory manager. --- src/i830.h | 2 ++ src/i830_batchbuffer.c | 8 ++++++++ src/i830_dri.c | 4 ---- src/i830_driver.c | 8 ++++---- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/i830.h b/src/i830.h index ccf91a04..403cd63d 100644 --- a/src/i830.h +++ b/src/i830.h @@ -463,6 +463,8 @@ typedef struct _I830Rec { #endif #endif + Bool need_mi_flush; + Bool NeedRingBufferLow; Bool allowPageFlip; Bool TripleBuffer; diff --git a/src/i830_batchbuffer.c b/src/i830_batchbuffer.c index 19d642d5..82758a2d 100644 --- a/src/i830_batchbuffer.c +++ b/src/i830_batchbuffer.c @@ -32,10 +32,12 @@ #include #include +#include #include "xf86.h" #include "i830.h" #include "i830_ring.h" +#include "i915_drm.h" static void intel_next_batch(ScrnInfoPtr pScrn) @@ -116,4 +118,10 @@ intel_batch_flush(ScrnInfoPtr pScrn) dri_bo_unreference(pI830->batch_bo); intel_next_batch(pScrn); + + /* Mark that we need to flush whatever potential rendering we've done in the + * blockhandler. We could set this less often, but it's probably not worth + * the work. + */ + pI830->need_mi_flush = TRUE; } diff --git a/src/i830_dri.c b/src/i830_dri.c index 95e1e724..8ec51fcc 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -1067,8 +1067,6 @@ I830DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, pI830->LockHeld = 1; i830_refresh_ring(pScrn); - I830EmitFlush(pScrn); - #ifdef DAMAGE if (!pI830->pDamage && pI830->allowPageFlip) { PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen); @@ -1122,8 +1120,6 @@ I830DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, } #endif - I830EmitFlush(pScrn); - #ifdef DAMAGE /* Try flipping back to the front page if necessary */ if (sPriv && !sPriv->pf_enabled && sPriv->pf_current_page != 0) { diff --git a/src/i830_driver.c b/src/i830_driver.c index 3a9d4252..cb9644ee 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -2496,17 +2496,17 @@ I830BlockHandler(int i, if (pScrn->vtSema && !pI830->noAccel) { /* Emit a flush of the rendering cache, or on the 965 and beyond * rendering results may not hit the framebuffer until significantly - * later. In the direct rendering case this is already done just - * after the page flipping updates, so there's no need to duplicate - * the effort here. + * later. */ - if (!pI830->noAccel && !pI830->directRenderingEnabled) + if (!pI830->noAccel && pI830->need_mi_flush) I830EmitFlush(pScrn); /* Flush the batch, so that any rendering is executed in a timely * fashion. */ intel_batch_flush(pScrn); + + pI830->need_mi_flush = FALSE; } /* From bade7d7d2505a10a8a7d24b084aff9742e2d6d64 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 6 Jun 2008 14:03:25 -0700 Subject: [PATCH 14/45] Use the DRM for submitting batchbuffers when available. There are some concerns with this, as the DRM will be setting the nonsecure flag on the batchbuffer, and the server may be submitting some secure-only commands. It appears to work on the 915GM test system currently. --- src/i830_batchbuffer.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/i830_batchbuffer.c b/src/i830_batchbuffer.c index 82758a2d..976a405c 100644 --- a/src/i830_batchbuffer.c +++ b/src/i830_batchbuffer.c @@ -100,18 +100,35 @@ intel_batch_flush(ScrnInfoPtr pScrn) dri_process_relocs(pI830->batch_bo); - if (!IS_I830(pI830) && !IS_845G(pI830)) { - BEGIN_LP_RING(2); - OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); - OUT_RING(pI830->batch_bo->offset); - ADVANCE_LP_RING(); + if (pI830->directRenderingEnabled) { + struct drm_i915_batchbuffer batch; + int ret; + + batch.start = pI830->batch_bo->offset; + batch.used = pI830->batch_used; + batch.cliprects = NULL; + batch.num_cliprects = 0; + batch.DR1 = 0; + batch.DR4 = 0xffffffff; + + ret = drmCommandWrite(pI830->drmSubFD, DRM_I915_BATCHBUFFER, + &batch, sizeof(batch)); + if (ret != 0) + FatalError("Failed to submit batchbuffer: %s\n", strerror(errno)); } else { - BEGIN_LP_RING(4); - OUT_RING(MI_BATCH_BUFFER); - OUT_RING(pI830->batch_bo->offset); - OUT_RING(pI830->batch_bo->offset + pI830->batch_used - 4); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + if (!IS_I830(pI830) && !IS_845G(pI830)) { + BEGIN_LP_RING(2); + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); + OUT_RING(pI830->batch_bo->offset); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(4); + OUT_RING(MI_BATCH_BUFFER); + OUT_RING(pI830->batch_bo->offset); + OUT_RING(pI830->batch_bo->offset + pI830->batch_used - 4); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } } dri_post_submit(pI830->batch_bo); From ecf19e1cda60a938d41413075ae6e00f24e0ec1a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 6 Jun 2008 15:27:44 -0700 Subject: [PATCH 15/45] Change most usage of pixmap offsets to using a reloc macro. This is based on airlied's RING->BATCH commit. The 965 code still needs to be fixed up for relocations. --- src/i830.h | 5 +++-- src/i830_batchbuffer.h | 13 +++++++++++++ src/i830_exa.c | 18 ++++++------------ src/i830_render.c | 10 ++++------ src/i915_render.c | 16 +++++++--------- src/i915_video.c | 2 +- 6 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/i830.h b/src/i830.h index 403cd63d..96843f04 100644 --- a/src/i830.h +++ b/src/i830.h @@ -690,6 +690,9 @@ typedef struct _I830Rec { #define I830_SELECT_DEPTH 2 #define I830_SELECT_THIRD 3 +unsigned long intel_get_pixmap_offset(PixmapPtr pPix); +unsigned long intel_get_pixmap_pitch(PixmapPtr pPix); + /* Batchbuffer support macros and functions */ #include "i830_batchbuffer.h" @@ -764,8 +767,6 @@ extern Bool I830DRISetHWS(ScrnInfoPtr pScrn); extern Bool I830DRIInstIrqHandler(ScrnInfoPtr pScrn); #endif -unsigned long intel_get_pixmap_offset(PixmapPtr pPix); -unsigned long intel_get_pixmap_pitch(PixmapPtr pPix); extern Bool I830AccelInit(ScreenPtr pScreen); extern void I830SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, diff --git a/src/i830_batchbuffer.h b/src/i830_batchbuffer.h index 91793264..2b898c26 100644 --- a/src/i830_batchbuffer.h +++ b/src/i830_batchbuffer.h @@ -59,8 +59,21 @@ intel_batch_emit_dword(I830Ptr pI830, uint32_t dword) pI830->batch_used += 4; } +static inline void +intel_batch_emit_reloc_pixmap(I830Ptr pI830, PixmapPtr pPixmap, uint32_t delta) +{ + assert(pI830->batch_ptr != NULL); + assert(intel_batch_space(pI830) >= 4); + *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = + intel_get_pixmap_offset(pPixmap) + delta; + pI830->batch_used += 4; +} + #define OUT_BATCH(dword) intel_batch_emit_dword(pI830, dword) +#define OUT_RELOC_PIXMAP(pPixmap, delta) \ + intel_batch_emit_reloc_pixmap(pI830, pPixmap, delta) + union intfloat { float f; unsigned int ui; diff --git a/src/i830_exa.c b/src/i830_exa.c index 2c807c51..75ccd742 100644 --- a/src/i830_exa.c +++ b/src/i830_exa.c @@ -162,7 +162,7 @@ I830EXAPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) { ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); - unsigned long offset, pitch; + unsigned long pitch; if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planemask)) I830FALLBACK("planemask is not solid"); @@ -172,11 +172,8 @@ I830EXAPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) i830_exa_check_pitch_2d(pPixmap); - offset = exaGetPixmapOffset(pPixmap); pitch = exaGetPixmapPitch(pPixmap); - if (offset % pI830->EXADriverPtr->pixmapOffsetAlign != 0) - I830FALLBACK("pixmap offset not aligned"); if (pitch % pI830->EXADriverPtr->pixmapPitchAlign != 0) I830FALLBACK("pixmap pitch not aligned"); @@ -202,10 +199,9 @@ I830EXASolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) { ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); - unsigned long offset, pitch; + unsigned long pitch; uint32_t cmd; - offset = exaGetPixmapOffset(pPixmap); pitch = exaGetPixmapPitch(pPixmap); { @@ -227,7 +223,7 @@ I830EXASolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) OUT_BATCH(pI830->BR[13] | pitch); OUT_BATCH((y1 << 16) | (x1 & 0xffff)); OUT_BATCH((y2 << 16) | (x2 & 0xffff)); - OUT_BATCH(offset); + OUT_RELOC_PIXMAP(pPixmap, 0); OUT_BATCH(pI830->BR[16]); ADVANCE_BATCH(); } @@ -285,14 +281,12 @@ I830EXACopy(PixmapPtr pDstPixmap, int src_x1, int src_y1, int dst_x1, I830Ptr pI830 = I830PTR(pScrn); uint32_t cmd; int dst_x2, dst_y2; - unsigned int dst_off, dst_pitch, src_off, src_pitch; + unsigned int dst_pitch, src_pitch; dst_x2 = dst_x1 + w; dst_y2 = dst_y1 + h; - dst_off = exaGetPixmapOffset(pDstPixmap); dst_pitch = exaGetPixmapPitch(pDstPixmap); - src_off = exaGetPixmapOffset(pI830->pSrcPixmap); src_pitch = exaGetPixmapPitch(pI830->pSrcPixmap); { @@ -322,10 +316,10 @@ I830EXACopy(PixmapPtr pDstPixmap, int src_x1, int src_y1, int dst_x1, OUT_BATCH(pI830->BR[13] | dst_pitch); OUT_BATCH((dst_y1 << 16) | (dst_x1 & 0xffff)); OUT_BATCH((dst_y2 << 16) | (dst_x2 & 0xffff)); - OUT_BATCH(dst_off); + OUT_RELOC_PIXMAP(pDstPixmap, 0); OUT_BATCH((src_y1 << 16) | (src_x1 & 0xffff)); OUT_BATCH(src_pitch); - OUT_BATCH(src_off); + OUT_RELOC_PIXMAP(pI830->pSrcPixmap, 0); ADVANCE_BATCH(); } diff --git a/src/i830_render.c b/src/i830_render.c index 3a959e82..d5cab3f3 100644 --- a/src/i830_render.c +++ b/src/i830_render.c @@ -275,10 +275,9 @@ i830_texture_setup(PicturePtr pPict, PixmapPtr pPix, int unit) ScrnInfoPtr pScrn = xf86Screens[pPict->pDrawable->pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); - uint32_t format, offset, pitch, filter; + uint32_t format, pitch, filter; uint32_t wrap_mode = TEXCOORDMODE_CLAMP_BORDER; - offset = intel_get_pixmap_offset(pPix); pitch = intel_get_pixmap_pitch(pPix); pI830->scale_units[unit][0] = pPix->drawable.width; pI830->scale_units[unit][1] = pPix->drawable.height; @@ -314,7 +313,7 @@ i830_texture_setup(PicturePtr pPict, PixmapPtr pPix, int unit) BEGIN_BATCH(10); OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | LOAD_TEXTURE_MAP(unit) | 4); - OUT_BATCH((offset & TM0S0_ADDRESS_MASK) | TM0S0_USE_FENCE); + OUT_RELOC_PIXMAP(pPix, TM0S0_USE_FENCE); OUT_BATCH(((pPix->drawable.height - 1) << TM0S1_HEIGHT_SHIFT) | ((pPix->drawable.width - 1) << TM0S1_WIDTH_SHIFT) | format); OUT_BATCH((pitch/4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D); @@ -394,7 +393,7 @@ i830_prepare_composite(int op, PicturePtr pSrcPicture, { ScrnInfoPtr pScrn = xf86Screens[pSrcPicture->pDrawable->pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); - uint32_t dst_format, dst_offset, dst_pitch; + uint32_t dst_format, dst_pitch; Bool is_affine_src, is_affine_mask; Bool is_nearest = FALSE; @@ -408,7 +407,6 @@ i830_prepare_composite(int op, PicturePtr pSrcPicture, if (!i830_get_dest_format(pDstPicture, &dst_format)) return FALSE; - dst_offset = intel_get_pixmap_offset(pDst); dst_pitch = intel_get_pixmap_pitch(pDst); if (!i830_texture_setup(pSrcPicture, pSrc, 0)) @@ -446,7 +444,7 @@ i830_prepare_composite(int op, PicturePtr pSrcPicture, OUT_BATCH(_3DSTATE_BUF_INFO_CMD); OUT_BATCH(BUF_3D_ID_COLOR_BACK| BUF_3D_USE_FENCE | BUF_3D_PITCH(dst_pitch)); - OUT_BATCH(BUF_3D_ADDR(dst_offset)); + OUT_RELOC_PIXMAP(pDst, 0); OUT_BATCH(MI_NOOP); OUT_BATCH(_3DSTATE_DST_BUF_VARS_CMD); diff --git a/src/i915_render.c b/src/i915_render.c index 4a02cf54..54197bfd 100644 --- a/src/i915_render.c +++ b/src/i915_render.c @@ -250,11 +250,10 @@ i915_texture_setup(PicturePtr pPict, PixmapPtr pPix, int unit) { ScrnInfoPtr pScrn = xf86Screens[pPict->pDrawable->pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); - uint32_t format, offset, pitch, filter; + uint32_t format, pitch, filter; int w, h, i; uint32_t wrap_mode = TEXCOORDMODE_CLAMP_BORDER; - offset = intel_get_pixmap_offset(pPix); pitch = intel_get_pixmap_pitch(pPix); w = pPict->pDrawable->width; h = pPict->pDrawable->height; @@ -288,7 +287,7 @@ i915_texture_setup(PicturePtr pPict, PixmapPtr pPix, int unit) I830FALLBACK("Bad filter 0x%x\n", pPict->filter); } - pI830->mapstate[unit * 3 + 0] = offset; + pI830->mapstate[unit * 3 + 0] = 0; /* offset filled in at emit time */ pI830->mapstate[unit * 3 + 1] = format | MS3_USE_FENCE_REGS | ((pPix->drawable.height - 1) << MS3_HEIGHT_SHIFT) | @@ -316,7 +315,7 @@ i915_prepare_composite(int op, PicturePtr pSrcPicture, { ScrnInfoPtr pScrn = xf86Screens[pSrcPicture->pDrawable->pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); - uint32_t dst_format, dst_offset, dst_pitch; + uint32_t dst_format, dst_pitch; uint32_t blendctl; int out_reg = FS_OC; FS_LOCALS(20); @@ -333,7 +332,6 @@ i915_prepare_composite(int op, PicturePtr pSrcPicture, if (!i915_get_dest_format(pDstPicture, &dst_format)) return FALSE; - dst_offset = intel_get_pixmap_offset(pDst); dst_pitch = intel_get_pixmap_pitch(pDst); if (!i915_texture_setup(pSrcPicture, pSrc, 0)) @@ -362,7 +360,7 @@ i915_prepare_composite(int op, PicturePtr pSrcPicture, BEGIN_BATCH(10); OUT_BATCH(_3DSTATE_MAP_STATE | 3); OUT_BATCH(0x00000001); /* map 0 */ - OUT_BATCH(pI830->mapstate[0]); + OUT_RELOC_PIXMAP(pSrc, 0); OUT_BATCH(pI830->mapstate[1]); OUT_BATCH(pI830->mapstate[2]); @@ -376,10 +374,10 @@ i915_prepare_composite(int op, PicturePtr pSrcPicture, BEGIN_BATCH(16); OUT_BATCH(_3DSTATE_MAP_STATE | 6); OUT_BATCH(0x00000003); /* map 0,1 */ - OUT_BATCH(pI830->mapstate[0]); + OUT_RELOC_PIXMAP(pSrc, 0); OUT_BATCH(pI830->mapstate[1]); OUT_BATCH(pI830->mapstate[2]); - OUT_BATCH(pI830->mapstate[3]); + OUT_RELOC_PIXMAP(pMask, 0); OUT_BATCH(pI830->mapstate[4]); OUT_BATCH(pI830->mapstate[5]); @@ -400,7 +398,7 @@ i915_prepare_composite(int op, PicturePtr pSrcPicture, OUT_BATCH(_3DSTATE_BUF_INFO_CMD); OUT_BATCH(BUF_3D_ID_COLOR_BACK| BUF_3D_USE_FENCE| BUF_3D_PITCH(dst_pitch)); - OUT_BATCH(BUF_3D_ADDR(dst_offset)); + OUT_RELOC_PIXMAP(pDst, 0); OUT_BATCH(_3DSTATE_DST_BUF_VARS_CMD); OUT_BATCH(dst_format); diff --git a/src/i915_video.c b/src/i915_video.c index aeb37293..e27854ee 100644 --- a/src/i915_video.c +++ b/src/i915_video.c @@ -130,7 +130,7 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id, OUT_BATCH(_3DSTATE_BUF_INFO_CMD); OUT_BATCH(BUF_3D_ID_COLOR_BACK | BUF_3D_USE_FENCE | BUF_3D_PITCH(intel_get_pixmap_pitch(pPixmap))); - OUT_BATCH(BUF_3D_ADDR(intel_get_pixmap_offset(pPixmap))); + OUT_RELOC_PIXMAP(pPixmap, 0); ADVANCE_BATCH(); if (!planar) { From e930c0dc5b5f98d256a4167ed70ba813c88924d2 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Sat, 7 Jun 2008 13:57:59 -0700 Subject: [PATCH 16/45] Use bufmgr_gem when available instead of the fake bufmgr. This is a bit unstable still sometimes. --- src/i830_batchbuffer.c | 69 ++++++++++++++++++++++++++++-------------- src/i830_driver.c | 32 +++++++++++++++----- src/i830_memory.c | 14 +++++---- 3 files changed, 78 insertions(+), 37 deletions(-) diff --git a/src/i830_batchbuffer.c b/src/i830_batchbuffer.c index 976a405c..416f4d05 100644 --- a/src/i830_batchbuffer.c +++ b/src/i830_batchbuffer.c @@ -98,36 +98,59 @@ intel_batch_flush(ScrnInfoPtr pScrn) dri_bo_unmap(pI830->batch_bo); pI830->batch_ptr = NULL; - dri_process_relocs(pI830->batch_bo); - - if (pI830->directRenderingEnabled) { - struct drm_i915_batchbuffer batch; + if (pI830->memory_manager) { + struct drm_i915_gem_execbuffer *exec; int ret; - batch.start = pI830->batch_bo->offset; - batch.used = pI830->batch_used; - batch.cliprects = NULL; - batch.num_cliprects = 0; - batch.DR1 = 0; - batch.DR4 = 0xffffffff; + exec = dri_process_relocs(pI830->batch_bo); - ret = drmCommandWrite(pI830->drmSubFD, DRM_I915_BATCHBUFFER, - &batch, sizeof(batch)); + exec->batch_start_offset = 0; + exec->batch_len = pI830->batch_used; + exec->cliprects_ptr = 0; + exec->num_cliprects = 0; + exec->DR1 = 0; + exec->DR4 = 0xffffffff; + + ret = drmCommandWriteRead(pI830->drmSubFD, DRM_I915_GEM_EXECBUFFER, + exec, sizeof(*exec)); if (ret != 0) FatalError("Failed to submit batchbuffer: %s\n", strerror(errno)); + + i830_refresh_ring(pScrn); } else { - if (!IS_I830(pI830) && !IS_845G(pI830)) { - BEGIN_LP_RING(2); - OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); - OUT_RING(pI830->batch_bo->offset); - ADVANCE_LP_RING(); + dri_process_relocs(pI830->batch_bo); + + if (pI830->directRenderingEnabled) { + struct drm_i915_batchbuffer batch; + int ret; + + batch.start = pI830->batch_bo->offset; + batch.used = pI830->batch_used; + batch.cliprects = NULL; + batch.num_cliprects = 0; + batch.DR1 = 0; + batch.DR4 = 0xffffffff; + + ret = drmCommandWrite(pI830->drmSubFD, DRM_I915_BATCHBUFFER, + &batch, sizeof(batch)); + if (ret != 0) + FatalError("Failed to submit batchbuffer: %s\n", strerror(errno)); + + i830_refresh_ring(pScrn); } else { - BEGIN_LP_RING(4); - OUT_RING(MI_BATCH_BUFFER); - OUT_RING(pI830->batch_bo->offset); - OUT_RING(pI830->batch_bo->offset + pI830->batch_used - 4); - OUT_RING(MI_NOOP); - ADVANCE_LP_RING(); + if (!IS_I830(pI830) && !IS_845G(pI830)) { + BEGIN_LP_RING(2); + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); + OUT_RING(pI830->batch_bo->offset); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(4); + OUT_RING(MI_BATCH_BUFFER); + OUT_RING(pI830->batch_bo->offset); + OUT_RING(pI830->batch_bo->offset + pI830->batch_used - 4); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } } } diff --git a/src/i830_driver.c b/src/i830_driver.c index cb9644ee..bce00af1 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -2750,13 +2750,25 @@ i830_init_bufmgr(ScrnInfoPtr pScrn) I830Ptr pI830 = I830PTR(pScrn); assert(pI830->FbBase != NULL); - pI830->bufmgr = intel_bufmgr_fake_init(pI830->fake_bufmgr_mem->offset, - pI830->FbBase + - pI830->fake_bufmgr_mem->offset, - pI830->fake_bufmgr_mem->size, - i830_fake_fence_emit, - i830_fake_fence_wait, - pScrn); + if (pI830->memory_manager) { + int batch_size; + + batch_size = 4096 * 4; + + /* The 865 has issues with larger-than-page-sized batch buffers. */ + if (IS_I865G(pI830)) + batch_size = 4096; + + pI830->bufmgr = intel_bufmgr_gem_init(pI830->drmSubFD, batch_size); + } else { + pI830->bufmgr = intel_bufmgr_fake_init(pI830->fake_bufmgr_mem->offset, + pI830->FbBase + + pI830->fake_bufmgr_mem->offset, + pI830->fake_bufmgr_mem->size, + i830_fake_fence_emit, + i830_fake_fence_wait, + pScrn); + } } @@ -3338,7 +3350,11 @@ I830LeaveVT(int scrnIndex, int flags) RestoreHWState(pScrn); - intel_bufmgr_fake_evict_all(pI830->bufmgr); + /* Evict everything from the bufmgr, as we're about to lose ownership of + * the graphics memory. + */ + if (!pI830->memory_manager) + intel_bufmgr_fake_evict_all(pI830->bufmgr); intel_batch_teardown(pScrn); i830_stop_ring(pScrn, TRUE); diff --git a/src/i830_memory.c b/src/i830_memory.c index 57e4f2e2..db99d97e 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -1375,12 +1375,14 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn) return FALSE; } - pI830->fake_bufmgr_mem = i830_allocate_memory(pScrn, "fake bufmgr", - MB(1), GTT_PAGE_SIZE, 0); - if (pI830->fake_bufmgr_mem == NULL) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to allocate fake bufmgr space.\n"); - return FALSE; + if (pI830->memory_manager == NULL) { + pI830->fake_bufmgr_mem = i830_allocate_memory(pScrn, "fake bufmgr", + MB(1), GTT_PAGE_SIZE, 0); + if (pI830->fake_bufmgr_mem == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to allocate fake bufmgr space.\n"); + return FALSE; + } } /* even in XAA, 965G needs state mem buffer for rendering */ From 339f00e340c3a9c8ac8f17147e37906494ef370b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 10 Jun 2008 16:14:06 -0700 Subject: [PATCH 17/45] [gem] Don't set up the ring in GEM mode, as that'll be handled by the kernel. --- src/i830_accel.c | 33 +++++++++++++++++++++- src/i830_batchbuffer.c | 2 -- src/i830_dri.c | 63 ++++++++++++++++++++++++++---------------- src/i830_driver.c | 49 ++++++++++++++++++-------------- src/i830_memory.c | 8 ++++-- 5 files changed, 104 insertions(+), 51 deletions(-) diff --git a/src/i830_accel.c b/src/i830_accel.c index a71ea475..c3cd08e0 100644 --- a/src/i830_accel.c +++ b/src/i830_accel.c @@ -54,12 +54,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ +#include + #include "xf86.h" #include "xaarop.h" #include "i830.h" #include "i810_reg.h" #include "i830_debug.h" #include "i830_ring.h" +#include "i915_drm.h" unsigned long intel_get_pixmap_offset(PixmapPtr pPix) @@ -190,7 +193,35 @@ I830Sync(ScrnInfoPtr pScrn) intel_batch_flush(pScrn); - i830_wait_ring_idle(pScrn); + if (pI830->directRenderingEnabled) { + struct drm_i915_irq_emit emit; + struct drm_i915_irq_wait wait; + int ret; + + /* Most of the uses of I830Sync while using GEM should actually be + * using set_domain on a specific buffer. We're not there yet, so fake + * it up using irq_emit/wait. It's still better than spinning on + * register reads for idle. + */ + emit.irq_seq = &wait.irq_seq; + ret = drmCommandWrite(pI830->drmSubFD, DRM_I830_IRQ_EMIT, &emit, + sizeof(emit)); + if (ret != 0) + FatalError("Failure to emit IRQ: %s\n", strerror(-ret)); + + do { + ret = drmCommandWrite(pI830->drmSubFD, DRM_I830_IRQ_WAIT, &wait, + sizeof(wait)); + } while (ret == -EINTR); + + if (ret != 0) + FatalError("Failure to wait for IRQ: %s\n", strerror(-ret)); + + if (!pI830->memory_manager) + i830_refresh_ring(pScrn); + } else { + i830_wait_ring_idle(pScrn); + } pI830->nextColorExpandBuf = 0; } diff --git a/src/i830_batchbuffer.c b/src/i830_batchbuffer.c index 416f4d05..2f53d2ff 100644 --- a/src/i830_batchbuffer.c +++ b/src/i830_batchbuffer.c @@ -115,8 +115,6 @@ intel_batch_flush(ScrnInfoPtr pScrn) exec, sizeof(*exec)); if (ret != 0) FatalError("Failed to submit batchbuffer: %s\n", strerror(errno)); - - i830_refresh_ring(pScrn); } else { dri_process_relocs(pI830->batch_bo); diff --git a/src/i830_dri.c b/src/i830_dri.c index 8ec51fcc..5a536706 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -175,22 +175,31 @@ I830InitDma(ScrnInfoPtr pScrn) memset(&info, 0, sizeof(drmI830Init)); info.func = I830_INIT_DMA; - info.ring_start = ring->mem->offset + pI830->LinearAddr; - info.ring_end = ring->mem->end + pI830->LinearAddr; - info.ring_size = ring->mem->size; + /* Initialize fields that are used in the absence of GEM */ + if (!pI830->memory_manager) { + info.ring_start = ring->mem->offset + pI830->LinearAddr; + info.ring_end = ring->mem->end + pI830->LinearAddr; + info.ring_size = ring->mem->size; + + /* Not used as of the middle of GEM development. */ + info.mmio_offset = (unsigned int)pI830DRI->regs; + + /* Not used as of before GEM development */ + info.front_offset = pI830->front_buffer->offset; + info.back_offset = pI830->back_buffer->offset; + info.depth_offset = pI830->depth_buffer->offset; + info.pitch = pScrn->displayWidth; + info.back_pitch = pScrn->displayWidth; + info.depth_pitch = pScrn->displayWidth; + info.w = pScrn->virtualX; + info.h = pScrn->virtualY; + } - info.mmio_offset = (unsigned int)pI830DRI->regs; info.sarea_priv_offset = sizeof(XF86DRISAREARec); - info.front_offset = pI830->front_buffer->offset; - info.back_offset = pI830->back_buffer->offset; - info.depth_offset = pI830->depth_buffer->offset; - info.w = pScrn->virtualX; - info.h = pScrn->virtualY; - info.pitch = pScrn->displayWidth; - info.back_pitch = pScrn->displayWidth; - info.depth_pitch = pScrn->displayWidth; + /* This should probably have been moved alongside offset/pitch in the sarea. + */ info.cpp = pI830->cpp; if (drmCommandWrite(pI830->drmSubFD, DRM_I830_INIT, @@ -799,17 +808,20 @@ I830DRIDoMappings(ScreenPtr pScreen) xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Registers = 0x%08x\n", (int)pI830DRI->regs); - if (drmAddMap(pI830->drmSubFD, - (drm_handle_t)pI830->LpRing->mem->offset + pI830->LinearAddr, - pI830->LpRing->mem->size, DRM_AGP, 0, - (drmAddress) &pI830->ring_map) < 0) { - xf86DrvMsg(pScreen->myNum, X_ERROR, - "[drm] drmAddMap(ring_map) failed. Disabling DRI\n"); - DRICloseScreen(pScreen); - return FALSE; + if (!pI830->memory_manager) { + if (drmAddMap(pI830->drmSubFD, + (drm_handle_t)pI830->LpRing->mem->offset + + pI830->LinearAddr, + pI830->LpRing->mem->size, DRM_AGP, 0, + (drmAddress) &pI830->ring_map) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] drmAddMap(ring_map) failed. Disabling DRI\n"); + DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] ring buffer = 0x%08x\n", + (int)pI830->ring_map); } - xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] ring buffer = 0x%08x\n", - (int)pI830->ring_map); if (!I830InitDma(pScrn)) { DRICloseScreen(pScreen); @@ -960,6 +972,7 @@ I830DRICloseScreen(ScreenPtr pScreen) xfree(pI830->pVisualConfigs); if (pI830->pVisualConfigsPriv) xfree(pI830->pVisualConfigsPriv); + pI830->directRenderingEnabled = FALSE; } static Bool @@ -1065,7 +1078,8 @@ I830DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, if (!pScrn->vtSema) return; pI830->LockHeld = 1; - i830_refresh_ring(pScrn); + if (!pI830->memory_manager) + i830_refresh_ring(pScrn); #ifdef DAMAGE if (!pI830->pDamage && pI830->allowPageFlip) { @@ -1763,7 +1777,8 @@ I830DRILock(ScrnInfoPtr pScrn) if (pI830->directRenderingEnabled && !pI830->LockHeld) { DRILock(screenInfo.screens[pScrn->scrnIndex], 0); pI830->LockHeld = 1; - i830_refresh_ring(pScrn); + if (!pI830->memory_manager) + i830_refresh_ring(pScrn); return TRUE; } else diff --git a/src/i830_driver.c b/src/i830_driver.c index bce00af1..e7994df6 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -211,6 +211,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include #ifdef XF86DRI_MM #include "xf86mm.h" +#include "i915_drm.h" #endif #endif @@ -3005,7 +3006,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) #endif if (!pI830->noAccel) { - if (pI830->LpRing->mem->size == 0) { + if (pI830->memory_manager == NULL && pI830->LpRing->mem->size == 0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling acceleration because the ring buffer " "allocation failed.\n"); @@ -3357,7 +3358,8 @@ I830LeaveVT(int scrnIndex, int flags) intel_bufmgr_fake_evict_all(pI830->bufmgr); intel_batch_teardown(pScrn); - i830_stop_ring(pScrn, TRUE); + if (!pI830->memory_manager) + i830_stop_ring(pScrn, TRUE); if (pI830->debug_modes) { i830CompareRegsToSnapshot(pScrn, "After LeaveVT"); @@ -3367,15 +3369,16 @@ I830LeaveVT(int scrnIndex, int flags) if (I830IsPrimary(pScrn)) i830_unbind_all_memory(pScrn); - /* Tell the kernel to evict all buffer objects and block new buffer - * allocations until we relese the lock. - */ #ifdef XF86DRI_MM - if (pI830->directRenderingOpen) { - /* XXX: - if (pI830->memory_manager != NULL && pScrn->vtSema) { - drmMMLock(pI830->drmSubFD, DRM_BO_MEM_TT, 1, 0); - }*/ + if (pI830->memory_manager) { + int ret; + + /* Tell the kernel to evict all buffer objects and block GTT usage while + * we're no longer in control of the chip. + */ + ret = drmCommandNone(pI830->drmSubFD, DRM_I915_GEM_LEAVEVT); + if (ret != 0) + FatalError("DRM_I915_LEAVEVT failed: %s\n", strerror(ret)); } #endif /* XF86DRI_MM */ @@ -3409,15 +3412,15 @@ I830EnterVT(int scrnIndex, int flags) pI830->leaving = FALSE; #ifdef XF86DRI_MM - if (pI830->directRenderingEnabled) { - /* Unlock the memory manager first of all so that we can pin our - * buffer objects + if (pI830->memory_manager) { + int ret; + + /* Tell the kernel that we're back in control and ready for GTT + * usage. */ - /* - if (pI830->memory_manager != NULL && pScrn->vtSema) { - drmMMUnlock(pI830->drmSubFD, DRM_BO_MEM_TT, 1); - } - */ + ret = drmCommandNone(pI830->drmSubFD, DRM_I915_GEM_ENTERVT); + if (ret != 0) + FatalError("DRM_I915_ENTERVT failed: %s\n", strerror(ret)); } #endif /* XF86DRI_MM */ @@ -3440,8 +3443,11 @@ I830EnterVT(int scrnIndex, int flags) "Existing errors found in hardware state.\n"); } - i830_stop_ring(pScrn, FALSE); - i830_start_ring(pScrn); + /* Re-set up the ring. */ + if (!pI830->memory_manager) { + i830_stop_ring(pScrn, FALSE); + i830_start_ring(pScrn); + } if (!pI830->SWCursor) I830InitHWCursor(pScrn); @@ -3504,7 +3510,8 @@ I830EnterVT(int scrnIndex, int flags) I830DRIResume(screenInfo.screens[scrnIndex]); - i830_refresh_ring(pScrn); + if (!pI830->memory_manager) + i830_refresh_ring(pScrn); I830Sync(pScrn); sarea->texAge++; diff --git a/src/i830_memory.c b/src/i830_memory.c index db99d97e..36131672 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -996,7 +996,7 @@ i830_allocate_ringbuffer(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); - if (pI830->noAccel || pI830->LpRing->mem != NULL) + if (pI830->noAccel || pI830->memory_manager || pI830->LpRing->mem != NULL) return TRUE; /* We don't have any mechanism in the DRM yet to alert it that we've moved @@ -1632,8 +1632,10 @@ i830_allocate_texture_memory(ScrnInfoPtr pScrn) size / 1024); return FALSE; } - /* The offset must stay constant currently because we don't ever update - * the DRI maps after screen init. + /* Now that the DRM uses the sarea to get the offsets of the buffers, + * and we update the classic DRM mappings and the sarea contents on + * changes, the NEED_LIFETIME_FIXED is no longer true and should be + * made conditional on DRM version. */ pI830->textures = i830_allocate_memory(pScrn, "classic textures", size, GTT_PAGE_SIZE, From 754df0aa55c4b5f0c3c415ad97d7612504410229 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 11 Jun 2008 14:43:38 -0700 Subject: [PATCH 18/45] [gem] Chase move of create ioctl from generic to device-specific. --- src/i830_memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i830_memory.c b/src/i830_memory.c index 36131672..d1a3e58d 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -734,7 +734,7 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, I830Ptr pI830 = I830PTR(pScrn); i830_memory *mem; int ret; - struct drm_gem_create create; + struct drm_i915_gem_create create; assert((flags & NEED_PHYSICAL_ADDR) == 0); @@ -755,7 +755,7 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, memset(&create, 0, sizeof(create)); create.size = size; - ret = ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_CREATE, &create); + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_CREATE, &create); if (ret) { xfree(mem->name); xfree(mem); From f07acbdaac95931d184ea2c557edb632e577eb47 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 12 Jun 2008 13:47:35 -0700 Subject: [PATCH 19/45] Require libdrm 2.4.0 always since we need the bufmgr code. This lets us remove a lot of conditional compile stuff in the DRI case, as if we're doing DRI and have 2.4.0, we can rely on GEM ioctls existing. --- configure.ac | 25 ++----------------------- src/Makefile.am | 6 +++--- src/i830.h | 5 ----- src/i830_dri.c | 17 ----------------- src/i830_driver.c | 17 +++++++---------- src/i830_memory.c | 38 ++++++++++++++------------------------ src/xvmc/Makefile.am | 5 +++-- 7 files changed, 29 insertions(+), 84 deletions(-) diff --git a/configure.ac b/configure.ac index 898c70b8..e62502c5 100644 --- a/configure.ac +++ b/configure.ac @@ -196,36 +196,15 @@ if test "x$GCC" = "xyes"; then -Wnested-externs -fno-strict-aliasing" fi +PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.0]) AM_CONDITIONAL(DRI, test x$DRI = xyes) if test "$DRI" = yes; then - PKG_CHECK_MODULES(DRI, [libdrm xf86driproto glproto]) + PKG_CHECK_MODULES(DRI, [xf86driproto glproto]) AC_DEFINE(XF86DRI,1,[Enable DRI driver support]) AC_DEFINE(XF86DRI_DEVEL,1,[Enable developmental DRI driver support]) - PKG_CHECK_MODULES(DRI_MM, [libdrm >= 2.3.1],[DRI_MM=yes], [DRI_MM=no]) - if test "x$DRI_MM" = xyes; then - AC_DEFINE(XF86DRI_MM,1,[Extended DRI memory management]) - fi if test "$have_damage_h" = yes; then AC_DEFINE(DAMAGE,1,[Use Damage extension]) fi - - save_CFLAGS="$CFLAGS" - CFLAGS="$XORG_CFLAGS $DRI_CFLAGS" - AC_CHECK_TYPE(drm_i915_flip_t, - [AC_DEFINE(HAVE_I915_FLIP, 1, - [Have drm_i915_flip_t and related definitions])], - [], [ -#include -#include -]) - AC_CHECK_DECL(DRM_IOCTL_GEM_CREATE, - [AC_DEFINE(HAVE_DRM_GEM, 1, - [Have DRM Graphics Execution Manager])], - [], [ -#include -#include -]) - CFLAGS="$save_CFLAGS" fi AM_CONDITIONAL(VIDEO_DEBUG, test x$VIDEO_DEBUG = xyes) diff --git a/src/Makefile.am b/src/Makefile.am index 7ab1f086..6b812f94 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,7 +30,8 @@ SUBDIRS = xvmc bios_reader ch7017 ch7xxx ivch sil164 tfp410 $(REGDUMPER) # _ladir passes a dummy rpath to libtool so the thing will actually link # TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. -AM_CFLAGS = @WARN_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ @PCIACCESS_CFLAGS@ \ +AM_CFLAGS = @WARN_CFLAGS@ @XORG_CFLAGS@ @DRM_CFLAGS@ @DRI_CFLAGS@ \ + @PCIACCESS_CFLAGS@ \ @XMODES_CFLAGS@ -DI830_XV -DI830_USE_XAA -DI830_USE_EXA intel_drv_la_LTLIBRARIES = intel_drv.la @@ -151,7 +152,6 @@ INTEL_G4I = \ exa_wm.g4i \ exa_wm_affine.g4i \ exa_wm_projective.g4i - INTEL_G4B = \ packed_yuv_sf.g4b \ @@ -173,7 +173,7 @@ INTEL_G4B = \ exa_wm_ca_srcalpha.g4b \ exa_wm_write.g4b \ exa_wm_xy.g4b - + EXTRA_DIST = \ $(XMODE_SRCS) \ $(INTEL_G4A) \ diff --git a/src/i830.h b/src/i830.h index 96843f04..5c6fa820 100644 --- a/src/i830.h +++ b/src/i830.h @@ -69,9 +69,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifdef XF86DRI #include "xf86drm.h" -#ifdef XF86DRI_MM -#include "xf86mm.h" -#endif #include "sarea.h" #define _XF86DRI_SERVER_ #include "dri.h" @@ -195,12 +192,10 @@ struct _i830_memory { i830_memory *prev; /** @} */ -#ifdef XF86DRI_MM uint32_t gem_handle; uint32_t alignment; uint32_t gem_name; Bool lifetime_fixed_offset; -#endif }; typedef struct { diff --git a/src/i830_dri.c b/src/i830_dri.c index 5a536706..85b07090 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -86,23 +86,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "i915_drm.h" -/* This block and the corresponding configure test can be removed when - * libdrm >= 2.3.1 is required. - */ -#ifndef HAVE_I915_FLIP - -#define DRM_VBLANK_FLIP 0x8000000 - -typedef struct drm_i915_flip { - int pipes; -} drm_i915_flip_t; - -#undef DRM_IOCTL_I915_FLIP -#define DRM_IOCTL_I915_FLIP DRM_IOW(DRM_COMMAND_BASE + DRM_I915_FLIP, \ - drm_i915_flip_t) - -#endif - #include "dristruct.h" static Bool I830InitVisualConfigs(ScreenPtr pScreen); diff --git a/src/i830_driver.c b/src/i830_driver.c index e7994df6..580cbbc0 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -209,11 +209,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #ifdef XF86DRI #include "dri.h" #include -#ifdef XF86DRI_MM -#include "xf86mm.h" #include "i915_drm.h" #endif -#endif #ifdef I830_USE_EXA const char *I830exaSymbols[] = { @@ -303,7 +300,7 @@ typedef enum { OPTION_LVDS24BITMODE, OPTION_FBC, OPTION_TILING, -#ifdef XF86DRI_MM +#ifdef XF86DRI OPTION_INTELTEXPOOL, #endif OPTION_LVDSFIXEDMODE, @@ -331,7 +328,7 @@ static OptionInfoRec I830Options[] = { {OPTION_LVDS24BITMODE, "LVDS24Bit", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_FBC, "FramebufferCompression", OPTV_BOOLEAN, {0}, TRUE}, {OPTION_TILING, "Tiling", OPTV_BOOLEAN, {0}, TRUE}, -#ifdef XF86DRI_MM +#ifdef XF86DRI {OPTION_INTELTEXPOOL,"Legacy3D", OPTV_BOOLEAN, {0}, FALSE}, #endif {OPTION_LVDSFIXEDMODE, "LVDSFixedMode", OPTV_BOOLEAN, {0}, FALSE}, @@ -1573,7 +1570,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) from = X_PROBED; -#ifdef XF86DRI_MM +#ifdef XF86DRI if (!IS_I965G(pI830)) { Bool tmp; @@ -3369,7 +3366,7 @@ I830LeaveVT(int scrnIndex, int flags) if (I830IsPrimary(pScrn)) i830_unbind_all_memory(pScrn); -#ifdef XF86DRI_MM +#ifdef XF86DRI if (pI830->memory_manager) { int ret; @@ -3380,7 +3377,7 @@ I830LeaveVT(int scrnIndex, int flags) if (ret != 0) FatalError("DRM_I915_LEAVEVT failed: %s\n", strerror(ret)); } -#endif /* XF86DRI_MM */ +#endif /* XF86DRI */ if (IS_I965G(pI830)) gen4_render_state_cleanup(pScrn); @@ -3411,7 +3408,7 @@ I830EnterVT(int scrnIndex, int flags) pI830->leaving = FALSE; -#ifdef XF86DRI_MM +#ifdef XF86DRI if (pI830->memory_manager) { int ret; @@ -3422,7 +3419,7 @@ I830EnterVT(int scrnIndex, int flags) if (ret != 0) FatalError("DRM_I915_ENTERVT failed: %s\n", strerror(ret)); } -#endif /* XF86DRI_MM */ +#endif /* XF86DRI */ if (I830IsPrimary(pScrn)) if (!i830_bind_all_memory(pScrn)) diff --git a/src/i830_memory.c b/src/i830_memory.c index d1a3e58d..c3576217 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -108,7 +108,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "i830.h" #include "i810_reg.h" -#ifdef XF86DRI_MM +#ifdef XF86DRI #include "i915_drm.h" #endif @@ -165,7 +165,7 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem) if (mem == NULL || mem->bound) return TRUE; -#if HAVE_DRM_GEM +#ifdef XF86DRI if (mem->gem_handle != 0) { I830Ptr pI830 = I830PTR(pScrn); struct drm_i915_gem_pin pin; @@ -218,7 +218,7 @@ i830_unbind_memory(ScrnInfoPtr pScrn, i830_memory *mem) if (mem->tiling != TILE_NONE) i830_clear_tiling(pScrn, mem->fence_nr); -#if HAVE_DRM_GEM +#ifdef XF86DRI if (mem->gem_handle != 0) { I830Ptr pI830 = I830PTR(pScrn); struct drm_i915_gem_unpin unpin; @@ -256,7 +256,7 @@ i830_free_memory(ScrnInfoPtr pScrn, i830_memory *mem) /* Free any AGP memory. */ i830_unbind_memory(pScrn, mem); -#if HAVE_DRM_GEM +#ifdef XF86DRI if (mem->gem_handle != 0) { I830Ptr pI830 = I830PTR(pScrn); struct drm_gem_close close; @@ -319,12 +319,10 @@ i830_reset_allocations(ScrnInfoPtr pScrn) } /* Free any allocations in buffer objects */ -#ifdef XF86DRI_MM if (pI830->memory_manager) { while (pI830->bo_list != NULL) i830_free_memory(pScrn, pI830->bo_list); } -#endif /* Null out the pointers for all the allocations we just freed. This is * kind of gross, but at least it's just one place now. @@ -375,7 +373,7 @@ i830_free_3d_memory(ScrnInfoPtr pScrn) * given range. * * This sets up the kernel memory manager to manage as much of the memory - * as we think it can, while leaving enough to us to fulfill our non-TTM + * as we think it can, while leaving enough to us to fulfill our non-GEM * static allocations. Some of these exist because of the need for physical * addresses to reference. */ @@ -384,7 +382,7 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) { I830Ptr pI830 = I830PTR(pScrn); i830_memory *start, *end; -#if HAVE_DRM_GEM +#ifdef XF86DRI int dri_major, dri_minor, dri_patch; #endif @@ -423,7 +421,7 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) pI830->memory_list = start; -#if HAVE_DRM_GEM +#ifdef XF86DRI DRIQueryVersion(&dri_major, &dri_minor, &dri_patch); /* Now that we have our manager set up, initialize the kernel MM if @@ -461,7 +459,7 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) } if (pI830->fb_compression) mmsize -= MB(6) + ROUND_TO_PAGE(FBC_LL_SIZE + FBC_LL_PAD); - /* Can't do TTM on stolen memory */ + /* Can't do GEM on stolen memory */ mmsize -= pI830->stolen_size; if (HWS_NEED_GFX(pI830) && IS_IGD_GM(pI830)) @@ -496,7 +494,7 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) pI830->memory_manager = NULL; } } -#endif /* XF86DRI_MM */ +#endif /* XF86DRI */ return TRUE; } @@ -509,14 +507,12 @@ i830_allocator_fini(ScrnInfoPtr pScrn) /* Free most of the allocations */ i830_reset_allocations(pScrn); -#ifdef XF86DRI_MM /* The memory manager is more special */ if (pI830->memory_manager) { /* XXX drmMMTakedown(pI830->drmSubFD, DRM_BO_MEM_TT);*/ i830_free_memory(pScrn, pI830->memory_manager); pI830->memory_manager = NULL; } -#endif /* XF86DRI_MM */ /* Free the start/end markers */ free(pI830->memory_list->next); @@ -726,7 +722,7 @@ i830_allocate_agp_memory(ScrnInfoPtr pScrn, i830_memory *mem, int flags) return TRUE; } -#if HAVE_DRM_GEM +#ifdef XF86DRI static i830_memory * i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, unsigned long size, unsigned long align, int flags) @@ -794,7 +790,7 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, return mem; } -#endif /* XF86DRI_MM */ +#endif /* XF86DRI */ /* Allocates video memory at the given size and alignment. * @@ -820,7 +816,7 @@ i830_allocate_memory(ScrnInfoPtr pScrn, const char *name, { i830_memory *mem; -#if HAVE_DRM_GEM +#ifdef XF86DRI I830Ptr pI830 = I830PTR(pScrn); if (pI830->memory_manager && !(flags & NEED_PHYSICAL_ADDR) && @@ -828,7 +824,7 @@ i830_allocate_memory(ScrnInfoPtr pScrn, const char *name, { return i830_allocate_memory_bo(pScrn, name, size, alignment, flags); } else -#endif +#endif /* XF86DRI */ { mem = i830_allocate_aperture(pScrn, name, size, alignment, flags); if (mem == NULL) @@ -958,7 +954,6 @@ i830_describe_allocations(ScrnInfoPtr pScrn, int verbosity, const char *prefix) "%s0x%08lx: end of aperture\n", prefix, pI830->FbMapSize); -#ifdef XF86DRI_MM if (pI830->memory_manager) { xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verbosity, "%sBO memory allocation layout:\n", prefix); @@ -988,7 +983,6 @@ i830_describe_allocations(ScrnInfoPtr pScrn, int verbosity, const char *prefix) "%s0x%08lx: end of memory manager\n", prefix, pI830->memory_manager->end); } -#endif /* XF86DRI_MM */ } static Bool @@ -1455,7 +1449,7 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn) if (!pI830->noAccel && !pI830->useEXA) { /* The lifetime fixed offset of xaa scratch is probably not required, * but we do some setup using it at XAAInit() time. And XAA may not - * end up being supported with TTM anyway. + * end up being supported with GEM anyway. */ pI830->xaa_scratch = i830_allocate_memory(pScrn, "xaa scratch", MAX_SCRATCH_BUFFER_SIZE, @@ -1967,12 +1961,10 @@ i830_bind_all_memory(ScrnInfoPtr pScrn) FatalError("Couldn't bind memory for %s\n", mem->name); } } -#ifdef XF86DRI_MM for (mem = pI830->bo_list; mem != NULL; mem = mem->next) { if (!mem->lifetime_fixed_offset && !i830_bind_memory(pScrn, mem)) FatalError("Couldn't bind memory for BO %s\n", mem->name); } -#endif } if (!pI830->SWCursor) i830_update_cursor_offsets(pScrn); @@ -1997,7 +1989,6 @@ i830_unbind_all_memory(ScrnInfoPtr pScrn) { i830_unbind_memory(pScrn, mem); } -#ifdef XF86DRI_MM for (mem = pI830->bo_list; mem != NULL; mem = mem->next) { /* Don't unpin objects which require that their offsets never * change. @@ -2005,7 +1996,6 @@ i830_unbind_all_memory(ScrnInfoPtr pScrn) if (!mem->lifetime_fixed_offset) i830_unbind_memory(pScrn, mem); } -#endif pI830->gtt_acquired = FALSE; diff --git a/src/xvmc/Makefile.am b/src/xvmc/Makefile.am index 345160fb..2f75cc56 100644 --- a/src/xvmc/Makefile.am +++ b/src/xvmc/Makefile.am @@ -4,7 +4,7 @@ lib_LTLIBRARIES=libI810XvMC.la libIntelXvMC.la libI810XvMC_la_SOURCES = I810XvMC.c \ I810XvMC.h -libI810XvMC_la_CFLAGS = @WARN_CFLAGS@ @XORG_CFLAGS@ @DRI_CFLAGS@ \ +libI810XvMC_la_CFLAGS = @WARN_CFLAGS@ @XORG_CFLAGS@ @DRM_CFLAGS@ @DRI_CFLAGS@ \ -I$(top_srcdir)/src -DTRUE=1 -DFALSE=0 libI810XvMC_la_LDFLAGS = -version-number 1:0:0 libI810XvMC_la_LIBADD = @DRI_LIBS@ @@ -22,7 +22,8 @@ libIntelXvMC_la_SOURCES = intel_xvmc.c \ xf86dri.h \ xf86dristr.h -libIntelXvMC_la_CFLAGS = @XORG_CFLAGS@ @DRI_CFLAGS@ @XVMCLIB_CFLAGS@ -I$(top_srcdir)/src -DTRUE=1 -DFALSE=0 +libIntelXvMC_la_CFLAGS = @XORG_CFLAGS@ @DRM_CFLAGS@ @DRI_CFLAGS@ \ + @XVMCLIB_CFLAGS@ -I$(top_srcdir)/src -DTRUE=1 -DFALSE=0 libIntelXvMC_la_LDFLAGS = -version-number 1:0:0 libIntelXvMC_la_LIBADD = @DRI_LIBS@ endif From 02d7141ac395446613edba0f2e2a951e750e4e9f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 13 Jun 2008 11:30:58 +1000 Subject: [PATCH 20/45] [gem] remove one more unused bit --- src/i830_dri.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/i830_dri.c b/src/i830_dri.c index 85b07090..2f3c5d39 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -1505,7 +1505,6 @@ I830DRIClipNotify(ScreenPtr pScreen, WindowPtr *ppWin, int num) static int i830_name_buffer (ScrnInfoPtr pScrn, i830_memory *mem) { -#if HAVE_DRM_GEM if (mem && mem->gem_handle) { I830Ptr pI830 = I830PTR(pScrn); @@ -1526,7 +1525,6 @@ i830_name_buffer (ScrnInfoPtr pScrn, i830_memory *mem) } return mem->gem_name; } -#endif return -1; } From d775ddc64dc8349b8ef9e85b0be9e93cb1997fea Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 13 Jun 2008 10:03:24 -0700 Subject: [PATCH 21/45] [gem] Catch -EINTR from blocking GEM ioctl and restart. --- src/i830_batchbuffer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/i830_batchbuffer.c b/src/i830_batchbuffer.c index 2f53d2ff..07ea0825 100644 --- a/src/i830_batchbuffer.c +++ b/src/i830_batchbuffer.c @@ -111,8 +111,10 @@ intel_batch_flush(ScrnInfoPtr pScrn) exec->DR1 = 0; exec->DR4 = 0xffffffff; - ret = drmCommandWriteRead(pI830->drmSubFD, DRM_I915_GEM_EXECBUFFER, - exec, sizeof(*exec)); + do { + ret = drmCommandWriteRead(pI830->drmSubFD, DRM_I915_GEM_EXECBUFFER, + exec, sizeof(*exec)); + } while (ret == -EINTR); if (ret != 0) FatalError("Failed to submit batchbuffer: %s\n", strerror(errno)); } else { From 2f8a0aa8cd24ede824aa52102b45a295f1b6b5be Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 20 May 2008 20:29:25 -0700 Subject: [PATCH 22/45] Remove some unreliable regs for i915 --- src/reg_dumper/idle.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/reg_dumper/idle.c b/src/reg_dumper/idle.c index 46a2fd5c..dbfa58e6 100644 --- a/src/reg_dumper/idle.c +++ b/src/reg_dumper/idle.c @@ -43,11 +43,13 @@ struct idle_flags { }; struct idle_flags i915_idle_flags[] = { +#if 0 {IDCT_DONE, "IDCT"}, {IQ_DONE, "IQ"}, {PR_DONE, "PR"}, {VLD_DONE, "VLD"}, {IP_DONE, "IP"}, +#endif {FBC_DONE, "FBC"}, {BINNER_DONE, "BINNER"}, {SF_DONE, "SF"}, @@ -66,7 +68,9 @@ struct idle_flags i915_idle_flags[] = { {PS_DONE, "PS"}, {CC_DONE, "CC"}, {MAP_FILTER_DONE, "map filter"}, +#if 0 {MAP_L2_IDLE, "map L2"}, +#endif {0, "total"}, {0, "other"}, @@ -105,8 +109,8 @@ setup_other_flags(I830Ptr pI830, other_idle_flags &= ~idle_flags[i].instdone_flag; total_idle_flags |= idle_flags[i].instdone_flag; } - idle_flags[i - 1].instdone_flag = total_idle_flags; - idle_flags[i].instdone_flag = other_idle_flags; + idle_flags[idle_flag_count - 2].instdone_flag = total_idle_flags; + idle_flags[idle_flag_count - 1].instdone_flag = other_idle_flags; } int main(int argc, char **argv) From 9d7929436488969ca4fd1fef4d2e92be5e1a93aa Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 20 Jun 2008 00:23:45 -0700 Subject: [PATCH 23/45] Flush pending batch in block handler Make sure any pending rendering commands are delivered to the hardware before the server goes to sleep. --- src/i830_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i830_driver.c b/src/i830_driver.c index 580cbbc0..5525aec4 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -2496,7 +2496,7 @@ I830BlockHandler(int i, * rendering results may not hit the framebuffer until significantly * later. */ - if (!pI830->noAccel && pI830->need_mi_flush) + if (!pI830->noAccel && (pI830->need_mi_flush || pI830->batch_used)) I830EmitFlush(pScrn); /* Flush the batch, so that any rendering is executed in a timely From e9916b9d496fd0b4df717892dda33f81a2e2990a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 11 Jul 2008 18:59:05 -0700 Subject: [PATCH 24/45] Set tiling state for buffers allocated using GEM. --- src/i830_memory.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/i830_memory.c b/src/i830_memory.c index c3576217..3d6e245f 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -901,6 +901,31 @@ i830_allocate_memory_tiled(ScrnInfoPtr pScrn, const char *name, mem->pitch = pitch; mem->fence_nr = -1; +#ifdef XF86DRI + if (mem->gem_handle != 0) { + struct drm_i915_gem_set_tiling set_tiling; + int ret; + + set_tiling.handle = mem->gem_handle; + if (tile_format == TILE_XMAJOR) + set_tiling.tiling_mode = I915_TILING_X; + else + set_tiling.tiling_mode = I915_TILING_Y; + + ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_SET_TILING, + &set_tiling); + if (ret != 0 || set_tiling.tiling_mode == I915_TILING_NONE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to set tiling on %s: %s\n", + mem->name, strerror(errno)); + i830_free_memory(pScrn, mem); + return i830_allocate_memory(pScrn, name, size, alignment, + flags); + return FALSE; + } + } +#endif + return mem; } From f4ab1f6ad47b8f9a33d45b35c1cb2ba9610b96a6 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 18 Jul 2008 14:31:45 -0700 Subject: [PATCH 25/45] Add intel_statuspage to .gitignore --- src/reg_dumper/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/src/reg_dumper/.gitignore b/src/reg_dumper/.gitignore index b0f9b6f2..0adc8b25 100644 --- a/src/reg_dumper/.gitignore +++ b/src/reg_dumper/.gitignore @@ -2,3 +2,4 @@ intel_hotplug intel_idle intel_reg_dumper intel_stepping +intel_statuspage From 286ff63f83db8ea16514512385e6f8c6875871ef Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 17 Jul 2008 17:06:28 -0700 Subject: [PATCH 26/45] Don't set up the HWS page in GEM mode now that the kernel manages it. --- src/i830_driver.c | 2 +- src/i830_memory.c | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/i830_driver.c b/src/i830_driver.c index 03861a91..dcbaa040 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -3477,7 +3477,7 @@ I830EnterVT(int scrnIndex, int flags) * operation which accessing that page, like irq install, etc. */ if (pI830->starting) { - if (HWS_NEED_GFX(pI830) && !I830DRISetHWS(pScrn)) { + if (pI830->hw_status != NULL && !I830DRISetHWS(pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Fail to setup hardware status page.\n"); I830DRICloseScreen(pScrn->pScreen); diff --git a/src/i830_memory.c b/src/i830_memory.c index 08a22019..222882cd 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -462,10 +462,6 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) /* Can't do GEM on stolen memory */ mmsize -= pI830->stolen_size; - /* new chipsets need non-stolen status page */ - if (HWS_NEED_GFX(pI830) && HWS_NEED_NONSTOLEN(pI830)) - mmsize -= HWSTATUS_PAGE_SIZE; - /* Create the aperture allocation */ pI830->memory_manager = i830_allocate_aperture(pScrn, "DRI memory manager", @@ -1717,7 +1713,7 @@ i830_allocate_3d_memory(ScrnInfoPtr pScrn) DPRINTF(PFX, "i830_allocate_3d_memory\n"); - if (HWS_NEED_GFX(pI830)) { + if (!pI830->memory_manager && HWS_NEED_GFX(pI830)) { if (!i830_allocate_hwstatus(pScrn)) return FALSE; } From d77d42e543ee82e801a8563a911826521c0ba557 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Sat, 26 Jul 2008 16:10:05 -0700 Subject: [PATCH 27/45] intel-gem: Give a better error message if the kernel rejects the tiling mode. --- src/i830_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i830_memory.c b/src/i830_memory.c index 222882cd..2e238e25 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -914,7 +914,8 @@ i830_allocate_memory_tiled(ScrnInfoPtr pScrn, const char *name, if (ret != 0 || set_tiling.tiling_mode == I915_TILING_NONE) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set tiling on %s: %s\n", - mem->name, strerror(errno)); + mem->name, + ret == 0 ? "rejected by kernel" : strerror(errno)); i830_free_memory(pScrn, mem); return i830_allocate_memory(pScrn, name, size, alignment, flags); From e9e6b4738573ffa3822ae68088bd53a645eedbce Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 30 Jul 2008 14:15:57 -0700 Subject: [PATCH 28/45] intel-gem: Use new getparam to detect kernel GEM support. --- src/i830_memory.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/i830_memory.c b/src/i830_memory.c index 2e238e25..b62bda05 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -384,6 +384,8 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) i830_memory *start, *end; #ifdef XF86DRI int dri_major, dri_minor, dri_patch; + struct drm_i915_getparam gp; + int has_gem; #endif start = xcalloc(1, sizeof(*start)); @@ -424,12 +426,19 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) #ifdef XF86DRI DRIQueryVersion(&dri_major, &dri_minor, &dri_patch); + has_gem = 0; + gp.param = I915_PARAM_HAS_GEM; + gp.value = &has_gem; + + (void)drmCommandWriteRead(pI830->drmSubFD, DRM_I915_GETPARAM, + &gp, sizeof(gp)); + /* Now that we have our manager set up, initialize the kernel MM if * possible, covering almost all of the aperture. We need libdri interface * 5.4 or newer so we can rely on the lock being held after DRIScreenInit, * rather than after DRIFinishScreenInit. */ - if (pI830->directRenderingEnabled && pI830->drmMinor >= 7 && + if (pI830->directRenderingEnabled && has_gem && (dri_major > 5 || (dri_major == 5 && dri_minor >= 4))) { int mmsize; From e5fab0b7681be06a5a3be4bbd769ba5c435e2128 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 25 Jul 2008 13:44:29 -0700 Subject: [PATCH 29/45] Add OUT_RELOC macro and backing intel_batch_emit_reloc function --- src/i830_batchbuffer.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/i830_batchbuffer.h b/src/i830_batchbuffer.h index 2b898c26..c9b84215 100644 --- a/src/i830_batchbuffer.h +++ b/src/i830_batchbuffer.h @@ -59,6 +59,20 @@ intel_batch_emit_dword(I830Ptr pI830, uint32_t dword) pI830->batch_used += 4; } +static inline void +intel_batch_emit_reloc (I830Ptr pI830, + dri_bo *bo, + uint32_t read_domains, + uint32_t write_domains, + uint32_t delta) +{ + assert(intel_batch_space(pI830) >= 4); + *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = bo->offset + delta; + intel_bo_emit_reloc (pI830->batch_bo, read_domains, write_domains, delta, + pI830->batch_used, bo); + pI830->batch_used += 4; +} + static inline void intel_batch_emit_reloc_pixmap(I830Ptr pI830, PixmapPtr pPixmap, uint32_t delta) { @@ -71,6 +85,9 @@ intel_batch_emit_reloc_pixmap(I830Ptr pI830, PixmapPtr pPixmap, uint32_t delta) #define OUT_BATCH(dword) intel_batch_emit_dword(pI830, dword) +#define OUT_RELOC(bo, read_domains, write_domains, delta) \ + intel_batch_emit_reloc (pI830, bo, read_domains, write_domains, delta) + #define OUT_RELOC_PIXMAP(pPixmap, delta) \ intel_batch_emit_reloc_pixmap(pI830, pPixmap, delta) From 1abf4d3a7a203ff5d6e5ceda29573e7fd69ddf8e Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 25 Jul 2008 14:48:45 -0700 Subject: [PATCH 30/45] Switch to using a buffer object for the vertex buffer --- src/i965_render.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/i965_render.c b/src/i965_render.c index 1cbfe242..93e28882 100644 --- a/src/i965_render.c +++ b/src/i965_render.c @@ -37,6 +37,7 @@ #include "xf86.h" #include "i830.h" #include "i915_reg.h" +#include "i915_drm.h" /* bring in brw structs */ #include "brw_defines.h" @@ -60,7 +61,7 @@ do { \ #endif #define MAX_VERTEX_PER_COMPOSITE 24 -#define MAX_VERTEX_BUFFERS 256 +#define VERTEX_BUFFER_SIZE (16 * MAX_VERTEX_PER_COMPOSITE) struct blendinfo { Bool dst_alpha; @@ -502,14 +503,14 @@ typedef struct _gen4_state { [BRW_BLENDFACTOR_COUNT]; struct brw_cc_viewport cc_viewport; PAD64 (brw_cc_viewport, 0); - - float vb[MAX_VERTEX_PER_COMPOSITE * MAX_VERTEX_BUFFERS]; } gen4_state_t; /** Private data for gen4 render accel implementation. */ struct gen4_render_state { gen4_state_t *card_state; uint32_t card_state_offset; + dri_bo *vb_bo; + int vb_bo_busy; int binding_table_index; int surface_state_index; @@ -1270,12 +1271,11 @@ i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, { ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); - gen4_state_t *card_state = pI830->gen4_render_state->card_state; struct gen4_render_state *render_state = pI830->gen4_render_state; Bool has_mask; Bool is_affine_src, is_affine_mask, is_affine; float src_x[3], src_y[3], src_w[3], mask_x[3], mask_y[3], mask_w[3]; - float *vb = card_state->vb; + float *vb; int i; is_affine_src = i830_transform_is_affine (pI830->transform[0]); @@ -1352,11 +1352,25 @@ i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, } } - if (render_state->vb_offset + MAX_VERTEX_PER_COMPOSITE >= ARRAY_SIZE(card_state->vb)) { - i830WaitSync(pScrn); + /* Arrange for a buffer object with sufficient space for our + * vertices, and that isn't "busy", that is, it is not already + * referenced by a batch that has been flushed. */ + if (! render_state->vb_bo || render_state->vb_bo_busy || + render_state->vb_offset + MAX_VERTEX_PER_COMPOSITE > VERTEX_BUFFER_SIZE) + { + if (render_state->vb_bo) + dri_bo_unreference (render_state->vb_bo); + + render_state->vb_bo = dri_bo_alloc (pI830->bufmgr, "vb", + VERTEX_BUFFER_SIZE * sizeof (float), + 4096); render_state->vb_offset = 0; } + /* Map the vertex buffer object so we can write to it. */ + dri_bo_map (render_state->vb_bo, 1); + vb = render_state->vb_bo->virtual; + i = render_state->vb_offset; /* rect (x2,y2) */ vb[i++] = (float)(dstX + w); @@ -1399,7 +1413,9 @@ i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, if (!is_affine) vb[i++] = mask_w[0]; } - assert (i * 4 <= sizeof(card_state->vb)); + assert (i <= VERTEX_BUFFER_SIZE); + + dri_bo_unmap (render_state->vb_bo); BEGIN_BATCH(12); OUT_BATCH(MI_FLUSH); @@ -1408,7 +1424,7 @@ i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, OUT_BATCH((0 << VB0_BUFFER_INDEX_SHIFT) | VB0_VERTEXDATA | (render_state->vertex_size << VB0_BUFFER_PITCH_SHIFT)); - OUT_BATCH(render_state->card_state_offset + offsetof(gen4_state_t, vb) + + OUT_RELOC(render_state->vb_bo, I915_GEM_DOMAIN_VERTEX, 0, render_state->vb_offset * 4); OUT_BATCH(3); OUT_BATCH(0); // ignore for VERTEXDATA, but still there @@ -1446,11 +1462,6 @@ i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, OUT_BATCH(0); /* Immediate data high DW */ ADVANCE_BATCH(); } - - /* Mark sync so we can wait for it before setting up the VB on the next - * rectangle. - */ - i830MarkSync(pScrn); } /** From b3c1a148679a4d943e556f996ef6b9004f549a41 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 25 Jul 2008 15:18:28 -0700 Subject: [PATCH 31/45] Eliminate unnecessary flush from i965_composite This improves 'x11perf -aa10text' performance from ~144k to ~169k --- src/i965_render.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/i965_render.c b/src/i965_render.c index 93e28882..6eafd445 100644 --- a/src/i965_render.c +++ b/src/i965_render.c @@ -1447,21 +1447,6 @@ i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, ErrorF("sync after 3dprimitive\n"); I830Sync(pScrn); #endif - /* we must be sure that the pipeline is flushed before next exa draw, - because that will be new state, binding state and instructions*/ - { - BEGIN_BATCH(4); - OUT_BATCH(BRW_PIPE_CONTROL | - BRW_PIPE_CONTROL_NOWRITE | - BRW_PIPE_CONTROL_WC_FLUSH | - BRW_PIPE_CONTROL_IS_FLUSH | - (1 << 10) | /* XXX texture cache flush for BLC/CTG */ - 2); - OUT_BATCH(0); /* Destination address */ - OUT_BATCH(0); /* Immediate data low DW */ - OUT_BATCH(0); /* Immediate data high DW */ - ADVANCE_BATCH(); - } } /** From a893f176dda0b64f7dadfda6bf0331240037851e Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 25 Jul 2008 15:56:35 -0700 Subject: [PATCH 32/45] Add call to intel_bufmgr_gem_enable_reuse This instructs GEM to reuse buffer objects and improves the performance of my favorite 'x11perf -aa10text' from about 169k to about 188k glyphs/sec. --- src/i830_driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i830_driver.c b/src/i830_driver.c index dcbaa040..a453d907 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -2760,6 +2760,7 @@ i830_init_bufmgr(ScrnInfoPtr pScrn) batch_size = 4096; pI830->bufmgr = intel_bufmgr_gem_init(pI830->drmSubFD, batch_size); + intel_bufmgr_gem_enable_reuse(pI830->bufmgr); } else { pI830->bufmgr = intel_bufmgr_fake_init(pI830->fake_bufmgr_mem->offset, pI830->FbBase + From 750bd0bde09adf956c17bbb49c5a6020f12e60a4 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Tue, 29 Jul 2008 15:22:39 -0700 Subject: [PATCH 33/45] Call DRM_I915_GEM_THROTTLE from I830BlockHandler This prevents the CPU from ridiculously outrunning the GPU. --- src/i830_driver.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/i830_driver.c b/src/i830_driver.c index a453d907..195bc5c2 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -2507,6 +2507,9 @@ I830BlockHandler(int i, intel_batch_flush(pScrn); pI830->need_mi_flush = FALSE; +#ifdef XF86DRI + drmCommandNone(pI830->drmSubFD, DRM_I915_GEM_THROTTLE); +#endif } /* From 59774e9aca2d743e82d616bb644d20ff6d60d492 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 29 Jul 2008 22:57:09 -0700 Subject: [PATCH 34/45] Add UXA - the unified memory acceleration architecture. This eliminates the cost of EXA migration management while providing full pixmap allocation control to the driver. The goal is to make something useful for UMA drivers. --- Makefile.am | 2 +- configure.ac | 1 + src/Makefile.am | 6 +- src/i830.h | 16 +- src/i830_accel.c | 31 +- src/i830_debug.c | 2 + src/i830_dri.c | 2 +- src/i830_driver.c | 155 ++++--- src/i830_exa.c | 131 +++++- src/i830_memory.c | 16 +- src/i830_video.c | 4 +- uxa/Makefile.am | 20 + uxa/uxa-accel.c | 1038 ++++++++++++++++++++++++++++++++++++++++++++ uxa/uxa-glyphs.c | 880 +++++++++++++++++++++++++++++++++++++ uxa/uxa-priv.h | 444 +++++++++++++++++++ uxa/uxa-render.c | 1052 +++++++++++++++++++++++++++++++++++++++++++++ uxa/uxa-unaccel.c | 370 ++++++++++++++++ uxa/uxa.c | 573 ++++++++++++++++++++++++ uxa/uxa.h | 671 +++++++++++++++++++++++++++++ 19 files changed, 5335 insertions(+), 79 deletions(-) create mode 100644 uxa/Makefile.am create mode 100644 uxa/uxa-accel.c create mode 100644 uxa/uxa-glyphs.c create mode 100644 uxa/uxa-priv.h create mode 100644 uxa/uxa-render.c create mode 100644 uxa/uxa-unaccel.c create mode 100644 uxa/uxa.c create mode 100644 uxa/uxa.h diff --git a/Makefile.am b/Makefile.am index b2398a88..5db07de9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AUTOMAKE_OPTIONS = foreign -SUBDIRS = src man +SUBDIRS = uxa src man EXTRA_DIST = README DISTCLEANFILES = doltcompile diff --git a/configure.ac b/configure.ac index db16c356..b24a1541 100644 --- a/configure.ac +++ b/configure.ac @@ -251,6 +251,7 @@ XORG_CHECK_LINUXDOC AC_OUTPUT([ Makefile + uxa/Makefile src/Makefile src/xvmc/Makefile src/bios_reader/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 2932233d..dd92c8d9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,13 +31,13 @@ SUBDIRS = xvmc bios_reader ch7017 ch7xxx ivch sil164 tfp410 $(REGDUMPER) # TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. AM_CFLAGS = @WARN_CFLAGS@ @XORG_CFLAGS@ @DRM_CFLAGS@ @DRI_CFLAGS@ \ - @PCIACCESS_CFLAGS@ \ - @XMODES_CFLAGS@ -DI830_XV -DI830_USE_XAA -DI830_USE_EXA + @PCIACCESS_CFLAGS@ -I../uxa \ + @XMODES_CFLAGS@ -DI830_XV -DI830_USE_XAA -DI830_USE_EXA -DI830_USE_UXA intel_drv_la_LTLIBRARIES = intel_drv.la intel_drv_la_LDFLAGS = -module -avoid-version intel_drv_ladir = @moduledir@/drivers -intel_drv_la_LIBADD = -lm +intel_drv_la_LIBADD = -lm ../uxa/libuxa.la if XSERVER_LIBPCIACCESS intel_drv_la_LIBADD += @PCIACCESS_LIBS@ endif diff --git a/src/i830.h b/src/i830.h index a8ab8c6c..2fb8efaa 100644 --- a/src/i830.h +++ b/src/i830.h @@ -83,7 +83,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifdef I830_USE_EXA #include "exa.h" +#include "uxa.h" Bool I830EXAInit(ScreenPtr pScreen); +Bool i830_uxa_init(ScreenPtr pScreen); unsigned long long I830TexOffsetStart(PixmapPtr pPix); #endif @@ -355,6 +357,14 @@ enum backlight_control { BCM_KERNEL, }; +typedef enum accel_method { + ACCEL_UNINIT = 0, + ACCEL_NONE, + ACCEL_XAA, + ACCEL_EXA, + ACCEL_UXA +} accel_method_t; + typedef struct _I830Rec { unsigned char *MMIOBase; unsigned char *GTTBase; @@ -496,8 +506,7 @@ typedef struct _I830Rec { Bool fence_used[FENCE_NEW_NR]; - Bool useEXA; - Bool noAccel; + accel_method_t accel; Bool SWCursor; #ifdef I830_USE_XAA XAAInfoRecPtr AccelInfoRec; @@ -518,6 +527,7 @@ typedef struct _I830Rec { #ifdef I830_USE_EXA ExaDriverPtr EXADriverPtr; + uxa_driver_t *uxa_driver; PixmapPtr pSrcPixmap; #endif @@ -902,7 +912,7 @@ static inline int i830_fb_compression_supported(I830Ptr pI830) /* fbc depends on tiled surface. And we don't support tiled * front buffer with XAA now. */ - if (!pI830->tiling || (IS_I965G(pI830) && !pI830->useEXA)) + if (!pI830->tiling || (IS_I965G(pI830) && pI830->accel <= ACCEL_XAA)) return FALSE; return TRUE; } diff --git a/src/i830_accel.c b/src/i830_accel.c index c3cd08e0..579de31c 100644 --- a/src/i830_accel.c +++ b/src/i830_accel.c @@ -67,12 +67,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. unsigned long intel_get_pixmap_offset(PixmapPtr pPix) { +#ifdef I830_USE_EXA ScreenPtr pScreen = pPix->drawable.pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); -#ifdef I830_USE_EXA - if (pI830->useEXA) + if (pI830->accel == ACCEL_EXA) return exaGetPixmapOffset(pPix); #endif return (unsigned long)pPix->devPrivate.ptr - (unsigned long)pI830->FbBase; @@ -81,17 +81,15 @@ intel_get_pixmap_offset(PixmapPtr pPix) unsigned long intel_get_pixmap_pitch(PixmapPtr pPix) { +#ifdef I830_USE_EXA ScreenPtr pScreen = pPix->drawable.pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); -#ifdef I830_USE_EXA - if (pI830->useEXA) + if (pI830->accel == ACCEL_EXA) return exaGetPixmapPitch(pPix); #endif -#ifdef I830_USE_XAA return (unsigned long)pPix->devKind; -#endif } int @@ -150,6 +148,9 @@ I830WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis) #endif #ifdef I830_USE_EXA pI830->EXADriverPtr = NULL; +#endif +#ifdef I830_USE_UXA + pI830->uxa_driver = NULL; #endif FatalError("lockup\n"); } @@ -176,7 +177,7 @@ I830Sync(ScrnInfoPtr pScrn) if (I810_DEBUG & (DEBUG_VERBOSE_ACCEL | DEBUG_VERBOSE_SYNC)) ErrorF("I830Sync\n"); - if (pI830->noAccel) + if (pI830->accel == ACCEL_NONE) return; #ifdef XF86DRI @@ -278,15 +279,25 @@ I830SelectBuffer(ScrnInfoPtr pScrn, int buffer) Bool I830AccelInit(ScreenPtr pScreen) { -#ifdef I830_USE_EXA ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); - if (pI830->useEXA) + switch (pI830->accel) { +#ifdef I830_USE_UXA + case ACCEL_UXA: + return i830_uxa_init(pScreen); +#endif +#ifdef I830_USE_EXA + case ACCEL_EXA: return I830EXAInit(pScreen); #endif #ifdef I830_USE_XAA - return I830XAAInit(pScreen); + case ACCEL_XAA: + return I830XAAInit(pScreen); #endif + case ACCEL_UNINIT: + case ACCEL_NONE: + break; + } return FALSE; } diff --git a/src/i830_debug.c b/src/i830_debug.c index 1671e255..f1205cc6 100644 --- a/src/i830_debug.c +++ b/src/i830_debug.c @@ -1314,6 +1314,8 @@ i830_valid_command (uint32_t cmd) if (!mi_cmds[opcode]) return -1; break; + case 1: + return -1; case 2: /* 2D */ count = (cmd & 0x1f) + 2; opcode = (cmd >> 22) & 0x7f; diff --git a/src/i830_dri.c b/src/i830_dri.c index 46783721..0e5d81dd 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -589,7 +589,7 @@ I830DRIScreenInit(ScreenPtr pScreen) #if DRIINFO_MAJOR_VERSION > 5 || \ (DRIINFO_MAJOR_VERSION == 5 && DRIINFO_MINOR_VERSION >= 3) - if (pI830->useEXA) + if (pI830->accel == ACCEL_EXA) pDRIInfo->texOffsetStart = I830TexOffsetStart; #endif diff --git a/src/i830_driver.c b/src/i830_driver.c index b6fac9f8..ed974ce2 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -290,9 +290,7 @@ static PciChipsets I830PciChipsets[] = { */ typedef enum { -#if defined(I830_USE_XAA) && defined(I830_USE_EXA) OPTION_ACCELMETHOD, -#endif OPTION_NOACCEL, OPTION_SW_CURSOR, OPTION_CACHE_LINES, @@ -318,9 +316,7 @@ typedef enum { } I830Opts; static OptionInfoRec I830Options[] = { -#if defined(I830_USE_XAA) && defined(I830_USE_EXA) {OPTION_ACCELMETHOD, "AccelMethod", OPTV_ANYSTR, {0}, FALSE}, -#endif {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_CACHE_LINES, "CacheLines", OPTV_INTEGER, {0}, FALSE}, @@ -1338,6 +1334,15 @@ i830_detect_chipset(ScrnInfoPtr pScrn) return TRUE; } +static const char *accel_name[] = +{ + "unspecified", + "no", + "XAA", + "EXA", + "UXA", +}; + /** * This is called per zaphod head (so usually just once) to do initialization * before the Screen is created. @@ -1554,7 +1559,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) num_pipe, num_pipe > 1 ? "s" : ""); if (xf86ReturnOptValBool(pI830->Options, OPTION_NOACCEL, FALSE)) { - pI830->noAccel = TRUE; + pI830->accel = ACCEL_NONE; } /* @@ -1568,29 +1573,38 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) * All this *could* go away if we removed XAA support from this driver, * for example. :) */ - if (!pI830->noAccel) { -#ifdef I830_USE_EXA - pI830->useEXA = TRUE; -#else - pI830->useEXA = FALSE; + if (pI830->accel == ACCEL_UNINIT) { + pI830->accel = ACCEL_NONE; +#ifdef I830_USE_XAA + pI830->accel = ACCEL_XAA; #endif -#if defined(I830_USE_XAA) && defined(I830_USE_EXA) +#ifdef I830_USE_EXA + pI830->accel = ACCEL_EXA; +#endif +#ifdef I830_USE_UXA + pI830->accel = ACCEL_UXA; +#endif +#if I830_USE_XAA + I830_USE_EXA + I830_USE_UXA >= 2 from = X_DEFAULT; if ((s = (char *)xf86GetOptValString(pI830->Options, OPTION_ACCELMETHOD))) { if (!xf86NameCmp(s, "EXA")) { from = X_CONFIG; - pI830->useEXA = TRUE; + pI830->accel = ACCEL_EXA; } else if (!xf86NameCmp(s, "XAA")) { from = X_CONFIG; - pI830->useEXA = FALSE; + pI830->accel = ACCEL_XAA; + } + else if (!xf86NameCmp(s, "UXA")) { + from = X_CONFIG; + pI830->accel = ACCEL_UXA; } } #endif - xf86DrvMsg(pScrn->scrnIndex, from, "Using %s for acceleration\n", - pI830->useEXA ? "EXA" : "XAA"); } + xf86DrvMsg(pScrn->scrnIndex, from, "Using %s acceleration\n", + accel_name[pI830->accel]); if (xf86ReturnOptValBool(pI830->Options, OPTION_SW_CURSOR, FALSE)) { pI830->SWCursor = TRUE; @@ -1601,7 +1615,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) #ifdef XF86DRI if (!pI830->directRenderingDisabled) { - if (pI830->noAccel || pI830->SWCursor) { + if (pI830->accel == ACCEL_NONE || pI830->SWCursor) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRI is disabled because it " "needs HW cursor and 2D acceleration.\n"); pI830->directRenderingDisabled = TRUE; @@ -1774,7 +1788,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) if (!IS_I965G(pI830) && pScrn->virtualY > 2048) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot support > 2048 vertical lines. disabling acceleration.\n"); - pI830->noAccel = TRUE; + pI830->accel = ACCEL_NONE; } /* Set display resolution */ @@ -1788,18 +1802,19 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) xf86LoaderReqSymLists(I810fbSymbols, NULL); + switch (pI830->accel) { #ifdef I830_USE_XAA - if (!pI830->noAccel && !pI830->useEXA) { + case ACCEL_XAA: if (!xf86LoadSubModule(pScrn, "xaa")) { PreInitCleanup(pScrn); return FALSE; } xf86LoaderReqSymLists(I810xaaSymbols, NULL); - } + break; #endif #ifdef I830_USE_EXA - if (!pI830->noAccel && pI830->useEXA) { + case ACCEL_EXA: { XF86ModReqInfo req; int errmaj, errmin; @@ -1817,8 +1832,12 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) return FALSE; } xf86LoaderReqSymLists(I830exaSymbols, NULL); + break; } #endif + default: + break; + } if (!pI830->SWCursor) { if (!xf86LoadSubModule(pScrn, "ramdac")) { PreInitCleanup(pScrn); @@ -1878,7 +1897,7 @@ i830_stop_ring(ScrnInfoPtr pScrn, Bool flush) pI830->entityPrivate->RingRunning = 0; /* Flush the ring buffer (if enabled), then disable it. */ - if (!pI830->noAccel) { + if (pI830->accel != ACCEL_NONE) { temp = INREG(LP_RING + RING_LEN); if (temp & RING_VALID) { i830_refresh_ring(pScrn); @@ -1900,7 +1919,7 @@ i830_start_ring(ScrnInfoPtr pScrn) DPRINTF(PFX, "SetRingRegs\n"); - if (pI830->noAccel) + if (pI830->accel == ACCEL_NONE) return; if (!I830IsPrimary(pScrn)) return; @@ -2441,7 +2460,7 @@ IntelEmitInvarientState(ScrnInfoPtr pScrn) I830Ptr pI830 = I830PTR(pScrn); uint32_t ctx_addr; - if (pI830->noAccel) + if (pI830->accel == ACCEL_NONE) return; #ifdef XF86DRI @@ -2496,12 +2515,12 @@ I830BlockHandler(int i, pI830->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = I830BlockHandler; - if (pScrn->vtSema && !pI830->noAccel) { + if (pScrn->vtSema && pI830->accel != ACCEL_NONE) { /* Emit a flush of the rendering cache, or on the 965 and beyond * rendering results may not hit the framebuffer until significantly * later. */ - if (!pI830->noAccel && (pI830->need_mi_flush || pI830->batch_used)) + if (pI830->accel != ACCEL_NONE && (pI830->need_mi_flush || pI830->batch_used)) I830EmitFlush(pScrn); /* Flush the batch, so that any rendering is executed in a timely @@ -3001,12 +3020,12 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) pI830->XvEnabled = !pI830->XvDisabled; if (pI830->XvEnabled) { if (!I830IsPrimary(pScrn)) { - if (!pI8301->XvEnabled || pI830->noAccel) { + if (!pI8301->XvEnabled || pI830->accel == ACCEL_NONE) { pI830->XvEnabled = FALSE; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Xv is disabled.\n"); } } else - if (pI830->noAccel || pI830->StolenOnly) { + if (pI830->accel == ACCEL_NONE || pI830->StolenOnly) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Xv is disabled because it " "needs 2D accel and AGPGART.\n"); pI830->XvEnabled = FALSE; @@ -3016,18 +3035,18 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) pI830->XvEnabled = FALSE; #endif - if (!pI830->noAccel) { + if (pI830->accel != ACCEL_NONE) { if (pI830->memory_manager == NULL && pI830->LpRing->mem->size == 0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling acceleration because the ring buffer " "allocation failed.\n"); - pI830->noAccel = TRUE; + pI830->accel = ACCEL_NONE; } } #ifdef I830_XV if (pI830->XvEnabled) { - if (pI830->noAccel) { + if (pI830->accel == ACCEL_NONE) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling Xv because it " "needs 2D acceleration.\n"); pI830->XvEnabled = FALSE; @@ -3049,7 +3068,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) */ if (pI830->directRenderingEnabled) { - if (pI830->noAccel || pI830->SWCursor || (pI830->StolenOnly && I830IsPrimary(pScrn))) { + if (pI830->accel == ACCEL_NONE || pI830->SWCursor || (pI830->StolenOnly && I830IsPrimary(pScrn))) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DRI is disabled because it " "needs HW cursor, 2D accel and AGPGART.\n"); pI830->directRenderingEnabled = FALSE; @@ -3123,7 +3142,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) DPRINTF(PFX, "assert( if(!I830EnterVT(scrnIndex, 0)) )\n"); - if (!pI830->useEXA) { + if (pI830->accel <= ACCEL_XAA) { if (I830IsPrimary(pScrn)) { if (!I830InitFBManager(pScreen, &(pI830->FbMemBox))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, @@ -3171,7 +3190,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) DPRINTF(PFX, "assert( if(!I830InitFBManager(pScreen, &(pI830->FbMemBox))) )\n"); - if (!pI830->noAccel) { + if (pI830->accel != ACCEL_NONE) { if (!I830AccelInit(pScreen)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware acceleration initialization failed\n"); @@ -3596,11 +3615,18 @@ I830CloseScreen(int scrnIndex, ScreenPtr pScreen) } #endif #ifdef I830_USE_EXA - if (pI830->useEXA && pI830->EXADriverPtr) { + if (pI830->EXADriverPtr) { exaDriverFini(pScreen); xfree(pI830->EXADriverPtr); pI830->EXADriverPtr = NULL; } +#endif +#ifdef I830_USE_UXA + if (pI830->uxa_driver) { + uxa_driver_fini (pScreen); + xfree (pI830->uxa_driver); + pI830->uxa_driver = NULL; + } #endif xf86_cursors_fini (pScreen); @@ -3830,19 +3856,34 @@ i830WaitSync(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); + switch (pI830->accel) { #ifdef I830_USE_XAA - if (!pI830->noAccel && !pI830->useEXA && pI830->AccelInfoRec - && pI830->AccelInfoRec->NeedToSync) { - (*pI830->AccelInfoRec->Sync)(pScrn); - pI830->AccelInfoRec->NeedToSync = FALSE; - } + case ACCEL_XAA: + if (pI830->AccelInfoRec && pI830->AccelInfoRec->NeedToSync) { + (*pI830->AccelInfoRec->Sync)(pScrn); + pI830->AccelInfoRec->NeedToSync = FALSE; + } + break; #endif #ifdef I830_USE_EXA - if (!pI830->noAccel && pI830->useEXA && pI830->EXADriverPtr) { - ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; - exaWaitSync(pScreen); - } + case ACCEL_EXA: + if (pI830->EXADriverPtr) { + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + exaWaitSync(pScreen); + } + break; #endif +#ifdef I830_USE_UXA + case ACCEL_UXA: + if (pI830->uxa_driver) { + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + uxa_wait_sync(pScreen); + } + break; +#endif + default: + break; + } } void @@ -3850,16 +3891,32 @@ i830MarkSync(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); + switch (pI830->accel) { #ifdef I830_USE_XAA - if (!pI830->useEXA && pI830->AccelInfoRec) - pI830->AccelInfoRec->NeedToSync = TRUE; + case ACCEL_XAA: + if (pI830->AccelInfoRec) + pI830->AccelInfoRec->NeedToSync = TRUE; + break; #endif #ifdef I830_USE_EXA - if (pI830->useEXA && pI830->EXADriverPtr) { - ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; - exaMarkSync(pScreen); - } + case ACCEL_EXA: + if (pI830->EXADriverPtr) { + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + exaMarkSync(pScreen); + } + break; #endif +#ifdef I830_USE_UXA + case ACCEL_UXA: + if (pI830->uxa_driver) { + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; + exaMarkSync(pScreen); + } + break; +#endif + default: + break; + } } void diff --git a/src/i830_exa.c b/src/i830_exa.c index 75ccd742..a6705f48 100644 --- a/src/i830_exa.c +++ b/src/i830_exa.c @@ -430,7 +430,7 @@ I830EXAInit(ScreenPtr pScreen) pI830->EXADriverPtr = exaDriverAlloc(); if (pI830->EXADriverPtr == NULL) { - pI830->noAccel = TRUE; + pI830->accel = ACCEL_NONE; return FALSE; } memset(pI830->EXADriverPtr, 0, sizeof(*pI830->EXADriverPtr)); @@ -558,7 +558,7 @@ I830EXAInit(ScreenPtr pScreen) pI830->EXADriverPtr->exa_minor = 0; if(!exaDriverInit(pScreen, pI830->EXADriverPtr)) { xfree(pI830->EXADriverPtr); - pI830->noAccel = TRUE; + pI830->accel = ACCEL_NONE; return FALSE; } } @@ -568,6 +568,133 @@ I830EXAInit(ScreenPtr pScreen) return TRUE; } +static Bool +i830_uxa_pixmap_is_offscreen(PixmapPtr pPixmap) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + /* XXX for now, eventually we'll support 'real' off-screen pixmaps */ + if ((void *)pPixmap->devPrivate.ptr >= (void *)pI830->FbBase && + (void *)pPixmap->devPrivate.ptr < + (void *)(pI830->FbBase + pI830->FbMapSize)) + { + return TRUE; + } else { + return FALSE; + } +} + + +Bool +i830_uxa_init (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + pI830->uxa_driver = uxa_driver_alloc(); + if (pI830->uxa_driver == NULL) { + pI830->accel = ACCEL_NONE; + return FALSE; + } + memset(pI830->uxa_driver, 0, sizeof(*pI830->uxa_driver)); + + pI830->bufferOffset = 0; + pI830->uxa_driver->uxa_major = 1; + pI830->uxa_driver->uxa_minor = 0; + + /* Limits are described in the BLT engine chapter under Graphics Data Size + * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO, + * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO. + * + * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768. + * + * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled. + * i965 limits 3D surface to 4kB-aligned offset if tiled. + * i965 limits 3D surfaces to w,h of ?,8192. + * i965 limits 3D surface to pitch of 1B - 128kB. + * i965 limits 3D surface pitch alignment to 1 or 2 times the element size. + * i965 limits 3D surface pitch alignment to 512B if tiled. + * i965 limits 3D destination drawing rect to w,h of 8192,8192. + * + * i915 limits 3D textures to 4B-aligned offset if un-tiled. + * i915 limits 3D textures to ~4kB-aligned offset if tiled. + * i915 limits 3D textures to width,height of 2048,2048. + * i915 limits 3D textures to pitch of 16B - 8kB, in dwords. + * i915 limits 3D destination to ~4kB-aligned offset if tiled. + * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled. + * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled. + * i915 limits 3D destination to POT aligned pitch if tiled. + * i915 limits 3D destination drawing rect to w,h of 2048,2048. + * + * i845 limits 3D textures to 4B-aligned offset if un-tiled. + * i845 limits 3D textures to ~4kB-aligned offset if tiled. + * i845 limits 3D textures to width,height of 2048,2048. + * i845 limits 3D textures to pitch of 4B - 8kB, in dwords. + * i845 limits 3D destination to 4B-aligned offset if un-tiled. + * i845 limits 3D destination to ~4kB-aligned offset if tiled. + * i845 limits 3D destination to pitch of 8B - 8kB, in dwords. + * i845 limits 3D destination drawing rect to w,h of 2048,2048. + * + * For the tiled issues, the only tiled buffer we draw to should be + * the front, which will have an appropriate pitch/offset already set up, + * so EXA doesn't need to worry. + */ + if (IS_I965G(pI830)) { + pI830->uxa_driver->maxX = 8192; + pI830->uxa_driver->maxY = 8192; + } else { + pI830->uxa_driver->maxX = 2048; + pI830->uxa_driver->maxY = 2048; + } + + /* Sync */ + pI830->uxa_driver->WaitMarker = I830EXASync; + + /* Solid fill */ + pI830->uxa_driver->PrepareSolid = I830EXAPrepareSolid; + pI830->uxa_driver->Solid = I830EXASolid; + pI830->uxa_driver->DoneSolid = I830EXADoneSolid; + + /* Copy */ + pI830->uxa_driver->PrepareCopy = I830EXAPrepareCopy; + pI830->uxa_driver->Copy = I830EXACopy; + pI830->uxa_driver->DoneCopy = I830EXADoneCopy; + + /* Composite */ + if (!IS_I9XX(pI830)) { + pI830->uxa_driver->CheckComposite = i830_check_composite; + pI830->uxa_driver->PrepareComposite = i830_prepare_composite; + pI830->uxa_driver->Composite = i830_composite; + pI830->uxa_driver->DoneComposite = i830_done_composite; + } else if (IS_I915G(pI830) || IS_I915GM(pI830) || + IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) + { + pI830->uxa_driver->CheckComposite = i915_check_composite; + pI830->uxa_driver->PrepareComposite = i915_prepare_composite; + pI830->uxa_driver->Composite = i830_composite; + pI830->uxa_driver->DoneComposite = i830_done_composite; + } else { + pI830->uxa_driver->CheckComposite = i965_check_composite; + pI830->uxa_driver->PrepareComposite = i965_prepare_composite; + pI830->uxa_driver->Composite = i965_composite; + pI830->uxa_driver->DoneComposite = i830_done_composite; + } + pI830->uxa_driver->PixmapIsOffscreen = i830_uxa_pixmap_is_offscreen; + + if(!uxa_driver_init(pScreen, pI830->uxa_driver)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "UXA initialization failed\n"); + xfree(pI830->uxa_driver); + pI830->accel = ACCEL_NONE; + return FALSE; + } + + I830SelectBuffer(pScrn, I830_SELECT_FRONT); + + return TRUE; +} + #ifdef XF86DRI #ifndef ExaOffscreenMarkUsed diff --git a/src/i830_memory.c b/src/i830_memory.c index b62bda05..c1748b3e 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -449,7 +449,7 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) mmsize = size; /* EXA area is fixed. */ - if (pI830->useEXA) { + if (pI830->accel == ACCEL_EXA) { mmsize -= ROUND_TO_PAGE(3 * pScrn->displayWidth * pI830->cpp * pScrn->virtualY); } @@ -1022,7 +1022,7 @@ i830_allocate_ringbuffer(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); - if (pI830->noAccel || pI830->memory_manager || pI830->LpRing->mem != NULL) + if (pI830->accel == ACCEL_NONE || pI830->memory_manager || pI830->LpRing->mem != NULL) return TRUE; /* We don't have any mechanism in the DRM yet to alert it that we've moved @@ -1167,7 +1167,7 @@ i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox, minspace = pitch * pScrn->virtualY; avail = pScrn->videoRam * 1024; - if (!pI830->useEXA) { + if (pI830->accel == ACCEL_XAA) { maxCacheLines = (avail - minspace) / pitch; /* This shouldn't happen. */ if (maxCacheLines < 0) { @@ -1198,7 +1198,7 @@ i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox, "Allocating %d scanlines for pixmap cache\n", cacheLines); } else { - /* For EXA, we have a separate allocation for the linear allocator + /* For non-XAA, we have a separate allocation for the linear allocator * which also does the pixmap cache. */ cacheLines = 0; @@ -1213,7 +1213,7 @@ i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox, * acceleration operations (non-XY COLOR_BLT) can't be done to tiled * buffers. */ - if (!pI830->useEXA && IS_I965G(pI830)) + if (pI830->accel <= ACCEL_XAA && IS_I965G(pI830)) tiling = FALSE; else tiling = pI830->tiling; @@ -1412,7 +1412,7 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn) } /* even in XAA, 965G needs state mem buffer for rendering */ - if (IS_I965G(pI830) && !pI830->noAccel && + if (IS_I965G(pI830) && pI830->accel != ACCEL_NONE && pI830->gen4_render_state_mem == NULL) { pI830->gen4_render_state_mem = @@ -1450,7 +1450,7 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn) return FALSE; #ifdef I830_USE_EXA - if (pI830->useEXA) { + if (pI830->accel == ACCEL_EXA) { if (pI830->exa_offscreen == NULL) { /* Default EXA to having 3 screens worth of offscreen memory space * (for pixmaps). @@ -1478,7 +1478,7 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn) } #endif /* I830_USE_EXA */ - if (!pI830->noAccel && !pI830->useEXA) { + if (pI830->accel == ACCEL_XAA) { /* The lifetime fixed offset of xaa scratch is probably not required, * but we do some setup using it at XAAInit() time. And XAA may not * end up being supported with GEM anyway. diff --git a/src/i830_video.c b/src/i830_video.c index 486f6708..1719835c 100644 --- a/src/i830_video.c +++ b/src/i830_video.c @@ -2460,13 +2460,13 @@ I830PutImage(ScrnInfoPtr pScrn, } #ifdef I830_USE_EXA - if (pPriv->textured && pI830->useEXA) { + if (pPriv->textured && pI830->accel == ACCEL_EXA) { /* Force the pixmap into framebuffer so we can draw to it. */ exaMoveInPixmap(pPixmap); } #endif - if (pPriv->textured && !pI830->useEXA && + if (pPriv->textured && pI830->accel <= ACCEL_XAA && (((char *)pPixmap->devPrivate.ptr < (char *)pI830->FbBase) || ((char *)pPixmap->devPrivate.ptr >= (char *)pI830->FbBase + pI830->FbMapSize))) { diff --git a/uxa/Makefile.am b/uxa/Makefile.am new file mode 100644 index 00000000..641b4146 --- /dev/null +++ b/uxa/Makefile.am @@ -0,0 +1,20 @@ +noinst_LTLIBRARIES = libuxa.la + +# Override these since UXA doesn't need them and the needed files aren't +# built (in hw/xfree86/os-support/solaris) until after UXA is built +SOLARIS_ASM_CFLAGS="" + +INCLUDES = \ + $(XORG_INCS) + +AM_CFLAGS = $(WARN_CFLAGS) $(XORG_CFLAGS) $(DIX_CFLAGS) + +libuxa_la_SOURCES = \ + uxa.c \ + uxa.h \ + uxa-accel.c \ + uxa-glyphs.c \ + uxa-render.c \ + uxa-priv.h \ + uxa-unaccel.c + diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c new file mode 100644 index 00000000..7c7b3e9b --- /dev/null +++ b/uxa/uxa-accel.c @@ -0,0 +1,1038 @@ +/* + * Copyright © 2001 Keith Packard + * + * 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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. + * + * Authors: + * Eric Anholt + * Michel Dänzer + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif +#include "uxa-priv.h" +#include +#include "dixfontstr.h" +#include "uxa.h" + +static void +uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + ScreenPtr pScreen = pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + RegionPtr pClip = fbGetCompositeClip(pGC); + PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable); + BoxPtr pextent, pbox; + int nbox; + int extentX1, extentX2, extentY1, extentY2; + int fullX1, fullX2, fullY1; + int partX1, partX2; + int off_x, off_y; + + if (uxa_screen->swappedOut || pGC->fillStyle != FillSolid || + !(pPixmap = uxa_get_offscreen_pixmap (pDrawable, &off_x, &off_y)) || + !(*uxa_screen->info->PrepareSolid) (pPixmap, + pGC->alu, + pGC->planemask, + pGC->fgPixel)) + { + uxa_check_fill_spans (pDrawable, pGC, n, ppt, pwidth, fSorted); + return; + } + + pextent = REGION_EXTENTS(pGC->pScreen, pClip); + extentX1 = pextent->x1; + extentY1 = pextent->y1; + extentX2 = pextent->x2; + extentY2 = pextent->y2; + while (n--) + { + fullX1 = ppt->x; + fullY1 = ppt->y; + fullX2 = fullX1 + (int) *pwidth; + ppt++; + pwidth++; + + if (fullY1 < extentY1 || extentY2 <= fullY1) + continue; + + if (fullX1 < extentX1) + fullX1 = extentX1; + + if (fullX2 > extentX2) + fullX2 = extentX2; + + if (fullX1 >= fullX2) + continue; + + nbox = REGION_NUM_RECTS (pClip); + if (nbox == 1) + { + (*uxa_screen->info->Solid) (pPixmap, + fullX1 + off_x, fullY1 + off_y, + fullX2 + off_x, fullY1 + 1 + off_y); + } + else + { + pbox = REGION_RECTS(pClip); + while(nbox--) + { + if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) + { + partX1 = pbox->x1; + if (partX1 < fullX1) + partX1 = fullX1; + partX2 = pbox->x2; + if (partX2 > fullX2) + partX2 = fullX2; + if (partX2 > partX1) { + (*uxa_screen->info->Solid) (pPixmap, + partX1 + off_x, fullY1 + off_y, + partX2 + off_x, fullY1 + 1 + off_y); + } + } + pbox++; + } + } + } + (*uxa_screen->info->DoneSolid) (pPixmap); + uxa_mark_sync(pScreen); +} + +static Bool +uxa_do_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, + int w, int h, int format, char *bits, int src_stride) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); + PixmapPtr pPix = uxa_get_drawable_pixmap (pDrawable); + RegionPtr pClip; + BoxPtr pbox; + int nbox; + int xoff, yoff; + int bpp = pDrawable->bitsPerPixel; + Bool access_prepared = FALSE; + + /* Don't bother with under 8bpp, XYPixmaps. */ + if (format != ZPixmap || bpp < 8) + return FALSE; + + /* Only accelerate copies: no rop or planemask. */ + if (!UXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy) + return FALSE; + + if (uxa_screen->swappedOut) + return FALSE; + + pPix = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff); + + if (!pPix || !uxa_screen->info->UploadToScreen) + return FALSE; + + x += pDrawable->x; + y += pDrawable->y; + + pClip = fbGetCompositeClip(pGC); + for (nbox = REGION_NUM_RECTS(pClip), + pbox = REGION_RECTS(pClip); + nbox--; + pbox++) + { + int x1 = x; + int y1 = y; + int x2 = x + w; + int y2 = y + h; + char *src; + Bool ok; + + if (x1 < pbox->x1) + x1 = pbox->x1; + if (y1 < pbox->y1) + y1 = pbox->y1; + if (x2 > pbox->x2) + x2 = pbox->x2; + if (y2 > pbox->y2) + y2 = pbox->y2; + if (x1 >= x2 || y1 >= y2) + continue; + + src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); + ok = uxa_screen->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, + x2 - x1, y2 - y1, src, src_stride); + /* If we fail to accelerate the upload, fall back to using unaccelerated + * fb calls. + */ + if (!ok) { + FbStip *dst; + FbStride dst_stride; + int dstBpp; + int dstXoff, dstYoff; + + if (!access_prepared) { + uxa_prepare_access(pDrawable, UXA_PREPARE_DEST); + + access_prepared = TRUE; + } + + fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp, + dstXoff, dstYoff); + + fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)), + src_stride / sizeof(FbStip), + (x1 - x) * dstBpp, + dst + (y1 + dstYoff) * dst_stride, + dst_stride, + (x1 + dstXoff) * dstBpp, + (x2 - x1) * dstBpp, + y2 - y1, + GXcopy, FB_ALLONES, dstBpp); + } + } + + if (access_prepared) + uxa_finish_access(pDrawable, UXA_PREPARE_DEST); + else + uxa_mark_sync(pDrawable->pScreen); + + return TRUE; +} + +#ifdef MITSHM + +static Bool +uxa_do_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, + unsigned int format, int w, int h, int sx, int sy, int sw, + int sh, int dx, int dy, char *data) +{ + int src_stride = PixmapBytePad(w, depth); + + if (uxa_do_put_image(pDrawable, pGC, depth, dx, dy, sw, sh, format, data + + sy * src_stride + sx * BitsPerPixel(depth) / 8, + src_stride)) + return TRUE; + + if (format == ZPixmap) + { + PixmapPtr pPixmap; + + pPixmap = GetScratchPixmapHeader(pDrawable->pScreen, w, h, depth, + BitsPerPixel(depth), PixmapBytePad(w, depth), (pointer)data); + if (!pPixmap) + return FALSE; + + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + + fbCopyArea((DrawablePtr)pPixmap, pDrawable, pGC, sx, sy, sw, sh, dx, dy); + uxa_finish_access(pDrawable, UXA_PREPARE_DEST); + + FreeScratchPixmapHeader(pPixmap); + + return TRUE; + } + + return FALSE; +} + +/* The actual ShmPutImage isn't wrapped by the damage layer, so we need to + * inform any interested parties of the damage incurred to the drawable. + * + * We also need to set the pending damage to ensure correct migration in all + * cases. + */ +void +uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format, + int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, + char *data) +{ + if (!uxa_do_shm_put_image(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, + dx, dy, data)) { + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, + data); + uxa_finish_access(pDrawable, UXA_PREPARE_DEST); + } +} + +ShmFuncs uxa_shm_funcs = { NULL, uxa_shm_put_image }; + +#endif + +static void +uxa_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, + int w, int h, int leftPad, int format, char *bits) +{ +#ifdef MITSHM + if (!uxa_do_shm_put_image(pDrawable, pGC, depth, format, w, h, 0, 0, w, h, x, y, + bits)) +#else + if (!uxa_do_put_image(pDrawable, pGC, depth, x, y, w, h, format, bits, + PixmapBytePad(w, pDrawable->depth))) +#endif + uxa_check_put_image(pDrawable, pGC, depth, x, y, w, h, leftPad, format, + bits); +} + +static Bool inline +uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen); + PixmapPtr pSrcPixmap, pDstPixmap; + int src_off_x, src_off_y, dst_off_x, dst_off_y; + int dirsetup; + + /* Need to get both pixmaps to call the driver routines */ + pSrcPixmap = uxa_get_offscreen_pixmap (pSrcDrawable, &src_off_x, &src_off_y); + pDstPixmap = uxa_get_offscreen_pixmap (pDstDrawable, &dst_off_x, &dst_off_y); + if (!pSrcPixmap || !pDstPixmap) + return FALSE; + + /* + * Now the case of a chip that only supports xdir = ydir = 1 or + * xdir = ydir = -1, but we have xdir != ydir. + */ + dirsetup = 0; /* No direction set up yet. */ + for (; nbox; pbox++, nbox--) { + if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { + /* Do a xdir = ydir = -1 blit instead. */ + if (dirsetup != -1) { + if (dirsetup != 0) + uxa_screen->info->DoneCopy(pDstPixmap); + dirsetup = -1; + if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + -1, -1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + (*uxa_screen->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) { + /* Do a xdir = ydir = 1 blit instead. */ + if (dirsetup != 1) { + if (dirsetup != 0) + uxa_screen->info->DoneCopy(pDstPixmap); + dirsetup = 1; + if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + 1, 1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + (*uxa_screen->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } else if (dx >= 0) { + /* + * xdir = 1, ydir = -1. + * Perform line-by-line xdir = ydir = 1 blits, going up. + */ + int i; + if (dirsetup != 1) { + if (dirsetup != 0) + uxa_screen->info->DoneCopy(pDstPixmap); + dirsetup = 1; + if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + 1, 1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) + (*uxa_screen->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy + i, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1 + i, + pbox->x2 - pbox->x1, 1); + } else { + /* + * xdir = -1, ydir = 1. + * Perform line-by-line xdir = ydir = -1 blits, going down. + */ + int i; + if (dirsetup != -1) { + if (dirsetup != 0) + uxa_screen->info->DoneCopy(pDstPixmap); + dirsetup = -1; + if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap, + pDstPixmap, + -1, -1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : + FB_ALLONES)) + return FALSE; + } + for (i = 0; i < pbox->y2 - pbox->y1; i++) + (*uxa_screen->info->Copy)(pDstPixmap, + src_off_x + pbox->x1 + dx, + src_off_y + pbox->y1 + dy + i, + dst_off_x + pbox->x1, + dst_off_y + pbox->y1 + i, + pbox->x2 - pbox->x1, 1); + } + } + if (dirsetup != 0) + uxa_screen->info->DoneCopy(pDstPixmap); + uxa_mark_sync(pDstDrawable->pScreen); + return TRUE; +} + +void +uxa_copy_n_to_n (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown, + Pixel bitplane, + void *closure) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen); + int src_off_x, src_off_y; + int dst_off_x, dst_off_y; + PixmapPtr pSrcPixmap, pDstPixmap; + + pSrcPixmap = uxa_get_drawable_pixmap (pSrcDrawable); + pDstPixmap = uxa_get_drawable_pixmap (pDstDrawable); + + uxa_get_drawable_deltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); + uxa_get_drawable_deltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y); + + /* Mixed directions must be handled specially if the card is lame */ + if ((uxa_screen->info->flags & UXA_TWO_BITBLT_DIRECTIONS) && + reverse != upsidedown) { + if (uxa_copy_n_to_n_two_dir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, + dx, dy)) + return; + goto fallback; + } + + if (!uxa_pixmap_is_offscreen(pSrcPixmap) || + !uxa_pixmap_is_offscreen(pDstPixmap) || + !(*uxa_screen->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, + upsidedown ? -1 : 1, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : FB_ALLONES)) { + goto fallback; + } + + while (nbox--) + { + (*uxa_screen->info->Copy) (pDstPixmap, + pbox->x1 + dx + src_off_x, + pbox->y1 + dy + src_off_y, + pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, + pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + pbox++; + } + + (*uxa_screen->info->DoneCopy) (pDstPixmap); + uxa_mark_sync (pDstDrawable->pScreen); + + return; + +fallback: + UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable, + uxa_drawable_location(pSrcDrawable), + uxa_drawable_location(pDstDrawable))); + uxa_prepare_access (pDstDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pSrcDrawable, UXA_PREPARE_SRC); + fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, + upsidedown, bitplane, closure); + uxa_finish_access (pSrcDrawable, UXA_PREPARE_SRC); + uxa_finish_access (pDstDrawable, UXA_PREPARE_DEST); +} + +RegionPtr +uxa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, + int srcx, int srcy, int width, int height, int dstx, int dsty) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen); + + if (uxa_screen->swappedOut) { + return uxa_check_copy_area(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, dstx, dsty); + } + + return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, + dstx, dsty, uxa_copy_n_to_n, 0, NULL); +} + +static void +uxa_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr ppt) +{ + int i; + xRectangle *prect; + + /* If we can't reuse the current GC as is, don't bother accelerating the + * points. + */ + if (pGC->fillStyle != FillSolid) { + uxa_check_poly_point(pDrawable, pGC, mode, npt, ppt); + return; + } + + prect = xalloc(sizeof(xRectangle) * npt); + for (i = 0; i < npt; i++) { + prect[i].x = ppt[i].x; + prect[i].y = ppt[i].y; + if (i > 0 && mode == CoordModePrevious) { + prect[i].x += prect[i - 1].x; + prect[i].y += prect[i - 1].y; + } + prect[i].width = 1; + prect[i].height = 1; + } + pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect); + xfree(prect); +} + +/** + * uxa_poly_lines() checks if it can accelerate the lines as a group of + * horizontal or vertical lines (rectangles), and uses existing rectangle fill + * acceleration if so. + */ +static void +uxa_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr ppt) +{ + xRectangle *prect; + int x1, x2, y1, y2; + int i; + + /* Don't try to do wide lines or non-solid fill style. */ + if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || + pGC->fillStyle != FillSolid) { + uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt); + return; + } + + prect = xalloc(sizeof(xRectangle) * (npt - 1)); + x1 = ppt[0].x; + y1 = ppt[0].y; + /* If we have any non-horizontal/vertical, fall back. */ + for (i = 0; i < npt - 1; i++) { + if (mode == CoordModePrevious) { + x2 = x1 + ppt[i + 1].x; + y2 = y1 + ppt[i + 1].y; + } else { + x2 = ppt[i + 1].x; + y2 = ppt[i + 1].y; + } + + if (x1 != x2 && y1 != y2) { + xfree(prect); + uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt); + return; + } + + if (x1 < x2) { + prect[i].x = x1; + prect[i].width = x2 - x1 + 1; + } else { + prect[i].x = x2; + prect[i].width = x1 - x2 + 1; + } + if (y1 < y2) { + prect[i].y = y1; + prect[i].height = y2 - y1 + 1; + } else { + prect[i].y = y2; + prect[i].height = y1 - y2 + 1; + } + + x1 = x2; + y1 = y2; + } + pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect); + xfree(prect); +} + +/** + * uxa_poly_segment() checks if it can accelerate the lines as a group of + * horizontal or vertical lines (rectangles), and uses existing rectangle fill + * acceleration if so. + */ +static void +uxa_poly_segment (DrawablePtr pDrawable, GCPtr pGC, int nseg, + xSegment *pSeg) +{ + xRectangle *prect; + int i; + + /* Don't try to do wide lines or non-solid fill style. */ + if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid || + pGC->fillStyle != FillSolid) + { + uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg); + return; + } + + /* If we have any non-horizontal/vertical, fall back. */ + for (i = 0; i < nseg; i++) { + if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) { + uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg); + return; + } + } + + prect = xalloc(sizeof(xRectangle) * nseg); + for (i = 0; i < nseg; i++) { + if (pSeg[i].x1 < pSeg[i].x2) { + prect[i].x = pSeg[i].x1; + prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1; + } else { + prect[i].x = pSeg[i].x2; + prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1; + } + if (pSeg[i].y1 < pSeg[i].y2) { + prect[i].y = pSeg[i].y1; + prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1; + } else { + prect[i].y = pSeg[i].y2; + prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1; + } + + /* don't paint last pixel */ + if (pGC->capStyle == CapNotLast) { + if (prect[i].width == 1) + prect[i].height--; + else + prect[i].width--; + } + } + pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect); + xfree(prect); +} + +static Bool uxa_fill_region_solid (DrawablePtr pDrawable, RegionPtr pRegion, + Pixel pixel, CARD32 planemask, CARD32 alu); + +static void +uxa_poly_fill_rect(DrawablePtr pDrawable, + GCPtr pGC, + int nrect, + xRectangle *prect) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); + RegionPtr pClip = fbGetCompositeClip(pGC); + PixmapPtr pPixmap = uxa_get_drawable_pixmap(pDrawable); + register BoxPtr pbox; + BoxPtr pextent; + int extentX1, extentX2, extentY1, extentY2; + int fullX1, fullX2, fullY1, fullY2; + int partX1, partX2, partY1, partY2; + int xoff, yoff; + int xorg, yorg; + int n; + RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED); + + /* Compute intersection of rects and clip region */ + REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y); + REGION_INTERSECT(pScreen, pReg, pClip, pReg); + + if (!REGION_NUM_RECTS(pReg)) + goto out; + + uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff); + + if (uxa_screen->swappedOut) + goto fallback; + + /* For ROPs where overlaps don't matter, convert rectangles to region and + * call uxa_fill_region_{solid,tiled}. + */ + if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) && + (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear || + pGC->alu == GXnoop || pGC->alu == GXcopyInverted || + pGC->alu == GXset)) { + if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) && + uxa_fill_region_solid(pDrawable, pReg, pGC->fillStyle == FillSolid ? + pGC->fgPixel : pGC->tile.pixel, pGC->planemask, + pGC->alu)) || + (pGC->fillStyle == FillTiled && !pGC->tileIsPixel && + uxa_fill_region_tiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg, + pGC->planemask, pGC->alu))) { + goto out; + } + } + + if (pGC->fillStyle != FillSolid && + !(pGC->tileIsPixel && pGC->fillStyle == FillTiled)) + { + goto fallback; + } + + if (!uxa_pixmap_is_offscreen (pPixmap) || + !(*uxa_screen->info->PrepareSolid) (pPixmap, + pGC->alu, + pGC->planemask, + pGC->fgPixel)) + { +fallback: + uxa_check_poly_fill_rect (pDrawable, pGC, nrect, prect); + goto out; + } + + xorg = pDrawable->x; + yorg = pDrawable->y; + + pextent = REGION_EXTENTS(pGC->pScreen, pClip); + extentX1 = pextent->x1; + extentY1 = pextent->y1; + extentX2 = pextent->x2; + extentY2 = pextent->y2; + while (nrect--) + { + fullX1 = prect->x + xorg; + fullY1 = prect->y + yorg; + fullX2 = fullX1 + (int) prect->width; + fullY2 = fullY1 + (int) prect->height; + prect++; + + if (fullX1 < extentX1) + fullX1 = extentX1; + + if (fullY1 < extentY1) + fullY1 = extentY1; + + if (fullX2 > extentX2) + fullX2 = extentX2; + + if (fullY2 > extentY2) + fullY2 = extentY2; + + if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) + continue; + n = REGION_NUM_RECTS (pClip); + if (n == 1) + { + (*uxa_screen->info->Solid) (pPixmap, + fullX1 + xoff, fullY1 + yoff, + fullX2 + xoff, fullY2 + yoff); + } + else + { + pbox = REGION_RECTS(pClip); + /* + * clip the rectangle to each box in the clip region + * this is logically equivalent to calling Intersect(), + * but rectangles may overlap each other here. + */ + while(n--) + { + partX1 = pbox->x1; + if (partX1 < fullX1) + partX1 = fullX1; + partY1 = pbox->y1; + if (partY1 < fullY1) + partY1 = fullY1; + partX2 = pbox->x2; + if (partX2 > fullX2) + partX2 = fullX2; + partY2 = pbox->y2; + if (partY2 > fullY2) + partY2 = fullY2; + + pbox++; + + if (partX1 < partX2 && partY1 < partY2) { + (*uxa_screen->info->Solid) (pPixmap, + partX1 + xoff, partY1 + yoff, + partX2 + xoff, partY2 + yoff); + } + } + } + } + (*uxa_screen->info->DoneSolid) (pPixmap); + uxa_mark_sync(pDrawable->pScreen); + +out: + REGION_UNINIT(pScreen, pReg); + REGION_DESTROY(pScreen, pReg); +} + +const GCOps uxa_ops = { + uxa_fill_spans, + uxa_check_set_spans, + uxa_put_image, + uxa_copy_area, + uxa_check_copy_plane, + uxa_poly_point, + uxa_poly_lines, + uxa_poly_segment, + miPolyRectangle, + uxa_check_poly_arc, + miFillPolygon, + uxa_poly_fill_rect, + miPolyFillArc, + miPolyText8, + miPolyText16, + miImageText8, + miImageText16, + uxa_check_image_glyph_blt, + uxa_check_poly_glyph_blt, + uxa_check_push_pixels, +}; + +void +uxa_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + RegionRec rgnDst; + int dx, dy; + PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); + + REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0); + + REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc); +#ifdef COMPOSITE + if (pPixmap->screen_x || pPixmap->screen_y) + REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst, + -pPixmap->screen_x, -pPixmap->screen_y); +#endif + + fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable, + NULL, + &rgnDst, dx, dy, uxa_copy_n_to_n, 0, NULL); + + REGION_UNINIT(pWin->drawable.pScreen, &rgnDst); +} + +static Bool +uxa_fill_region_solid (DrawablePtr pDrawable, + RegionPtr pRegion, + Pixel pixel, + CARD32 planemask, + CARD32 alu) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); + PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable); + int xoff, yoff; + Bool ret = FALSE; + + uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff); + REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); + + if (uxa_pixmap_is_offscreen (pPixmap) && + (*uxa_screen->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) + { + int nbox; + BoxPtr pBox; + + nbox = REGION_NUM_RECTS (pRegion); + pBox = REGION_RECTS (pRegion); + + while (nbox--) + { + (*uxa_screen->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, + pBox->y2); + pBox++; + } + (*uxa_screen->info->DoneSolid) (pPixmap); + uxa_mark_sync(pDrawable->pScreen); + + ret = TRUE; + } + + REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); + + return ret; +} + +/* Try to do an accelerated tile of the pTile into pRegion of pDrawable. + * Based on fbFillRegionTiled(), fbTile(). + */ +Bool +uxa_fill_region_tiled (DrawablePtr pDrawable, + RegionPtr pRegion, + PixmapPtr pTile, + DDXPointPtr pPatOrg, + CARD32 planemask, + CARD32 alu) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); + PixmapPtr pPixmap; + int xoff, yoff; + int tileWidth, tileHeight; + int nbox = REGION_NUM_RECTS (pRegion); + BoxPtr pBox = REGION_RECTS (pRegion); + Bool ret = FALSE; + + tileWidth = pTile->drawable.width; + tileHeight = pTile->drawable.height; + + /* If we're filling with a solid color, grab it out and go to + * FillRegionSolid, saving numerous copies. + */ + if (tileWidth == 1 && tileHeight == 1) + return uxa_fill_region_solid(pDrawable, pRegion, + uxa_get_pixmap_first_pixel (pTile), planemask, + alu); + + pPixmap = uxa_get_drawable_pixmap (pDrawable); + uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff); + REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); + + pPixmap = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff); + + if (!pPixmap || !uxa_pixmap_is_offscreen(pTile)) + goto out; + + if ((*uxa_screen->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) + { + while (nbox--) + { + int height = pBox->y2 - pBox->y1; + int dstY = pBox->y1; + int tileY; + + modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY); + + while (height > 0) { + int width = pBox->x2 - pBox->x1; + int dstX = pBox->x1; + int tileX; + int h = tileHeight - tileY; + + if (h > height) + h = height; + height -= h; + + modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth, + tileX); + + while (width > 0) { + int w = tileWidth - tileX; + if (w > width) + w = width; + width -= w; + + (*uxa_screen->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, + w, h); + dstX += w; + tileX = 0; + } + dstY += h; + tileY = 0; + } + pBox++; + } + (*uxa_screen->info->DoneCopy) (pPixmap); + uxa_mark_sync(pDrawable->pScreen); + + ret = TRUE; + } + +out: + REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff); + + return ret; +} + + +/** + * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory. + * + * This is probably the only case we actually care about. The rest fall through + * to migration and fbGetImage, which hopefully will result in migration pushing + * the pixmap out of framebuffer. + */ +void +uxa_get_image (DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); + BoxRec Box; + PixmapPtr pPix = uxa_get_drawable_pixmap (pDrawable); + int xoff, yoff; + Bool ok; + + uxa_get_drawable_deltas (pDrawable, pPix, &xoff, &yoff); + + Box.x1 = pDrawable->y + x + xoff; + Box.y1 = pDrawable->y + y + yoff; + Box.x2 = Box.x1 + w; + Box.y2 = Box.y1 + h; + + if (uxa_screen->swappedOut) + goto fallback; + + pPix = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff); + + if (pPix == NULL || uxa_screen->info->DownloadFromScreen == NULL) + goto fallback; + + /* Only cover the ZPixmap, solid copy case. */ + if (format != ZPixmap || !UXA_PM_IS_SOLID(pDrawable, planeMask)) + goto fallback; + + /* Only try to handle the 8bpp and up cases, since we don't want to think + * about <8bpp. + */ + if (pDrawable->bitsPerPixel < 8) + goto fallback; + + ok = uxa_screen->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, + pDrawable->y + y + yoff, w, h, d, + PixmapBytePad(w, pDrawable->depth)); + if (ok) { + uxa_wait_sync(pDrawable->pScreen); + goto out; + } + +fallback: + UXA_FALLBACK(("from %p (%c)\n", pDrawable, + uxa_drawable_location(pDrawable))); + + uxa_prepare_access (pDrawable, UXA_PREPARE_SRC); + fbGetImage (pDrawable, x, y, w, h, format, planeMask, d); + uxa_finish_access (pDrawable, UXA_PREPARE_SRC); + +out: + return; +} diff --git a/uxa/uxa-glyphs.c b/uxa/uxa-glyphs.c new file mode 100644 index 00000000..3c446405 --- /dev/null +++ b/uxa/uxa-glyphs.c @@ -0,0 +1,880 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * Partly based on code Copyright © 2000 SuSE, 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 Red Hat not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat + * 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. + * + * 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 SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * 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. + * + * Author: Owen Taylor + * Based on code by: Keith Packard + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "uxa-priv.h" + +#include "mipict.h" + +#if DEBUG_GLYPH_CACHE +#define DBG_GLYPH_CACHE(a) ErrorF a +#else +#define DBG_GLYPH_CACHE(a) +#endif + +/* Width of the pixmaps we use for the caches; this should be less than + * max texture size of the driver; this may need to actually come from + * the driver. + */ +#define CACHE_PICTURE_WIDTH 1024 + +/* Maximum number of glyphs we buffer on the stack before flushing + * rendering to the mask or destination surface. + */ +#define GLYPH_BUFFER_SIZE 256 + +typedef struct { + PicturePtr source; + uxa_composite_rect_t rects[GLYPH_BUFFER_SIZE]; + int count; +} uxa_glyph_buffer_t; + +typedef enum { + UXA_GLYPH_SUCCESS, /* Glyph added to render buffer */ + UXA_GLYPH_FAIL, /* out of memory, etc */ + UXA_GLYPH_NEED_FLUSH, /* would evict a glyph already in the buffer */ +} uxa_glyph_cache_result_t; + +void +uxa_glyphs_init(ScreenPtr pScreen) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + int i = 0; + + memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches)); + + uxa_screen->glyphCaches[i].format = PICT_a8; + uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 16; + i++; + uxa_screen->glyphCaches[i].format = PICT_a8; + uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 32; + i++; + uxa_screen->glyphCaches[i].format = PICT_a8r8g8b8; + uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 16; + i++; + uxa_screen->glyphCaches[i].format = PICT_a8r8g8b8; + uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 32; + i++; + + assert(i == UXA_NUM_GLYPH_CACHES); + + for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { + uxa_screen->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / uxa_screen->glyphCaches[i].glyphWidth; + uxa_screen->glyphCaches[i].size = 256; + uxa_screen->glyphCaches[i].hashSize = 557; + } +} + +static void +uxa_unrealize_glyph_caches(ScreenPtr pScreen, + unsigned int format) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + int i; + + for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { + uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; + + if (cache->format != format) + continue; + + if (cache->picture) { + FreePicture ((pointer) cache->picture, (XID) 0); + cache->picture = NULL; + } + + if (cache->hashEntries) { + xfree(cache->hashEntries); + cache->hashEntries = NULL; + } + + if (cache->glyphs) { + xfree(cache->glyphs); + cache->glyphs = NULL; + } + cache->glyphCount = 0; + } +} + +/* All caches for a single format share a single pixmap for glyph storage, + * allowing mixing glyphs of different sizes without paying a penalty + * for switching between source pixmaps. (Note that for a size of font + * right at the border between two sizes, we might be switching for almost + * every glyph.) + * + * This function allocates the storage pixmap, and then fills in the + * rest of the allocated structures for all caches with the given format. + */ +static Bool +uxa_realize_glyph_caches(ScreenPtr pScreen, + unsigned int format) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + int depth = PIXMAN_FORMAT_DEPTH(format); + PictFormatPtr pPictFormat; + PixmapPtr pPixmap; + PicturePtr pPicture; + int height; + int i; + int error; + + pPictFormat = PictureMatchFormat(pScreen, depth, format); + if (!pPictFormat) + return FALSE; + + /* Compute the total vertical size needed for the format */ + + height = 0; + for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { + uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; + int rows; + + if (cache->format != format) + continue; + + cache->yOffset = height; + + rows = (cache->size + cache->columns - 1) / cache->columns; + height += rows * cache->glyphHeight; + } + + /* Now allocate the pixmap and picture */ + + pPixmap = (*pScreen->CreatePixmap) (pScreen, + CACHE_PICTURE_WIDTH, + height, depth, 0); + if (!pPixmap) + return FALSE; + + pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, + 0, 0, serverClient, &error); + + (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ + + if (!pPicture) + return FALSE; + + /* And store the picture in all the caches for the format */ + + for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { + uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; + int j; + + if (cache->format != format) + continue; + + cache->picture = pPicture; + cache->picture->refcnt++; + cache->hashEntries = xalloc(sizeof(int) * cache->hashSize); + cache->glyphs = xalloc(sizeof(uxa_cached_glyph_t) * cache->size); + cache->glyphCount = 0; + + if (!cache->hashEntries || !cache->glyphs) + goto bail; + + for (j = 0; j < cache->hashSize; j++) + cache->hashEntries[j] = -1; + + cache->evictionPosition = rand() % cache->size; + } + + /* Each cache references the picture individually */ + FreePicture ((pointer) pPicture, (XID) 0); + return TRUE; + +bail: + uxa_unrealize_glyph_caches(pScreen, format); + return FALSE; +} + +void +uxa_glyphs_fini (ScreenPtr pScreen) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + int i; + + for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { + uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; + + if (cache->picture) + uxa_unrealize_glyph_caches(pScreen, cache->format); + } +} + +static int +uxa_glyph_cache_hash_lookup(uxa_glyph_cache_t *cache, GlyphPtr pGlyph) +{ + int slot; + + slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + int entryPos = cache->hashEntries[slot]; + if (entryPos == -1) + return -1; + + if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){ + return entryPos; + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +static void +uxa_glyph_cache_hash_insert(uxa_glyph_cache_t *cache, + GlyphPtr pGlyph, + int pos) +{ + int slot; + + memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1)); + + slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + if (cache->hashEntries[slot] == -1) { + cache->hashEntries[slot] = pos; + return; + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +static void +uxa_glyph_cache_hash_remove(uxa_glyph_cache_t *cache, + int pos) +{ + int slot; + int emptiedSlot = -1; + + slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize; + + while (TRUE) { /* hash table can never be full */ + int entryPos = cache->hashEntries[slot]; + + if (entryPos == -1) + return; + + if (entryPos == pos) { + cache->hashEntries[slot] = -1; + emptiedSlot = slot; + } else if (emptiedSlot != -1) { + /* See if we can move this entry into the emptied slot, we can't + * do that if if entry would have hashed between the current position + * and the emptied slot. (taking wrapping into account). Bad positions + * are: + * + * | XXXXXXXXXX | + * i j + * + * |XXX XXXX| + * j i + * + * i - slot, j - emptiedSlot + * + * (Knuth 6.4R) + */ + + int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize; + + if (!((entrySlot >= slot && entrySlot < emptiedSlot) || + (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot)))) + { + cache->hashEntries[emptiedSlot] = entryPos; + cache->hashEntries[slot] = -1; + emptiedSlot = slot; + } + } + + slot--; + if (slot < 0) + slot = cache->hashSize - 1; + } +} + +#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) +#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) + +/* The most efficient thing to way to upload the glyph to the screen + * is to use the UploadToScreen() driver hook; this allows us to + * pipeline glyph uploads and to avoid creating offscreen pixmaps for + * glyphs that we'll never use again. + */ +static Bool +uxa_glyph_cache_upload_glyph(ScreenPtr pScreen, + uxa_glyph_cache_t *cache, + int pos, + GlyphPtr pGlyph) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; + PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable; + PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable; + int cacheXoff, cacheYoff; + + if (!uxa_screen->info->UploadToScreen || uxa_screen->swappedOut) + return FALSE; + + /* If the glyph pixmap is already uploaded, no point in doing + * things this way */ + if (uxa_pixmap_is_offscreen(pGlyphPixmap)) + return FALSE; + + /* UploadToScreen only works if bpp match */ + if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel) + return FALSE; + + pCachePixmap = uxa_get_offscreen_pixmap ((DrawablePtr)pCachePixmap, &cacheXoff, &cacheYoff); + if (!pCachePixmap) + return FALSE; + + if (!uxa_screen->info->UploadToScreen(pCachePixmap, + CACHE_X(pos) + cacheXoff, + CACHE_Y(pos) + cacheYoff, + pGlyph->info.width, + pGlyph->info.height, + (char *)pGlyphPixmap->devPrivate.ptr, + pGlyphPixmap->devKind)) + return FALSE; + + return TRUE; +} + +static uxa_glyph_cache_result_t +uxa_glyph_cache_buffer_glyph(ScreenPtr pScreen, + uxa_glyph_cache_t *cache, + uxa_glyph_buffer_t *buffer, + GlyphPtr pGlyph, + int xGlyph, + int yGlyph) +{ + uxa_composite_rect_t *rect; + int pos; + + if (buffer->source && buffer->source != cache->picture) + return UXA_GLYPH_NEED_FLUSH; + + if (!cache->picture) { + if (!uxa_realize_glyph_caches(pScreen, cache->format)) + return UXA_GLYPH_FAIL; + } + + DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", + cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB", + (long)*(CARD32 *) pGlyph->sha1)); + + pos = uxa_glyph_cache_hash_lookup(cache, pGlyph); + if (pos != -1) { + DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); + } else { + if (cache->glyphCount < cache->size) { + /* Space remaining; we fill from the start */ + pos = cache->glyphCount; + cache->glyphCount++; + DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); + + uxa_glyph_cache_hash_insert(cache, pGlyph, pos); + + } else { + /* Need to evict an entry. We have to see if any glyphs + * already in the output buffer were at this position in + * the cache + */ + + pos = cache->evictionPosition; + DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); + if (buffer->count) { + int x, y; + int i; + + x = CACHE_X(pos); + y = CACHE_Y(pos); + + for (i = 0; i < buffer->count; i++) { + if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) { + DBG_GLYPH_CACHE((" must flush buffer\n")); + return UXA_GLYPH_NEED_FLUSH; + } + } + } + + /* OK, we're all set, swap in the new glyph */ + uxa_glyph_cache_hash_remove(cache, pos); + uxa_glyph_cache_hash_insert(cache, pGlyph, pos); + + /* And pick a new eviction position */ + cache->evictionPosition = rand() % cache->size; + } + + /* Now actually upload the glyph into the cache picture; if + * we can't do it with UploadToScreen (because the glyph is + * offscreen, etc), we fall back to CompositePicture. + */ + if (!uxa_glyph_cache_upload_glyph(pScreen, cache, pos, pGlyph)) { + CompositePicture (PictOpSrc, + GlyphPicture(pGlyph)[pScreen->myNum], + None, + cache->picture, + 0, 0, + 0, 0, + CACHE_X(pos), + CACHE_Y(pos), + pGlyph->info.width, + pGlyph->info.height); + } + + } + + + buffer->source = cache->picture; + + rect = &buffer->rects[buffer->count]; + rect->xSrc = CACHE_X(pos); + rect->ySrc = CACHE_Y(pos); + rect->xDst = xGlyph - pGlyph->info.x; + rect->yDst = yGlyph - pGlyph->info.y; + rect->width = pGlyph->info.width; + rect->height = pGlyph->info.height; + + buffer->count++; + + return UXA_GLYPH_SUCCESS; +} + +#undef CACHE_X +#undef CACHE_Y + +static uxa_glyph_cache_result_t +uxa_buffer_glyph(ScreenPtr pScreen, + uxa_glyph_buffer_t *buffer, + GlyphPtr pGlyph, + int xGlyph, + int yGlyph) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; + int width = pGlyph->info.width; + int height = pGlyph->info.height; + uxa_composite_rect_t *rect; + PicturePtr source; + int i; + + if (buffer->count == GLYPH_BUFFER_SIZE) + return UXA_GLYPH_NEED_FLUSH; + + if (PICT_FORMAT_BPP(format) == 1) + format = PICT_a8; + + for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) { + uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; + + if (format == cache->format && + width <= cache->glyphWidth && + height <= cache->glyphHeight) { + uxa_glyph_cache_result_t result = uxa_glyph_cache_buffer_glyph(pScreen, &uxa_screen->glyphCaches[i], + buffer, + pGlyph, xGlyph, yGlyph); + switch (result) { + case UXA_GLYPH_FAIL: + break; + case UXA_GLYPH_SUCCESS: + case UXA_GLYPH_NEED_FLUSH: + return result; + } + } + } + + /* Couldn't find the glyph in the cache, use the glyph picture directly */ + + source = GlyphPicture(pGlyph)[pScreen->myNum]; + if (buffer->source && buffer->source != source) + return UXA_GLYPH_NEED_FLUSH; + + buffer->source = source; + + rect = &buffer->rects[buffer->count]; + rect->xSrc = 0; + rect->ySrc = 0; + rect->xDst = xGlyph - pGlyph->info.x; + rect->yDst = yGlyph - pGlyph->info.y; + rect->width = pGlyph->info.width; + rect->height = pGlyph->info.height; + + buffer->count++; + + return UXA_GLYPH_SUCCESS; +} + +static void +uxa_glyphs_to_mask(PicturePtr pMask, + uxa_glyph_buffer_t *buffer) +{ + uxa_composite_rects(PictOpAdd, buffer->source, pMask, + buffer->count, buffer->rects); + + buffer->count = 0; + buffer->source = NULL; +} + +static void +uxa_glyphs_to_dst(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + uxa_glyph_buffer_t *buffer, + INT16 xSrc, + INT16 ySrc, + INT16 xDst, + INT16 yDst) +{ + int i; + + for (i = 0; i < buffer->count; i++) { + uxa_composite_rect_t *rect = &buffer->rects[i]; + + CompositePicture (op, + pSrc, + buffer->source, + pDst, + xSrc + rect->xDst - xDst, + ySrc + rect->yDst - yDst, + rect->xSrc, + rect->ySrc, + rect->xDst, + rect->yDst, + rect->width, + rect->height); + } + + buffer->count = 0; + buffer->source = NULL; +} + +/* Cut and paste from render/glyph.c - probably should export it instead */ +static void +uxa_glyph_extents (int nlist, + GlyphListPtr list, + GlyphPtr *glyphs, + BoxPtr extents) +{ + int x1, x2, y1, y2; + int n; + GlyphPtr glyph; + int x, y; + + x = 0; + y = 0; + extents->x1 = MAXSHORT; + extents->x2 = MINSHORT; + extents->y1 = MAXSHORT; + extents->y2 = MINSHORT; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + list++; + while (n--) + { + glyph = *glyphs++; + x1 = x - glyph->info.x; + if (x1 < MINSHORT) + x1 = MINSHORT; + y1 = y - glyph->info.y; + if (y1 < MINSHORT) + y1 = MINSHORT; + x2 = x1 + glyph->info.width; + if (x2 > MAXSHORT) + x2 = MAXSHORT; + y2 = y1 + glyph->info.height; + if (y2 > MAXSHORT) + y2 = MAXSHORT; + if (x1 < extents->x1) + extents->x1 = x1; + if (x2 > extents->x2) + extents->x2 = x2; + if (y1 < extents->y1) + extents->y1 = y1; + if (y2 > extents->y2) + extents->y2 = y2; + x += glyph->info.xOff; + y += glyph->info.yOff; + } + } +} + +/** + * Returns TRUE if the glyphs in the lists intersect. Only checks based on + * bounding box, which appears to be good enough to catch most cases at least. + */ +static Bool +uxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs) +{ + int x1, x2, y1, y2; + int n; + GlyphPtr glyph; + int x, y; + BoxRec extents; + Bool first = TRUE; + + x = 0; + y = 0; + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + list++; + while (n--) { + glyph = *glyphs++; + + if (glyph->info.width == 0 || glyph->info.height == 0) { + x += glyph->info.xOff; + y += glyph->info.yOff; + continue; + } + + x1 = x - glyph->info.x; + if (x1 < MINSHORT) + x1 = MINSHORT; + y1 = y - glyph->info.y; + if (y1 < MINSHORT) + y1 = MINSHORT; + x2 = x1 + glyph->info.width; + if (x2 > MAXSHORT) + x2 = MAXSHORT; + y2 = y1 + glyph->info.height; + if (y2 > MAXSHORT) + y2 = MAXSHORT; + + if (first) { + extents.x1 = x1; + extents.y1 = y1; + extents.x2 = x2; + extents.y2 = y2; + first = FALSE; + } else { + if (x1 < extents.x2 && x2 > extents.x1 && + y1 < extents.y2 && y2 > extents.y1) + { + return TRUE; + } + + if (x1 < extents.x1) + extents.x1 = x1; + if (x2 > extents.x2) + extents.x2 = x2; + if (y1 < extents.y1) + extents.y1 = y1; + if (y2 > extents.y2) + extents.y2 = y2; + } + x += glyph->info.xOff; + y += glyph->info.yOff; + } + } + + return FALSE; +} + +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) + +void +uxa_glyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ + PicturePtr pPicture; + PixmapPtr pMaskPixmap = 0; + PicturePtr pMask; + ScreenPtr pScreen = pDst->pDrawable->pScreen; + int width = 0, height = 0; + int x, y; + int xDst = list->xOff, yDst = list->yOff; + int n; + GlyphPtr glyph; + int error; + BoxRec extents = {0, 0, 0, 0}; + CARD32 component_alpha; + uxa_glyph_buffer_t buffer; + + /* If we don't have a mask format but all the glyphs have the same format + * and don't intersect, use the glyph format as mask format for the full + * benefits of the glyph cache. + */ + if (!maskFormat) { + Bool sameFormat = TRUE; + int i; + + maskFormat = list[0].format; + + for (i = 0; i < nlist; i++) { + if (maskFormat->format != list[i].format->format) { + sameFormat = FALSE; + break; + } + } + + if (!sameFormat || (maskFormat->depth != 1 && + uxa_glyphs_intersect(nlist, list, glyphs))) { + maskFormat = NULL; + } + } + + if (maskFormat) + { + GCPtr pGC; + xRectangle rect; + + uxa_glyph_extents (nlist, list, glyphs, &extents); + + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) + return; + width = extents.x2 - extents.x1; + height = extents.y2 - extents.y1; + + if (maskFormat->depth == 1) { + PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8); + + if (a8Format) + maskFormat = a8Format; + } + + pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pMaskPixmap) + return; + component_alpha = NeedsComponent(maskFormat->format); + pMask = CreatePicture (0, &pMaskPixmap->drawable, + maskFormat, CPComponentAlpha, &component_alpha, + serverClient, &error); + if (!pMask) + { + (*pScreen->DestroyPixmap) (pMaskPixmap); + return; + } + pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); + ValidateGC (&pMaskPixmap->drawable, pGC); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); + FreeScratchGC (pGC); + x = -extents.x1; + y = -extents.y1; + } + else + { + pMask = pDst; + x = 0; + y = 0; + } + buffer.count = 0; + buffer.source = NULL; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) + { + glyph = *glyphs++; + pPicture = GlyphPicture (glyph)[pScreen->myNum]; + + if (glyph->info.width > 0 && glyph->info.height > 0 && + uxa_buffer_glyph(pScreen, &buffer, glyph, x, y) == UXA_GLYPH_NEED_FLUSH) + { + if (maskFormat) + uxa_glyphs_to_mask(pMask, &buffer); + else + uxa_glyphs_to_dst(op, pSrc, pDst, &buffer, + xSrc, ySrc, xDst, yDst); + + uxa_buffer_glyph(pScreen, &buffer, glyph, x, y); + } + + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + + if (maskFormat) + uxa_glyphs_to_mask(pMask, &buffer); + else + uxa_glyphs_to_dst(op, pSrc, pDst, &buffer, + xSrc, ySrc, xDst, yDst); + + if (maskFormat) + { + x = extents.x1; + y = extents.y1; + CompositePicture (op, + pSrc, + pMask, + pDst, + xSrc + x - xDst, + ySrc + y - yDst, + 0, 0, + x, y, + width, height); + FreePicture ((pointer) pMask, (XID) 0); + (*pScreen->DestroyPixmap) (pMaskPixmap); + } +} diff --git a/uxa/uxa-priv.h b/uxa/uxa-priv.h new file mode 100644 index 00000000..acc82bba --- /dev/null +++ b/uxa/uxa-priv.h @@ -0,0 +1,444 @@ +/* + * + * Copyright © 2000,2008 Keith Packard + * 2005 Zack Rusin, Trolltech + * + * 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes 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. + */ + +#ifndef UXAPRIV_H +#define UXAPRIV_H + +#ifdef HAVE_DIX_CONFIG_H +#include +#else +#include +#endif + +#include "uxa.h" + +#include +#define NEED_EVENTS +#include +#ifdef MITSHM +#define _XSHM_SERVER_ +#include +#endif +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "servermd.h" +#include "mibstore.h" +#include "colormapst.h" +#include "gcstruct.h" +#include "input.h" +#include "mipointer.h" +#include "mi.h" +#include "dix.h" +#include "fb.h" +#include "fboverlay.h" +#ifdef RENDER +//#include "fbpict.h" +#include "glyphstr.h" +#endif +#include "damage.h" + +#define DEBUG_TRACE_FALL 0 +#define DEBUG_MIGRATE 0 +#define DEBUG_PIXMAP 0 +#define DEBUG_OFFSCREEN 0 +#define DEBUG_GLYPH_CACHE 0 + +#if DEBUG_TRACE_FALL +#define UXA_FALLBACK(x) \ +do { \ + ErrorF("UXA fallback at %s: ", __FUNCTION__); \ + ErrorF x; \ +} while (0) + +char +uxa_drawable_location(DrawablePtr pDrawable); +#else +#define UXA_FALLBACK(x) +#endif + +#if DEBUG_PIXMAP +#define DBG_PIXMAP(a) ErrorF a +#else +#define DBG_PIXMAP(a) +#endif + +typedef struct { + unsigned char sha1[20]; +} uxa_cached_glyph_t; + +typedef struct { + /* The identity of the cache, statically configured at initialization */ + unsigned int format; + int glyphWidth; + int glyphHeight; + + int size; /* Size of cache; eventually this should be dynamically determined */ + + /* Hash table mapping from glyph sha1 to position in the glyph; we use + * open addressing with a hash table size determined based on size and large + * enough so that we always have a good amount of free space, so we can + * use linear probing. (Linear probing is preferrable to double hashing + * here because it allows us to easily remove entries.) + */ + int *hashEntries; + int hashSize; + + uxa_cached_glyph_t *glyphs; + int glyphCount; /* Current number of glyphs */ + + PicturePtr picture; /* Where the glyphs of the cache are stored */ + int yOffset; /* y location within the picture where the cache starts */ + int columns; /* Number of columns the glyphs are layed out in */ + int evictionPosition; /* Next random position to evict a glyph */ +} uxa_glyph_cache_t; + +#define UXA_NUM_GLYPH_CACHES 4 + +typedef void (*EnableDisableFBAccessProcPtr)(int, Bool); +typedef struct { + uxa_driver_t *info; + CreateGCProcPtr SavedCreateGC; + CloseScreenProcPtr SavedCloseScreen; + GetImageProcPtr SavedGetImage; + GetSpansProcPtr SavedGetSpans; + CreatePixmapProcPtr SavedCreatePixmap; + DestroyPixmapProcPtr SavedDestroyPixmap; + CopyWindowProcPtr SavedCopyWindow; + ChangeWindowAttributesProcPtr SavedChangeWindowAttributes; + BitmapToRegionProcPtr SavedBitmapToRegion; +#ifdef RENDER + CompositeProcPtr SavedComposite; + TrianglesProcPtr SavedTriangles; + GlyphsProcPtr SavedGlyphs; + TrapezoidsProcPtr SavedTrapezoids; + AddTrapsProcPtr SavedAddTraps; +#endif + + Bool swappedOut; + unsigned disableFbCount; + unsigned offScreenCounter; + + uxa_glyph_cache_t glyphCaches[UXA_NUM_GLYPH_CACHES]; +} uxa_screen_t; + +/* + * This is the only completely portable way to + * compute this info. + */ +#ifndef BitsPerPixel +#define BitsPerPixel(d) (\ + PixmapWidthPaddingInfo[d].notPower2 ? \ + (PixmapWidthPaddingInfo[d].bytesPerPixel * 8) : \ + ((1 << PixmapWidthPaddingInfo[d].padBytesLog2) * 8 / \ + (PixmapWidthPaddingInfo[d].padRoundUp+1))) +#endif + +extern DevPrivateKey uxa_screen_key; +#define uxa_get_screen(s) ((uxa_screen_t *)dixLookupPrivate(&(s)->devPrivates, uxa_screen_key)) + +/** Align an offset to an arbitrary alignment */ +#define UXA_ALIGN(offset, align) (((offset) + (align) - 1) - \ + (((offset) + (align) - 1) % (align))) +/** Align an offset to a power-of-two alignment */ +#define UXA_ALIGN2(offset, align) (((offset) + (align) - 1) & ~((align) - 1)) + +typedef struct { + INT16 xSrc; + INT16 ySrc; + INT16 xDst; + INT16 yDst; + INT16 width; + INT16 height; +} uxa_composite_rect_t; + +/** + * exaDDXDriverInit must be implemented by the DDX using EXA, and is the place + * to set EXA options or hook in screen functions to handle using EXA as the AA. + */ +void exaDDXDriverInit (ScreenPtr pScreen); + +void +uxa_prepare_access_window(WindowPtr pWin); + +void +uxa_finish_access_window(WindowPtr pWin); + +/* uxa-unaccel.c */ +void +uxa_prepare_access_gc(GCPtr pGC); + +void +uxa_finish_access_gc(GCPtr pGC); + +void +uxa_check_fill_spans (DrawablePtr pDrawable, GCPtr pGC, int nspans, + DDXPointPtr ppt, int *pwidth, int fSorted); + +void +uxa_check_set_spans (DrawablePtr pDrawable, GCPtr pGC, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, int fSorted); + +void +uxa_check_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, int format, + char *bits); + +RegionPtr +uxa_check_copy_area (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int w, int h, int dstx, int dsty); + +RegionPtr +uxa_check_copy_plane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int w, int h, int dstx, int dsty, + unsigned long bitPlane); + +void +uxa_check_poly_point (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr pptInit); + +void +uxa_check_poly_lines (DrawablePtr pDrawable, GCPtr pGC, + int mode, int npt, DDXPointPtr ppt); + +void +uxa_check_poly_segment (DrawablePtr pDrawable, GCPtr pGC, + int nsegInit, xSegment *pSegInit); + +void +uxa_check_poly_arc (DrawablePtr pDrawable, GCPtr pGC, + int narcs, xArc *pArcs); + +void +uxa_check_poly_fill_rect (DrawablePtr pDrawable, GCPtr pGC, + int nrect, xRectangle *prect); + +void +uxa_check_image_glyph_blt (DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase); + +void +uxa_check_poly_glyph_blt (DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase); + +void +uxa_check_push_pixels (GCPtr pGC, PixmapPtr pBitmap, + DrawablePtr pDrawable, + int w, int h, int x, int y); + +void +uxa_check_get_spans (DrawablePtr pDrawable, + int wMax, + DDXPointPtr ppt, + int *pwidth, + int nspans, + char *pdstStart); + +void +uxa_check_add_traps (PicturePtr pPicture, + INT16 x_off, + INT16 y_off, + int ntrap, + xTrap *traps); + +/* uxa-accel.c */ + +static _X_INLINE Bool +uxa_gc_reads_destination(DrawablePtr pDrawable, unsigned long planemask, + unsigned int fillStyle, unsigned char alu) +{ + return ((alu != GXcopy && alu != GXclear &&alu != GXset && + alu != GXcopyInverted) || fillStyle == FillStippled || + !UXA_PM_IS_SOLID(pDrawable, planemask)); +} + +void +uxa_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc); + +Bool +uxa_fill_region_tiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile, + DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu); + +void +uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format, + int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, + char *data); + +void +uxa_get_image (DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d); + +extern const GCOps uxa_ops; + +#ifdef MITSHM +extern ShmFuncs uxa_shm_funcs; + +/* XXX these come from shmint.h, which isn't exported by the server */ +void +ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs); + +void +ShmSetPixmapFormat(ScreenPtr pScreen, int format); + +void +fbShmPutImage(XSHM_PUT_IMAGE_ARGS); + +#endif + +#ifdef RENDER + +/* XXX these are in fbpict.h, which is not installed */ +void +fbComposite (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); + +void +fbAddTraps (PicturePtr pPicture, + INT16 xOff, + INT16 yOff, + int ntrap, + xTrap *traps); + +void +uxa_check_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); +#endif + +/* uxa.c */ +void +uxa_prepare_access(DrawablePtr pDrawable, int index); + +void +uxa_finish_access(DrawablePtr pDrawable, int index); + +void +uxa_get_drawable_deltas (DrawablePtr pDrawable, PixmapPtr pPixmap, + int *xp, int *yp); + +Bool +uxa_drawable_is_offscreen (DrawablePtr pDrawable); + +Bool +uxa_pixmap_is_offscreen(PixmapPtr p); + +PixmapPtr +uxa_get_offscreen_pixmap (DrawablePtr pDrawable, int *xp, int *yp); + +PixmapPtr +uxa_get_drawable_pixmap(DrawablePtr pDrawable); + +RegionPtr +uxa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC, + int srcx, int srcy, int width, int height, int dstx, int dsty); + +void +uxa_copy_n_to_n (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown, + Pixel bitplane, + void *closure); + +/* uxa_render.c */ +Bool +uxa_op_reads_destination (CARD8 op); + +void +uxa_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); + +void +uxa_composite_rects(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + int nrect, + uxa_composite_rect_t *rects); + +void +uxa_trapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps); + +void +uxa_triangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tris); + +/* uxa_glyph.c */ +void +uxa_glyphs_init(ScreenPtr pScreen); + +void +uxa_glyphs_fini (ScreenPtr pScreen); + +void +uxa_glyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs); + +#endif /* UXAPRIV_H */ diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c new file mode 100644 index 00000000..38e6088f --- /dev/null +++ b/uxa/uxa-render.c @@ -0,0 +1,1052 @@ +/* + * Copyright © 2001 Keith Packard + * + * 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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_DIX_CONFIG_H +#include +#endif + +#include + +#include "uxa-priv.h" + +#ifdef RENDER +#include "mipict.h" + +#if DEBUG_TRACE_FALL +static void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string, int n) +{ + char format[20]; + char size[20]; + char loc; + int temp; + + if (!pict) { + snprintf(string, n, "None"); + return; + } + + switch (pict->format) + { + case PICT_a8r8g8b8: + snprintf(format, 20, "ARGB8888"); + break; + case PICT_x8r8g8b8: + snprintf(format, 20, "XRGB8888"); + break; + case PICT_r5g6b5: + snprintf(format, 20, "RGB565 "); + break; + case PICT_x1r5g5b5: + snprintf(format, 20, "RGB555 "); + break; + case PICT_a8: + snprintf(format, 20, "A8 "); + break; + case PICT_a1: + snprintf(format, 20, "A1 "); + break; + default: + snprintf(format, 20, "0x%x", (int)pict->format); + break; + } + + loc = uxa_get_drawable_pixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; + + snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, + pict->pDrawable->height, pict->repeat ? + " R" : ""); + + snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size); +} + +static void +uxa_print_composite_fallback(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst) +{ + char sop[20]; + char srcdesc[40], maskdesc[40], dstdesc[40]; + + switch(op) + { + case PictOpSrc: + sprintf(sop, "Src"); + break; + case PictOpOver: + sprintf(sop, "Over"); + break; + default: + sprintf(sop, "0x%x", (int)op); + break; + } + + uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40); + uxa_composite_fallback_pict_desc(pMask, maskdesc, 40); + uxa_composite_fallback_pict_desc(pDst, dstdesc, 40); + + ErrorF("Composite fallback: op %s, \n" + " src %s, \n" + " mask %s, \n" + " dst %s, \n", + sop, srcdesc, maskdesc, dstdesc); +} +#endif /* DEBUG_TRACE_FALL */ + +Bool +uxa_op_reads_destination (CARD8 op) +{ + /* FALSE (does not read destination) is the list of ops in the protocol + * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. + * That's just Clear and Src. ReduceCompositeOp() will already have + * converted con/disjoint clear/src to Clear or Src. + */ + switch (op) { + case PictOpClear: + case PictOpSrc: + return FALSE; + default: + return TRUE; + } +} + + +static Bool +uxa_get_pixel_from_rgba(CARD32 *pixel, + CARD16 red, + CARD16 green, + CARD16 blue, + CARD16 alpha, + CARD32 format) +{ + int rbits, bbits, gbits, abits; + int rshift, bshift, gshift, ashift; + + *pixel = 0; + + if (!PICT_FORMAT_COLOR(format)) + return FALSE; + + rbits = PICT_FORMAT_R(format); + gbits = PICT_FORMAT_G(format); + bbits = PICT_FORMAT_B(format); + abits = PICT_FORMAT_A(format); + + if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { + bshift = 0; + gshift = bbits; + rshift = gshift + gbits; + ashift = rshift + rbits; + } else { /* PICT_TYPE_ABGR */ + rshift = 0; + gshift = rbits; + bshift = gshift + gbits; + ashift = bshift + bbits; + } + + *pixel |= ( blue >> (16 - bbits)) << bshift; + *pixel |= ( red >> (16 - rbits)) << rshift; + *pixel |= (green >> (16 - gbits)) << gshift; + *pixel |= (alpha >> (16 - abits)) << ashift; + + return TRUE; +} + +static Bool +uxa_get_rgba_from_pixel(CARD32 pixel, + CARD16 *red, + CARD16 *green, + CARD16 *blue, + CARD16 *alpha, + CARD32 format) +{ + int rbits, bbits, gbits, abits; + int rshift, bshift, gshift, ashift; + + if (!PICT_FORMAT_COLOR(format)) + return FALSE; + + rbits = PICT_FORMAT_R(format); + gbits = PICT_FORMAT_G(format); + bbits = PICT_FORMAT_B(format); + abits = PICT_FORMAT_A(format); + + if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { + bshift = 0; + gshift = bbits; + rshift = gshift + gbits; + ashift = rshift + rbits; + } else { /* PICT_TYPE_ABGR */ + rshift = 0; + gshift = rbits; + bshift = gshift + gbits; + ashift = bshift + bbits; + } + + *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); + while (rbits < 16) { + *red |= *red >> rbits; + rbits <<= 1; + } + + *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); + while (gbits < 16) { + *green |= *green >> gbits; + gbits <<= 1; + } + + *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); + while (bbits < 16) { + *blue |= *blue >> bbits; + bbits <<= 1; + } + + if (abits) { + *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); + while (abits < 16) { + *alpha |= *alpha >> abits; + abits <<= 1; + } + } else + *alpha = 0xffff; + + return TRUE; +} + +static int +uxa_try_driver_solid_fill(PicturePtr pSrc, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + RegionRec region; + BoxPtr pbox; + int nbox; + int dst_off_x, dst_off_y; + PixmapPtr pSrcPix, pDstPix; + CARD32 pixel; + CARD16 red, green, blue, alpha; + + pDstPix = uxa_get_drawable_pixmap (pDst->pDrawable); + pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable); + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, + xSrc, ySrc, 0, 0, xDst, yDst, + width, height)) + return 1; + + uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); + + REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + + pixel = uxa_get_pixmap_first_pixel (pSrcPix); + + if (!uxa_pixmap_is_offscreen(pDstPix)) { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 0; + } + + if (!uxa_get_rgba_from_pixel(pixel, &red, &green, &blue, &alpha, + pSrc->format)) + { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return -1; + } + + if (!uxa_get_pixel_from_rgba(&pixel, red, green, blue, alpha, + pDst->format)) + { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return -1; + } + + if (!(*uxa_screen->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) + { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return -1; + } + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + while (nbox--) + { + (*uxa_screen->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2); + pbox++; + } + + (*uxa_screen->info->DoneSolid) (pDstPix); + uxa_mark_sync(pDst->pDrawable->pScreen); + + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 1; +} + +static int +uxa_try_driver_composite_rects(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + int nrect, + uxa_composite_rect_t *rects) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + int src_off_x, src_off_y, dst_off_x, dst_off_y; + PixmapPtr pSrcPix, pDstPix; + struct _Pixmap scratch; + + if (!uxa_screen->info->PrepareComposite) + return -1; + + pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable); + + pDstPix = uxa_get_drawable_pixmap(pDst->pDrawable); + + if (uxa_screen->info->CheckComposite && + !(*uxa_screen->info->CheckComposite) (op, pSrc, NULL, pDst)) + { + return -1; + } + + uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); + + pSrcPix = uxa_get_offscreen_pixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (!uxa_pixmap_is_offscreen(pDstPix)) + return 0; + + if (!pSrcPix && uxa_screen->info->UploadToScratch) + { + pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable); + if ((*uxa_screen->info->UploadToScratch) (pSrcPix, &scratch)) + pSrcPix = &scratch; + } + + if (!pSrcPix) + return 0; + + if (!(*uxa_screen->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix, + NULL, pDstPix)) + return -1; + + while (nrect--) + { + INT16 xDst = rects->xDst + pDst->pDrawable->x; + INT16 yDst = rects->yDst + pDst->pDrawable->y; + INT16 xSrc = rects->xSrc + pSrc->pDrawable->x; + INT16 ySrc = rects->ySrc + pSrc->pDrawable->y; + + RegionRec region; + BoxPtr pbox; + int nbox; + + if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, + xSrc, ySrc, 0, 0, xDst, yDst, + rects->width, rects->height)) + goto next_rect; + + REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + xSrc = xSrc + src_off_x - xDst - dst_off_x; + ySrc = ySrc + src_off_y - yDst - dst_off_y; + + while (nbox--) + { + (*uxa_screen->info->Composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + 0, 0, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + + next_rect: + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + rects++; + } + + (*uxa_screen->info->DoneComposite) (pDstPix); + uxa_mark_sync(pDst->pDrawable->pScreen); + + return 1; +} + +/** + * Copy a number of rectangles from source to destination in a single + * operation. This is specialized for building a glyph mask: we don'y + * have a mask argument because we don't need it for that, and we + * don't have he special-case fallbacks found in uxa_composite() - if the + * driver can support it, we use the driver functionality, otherwise we + * fallback straight to software. + */ +void +uxa_composite_rects(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + int nrect, + uxa_composite_rect_t *rects) +{ + int n; + uxa_composite_rect_t *r; + + /************************************************************/ + + ValidatePicture (pSrc); + ValidatePicture (pDst); + + if (uxa_try_driver_composite_rects(op, pSrc, pDst, nrect, rects) != 1) { + n = nrect; + r = rects; + while (n--) { + uxa_check_composite (op, pSrc, NULL, pDst, + r->xSrc, r->ySrc, + 0, 0, + r->xDst, r->yDst, + r->width, r->height); + r++; + } + } + + /************************************************************/ + +} + +static int +uxa_try_driver_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) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + RegionRec region; + BoxPtr pbox; + int nbox; + int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; + PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; + struct _Pixmap scratch; + + pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable); + pDstPix = uxa_get_drawable_pixmap(pDst->pDrawable); + if (pMask) + pMaskPix = uxa_get_drawable_pixmap(pMask->pDrawable); + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + + if (pMask) { + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + } + + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + if (uxa_screen->info->CheckComposite && + !(*uxa_screen->info->CheckComposite) (op, pSrc, pMask, pDst)) + { + return -1; + } + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height)) + return 1; + + uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); + + REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + + pSrcPix = uxa_get_offscreen_pixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (pMask) + pMaskPix = uxa_get_offscreen_pixmap (pMask->pDrawable, &mask_off_x, + &mask_off_y); + + if (!uxa_pixmap_is_offscreen(pDstPix)) { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 0; + } + + if (!pSrcPix && (!pMask || pMaskPix) && uxa_screen->info->UploadToScratch) { + pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable); + if ((*uxa_screen->info->UploadToScratch) (pSrcPix, &scratch)) + pSrcPix = &scratch; + } else if (pSrcPix && pMask && !pMaskPix && uxa_screen->info->UploadToScratch) { + pMaskPix = uxa_get_drawable_pixmap (pMask->pDrawable); + if ((*uxa_screen->info->UploadToScratch) (pMaskPix, &scratch)) + pMaskPix = &scratch; + } + + if (!pSrcPix || (pMask && !pMaskPix)) { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 0; + } + + if (!(*uxa_screen->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, + pMaskPix, pDstPix)) + { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return -1; + } + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + xMask = xMask + mask_off_x - xDst - dst_off_x; + yMask = yMask + mask_off_y - yDst - dst_off_y; + + xSrc = xSrc + src_off_x - xDst - dst_off_x; + ySrc = ySrc + src_off_y - yDst - dst_off_y; + + while (nbox--) + { + (*uxa_screen->info->Composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + pbox->x1 + xMask, + pbox->y1 + yMask, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + (*uxa_screen->info->DoneComposite) (pDstPix); + uxa_mark_sync(pDst->pDrawable->pScreen); + + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 1; +} + +/** + * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of + * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component + * alpha and limited 1-tmu cards. + * + * From http://anholt.livejournal.com/32058.html: + * + * The trouble is that component-alpha rendering requires two different sources + * for blending: one for the source value to the blender, which is the + * per-channel multiplication of source and mask, and one for the source alpha + * for multiplying with the destination channels, which is the multiplication + * of the source channels by the mask alpha. So the equation for Over is: + * + * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A + * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R + * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G + * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B + * + * But we can do some simpler operations, right? How about PictOpOutReverse, + * which has a source factor of 0 and dest factor of (1 - source alpha). We + * can get the source alpha value (srca.X = src.A * mask.X) out of the texture + * blenders pretty easily. So we can do a component-alpha OutReverse, which + * gets us: + * + * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A + * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R + * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G + * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B + * + * OK. And if an op doesn't use the source alpha value for the destination + * factor, then we can do the channel multiplication in the texture blenders + * to get the source value, and ignore the source alpha that we wouldn't use. + * We've supported this in the Radeon driver for a long time. An example would + * be PictOpAdd, which does: + * + * dst.A = src.A * mask.A + dst.A + * dst.R = src.R * mask.R + dst.R + * dst.G = src.G * mask.G + dst.G + * dst.B = src.B * mask.B + dst.B + * + * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right + * after it, we get: + * + * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) + * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) + * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) + * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) + */ + +static int +uxa_try_magic_two_pass_composite_helper(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + + assert(op == PictOpOver); + + if (uxa_screen->info->CheckComposite && + (!(*uxa_screen->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, + pDst) || + !(*uxa_screen->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst))) + { + return -1; + } + + /* Now, we think we should be able to accelerate this operation. First, + * composite the destination to be the destination times the source alpha + * factors. + */ + uxa_composite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + + /* Then, add in the source value times the destination alpha factors (1.0). + */ + uxa_composite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + + return 1; +} + +void +uxa_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) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + int ret = -1; + Bool saveSrcRepeat = pSrc->repeat; + Bool saveMaskRepeat = pMask ? pMask->repeat : 0; + RegionRec region; + + /* We currently don't support acceleration of gradients, or other pictures + * with a NULL pDrawable. + */ + if (uxa_screen->swappedOut || + pSrc->pDrawable == NULL || (pMask != NULL && pMask->pDrawable == NULL)) + { + goto fallback; + } + + /* Remove repeat in source if useless */ + if (pSrc->repeat && !pSrc->transform && xSrc >= 0 && + (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && + (ySrc + height) <= pSrc->pDrawable->height) + pSrc->repeat = 0; + + if (!pMask) + { + if ((op == PictOpSrc && + ((pSrc->format == pDst->format) || + (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) || + (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) || + (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap && + pSrc->format == pDst->format && + (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8))) + { + if (pSrc->pDrawable->width == 1 && + pSrc->pDrawable->height == 1 && + pSrc->repeat) + { + ret = uxa_try_driver_solid_fill(pSrc, pDst, xSrc, ySrc, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } + else if (pSrc->pDrawable != NULL && + !pSrc->repeat && + !pSrc->transform) + { + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, + yDst, width, height)) + goto done; + + + uxa_copy_n_to_n (pSrc->pDrawable, pDst->pDrawable, NULL, + REGION_RECTS(®ion), REGION_NUM_RECTS(®ion), + xSrc - xDst, ySrc - yDst, + FALSE, FALSE, 0, NULL); + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + goto done; + } + else if (pSrc->pDrawable != NULL && + pSrc->pDrawable->type == DRAWABLE_PIXMAP && + !pSrc->transform && + pSrc->repeatType == RepeatNormal) + { + DDXPointRec patOrg; + + /* Let's see if the driver can do the repeat in one go */ + if (uxa_screen->info->PrepareComposite && !pSrc->alphaMap && + !pDst->alphaMap) + { + ret = uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, + ySrc, xMask, yMask, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } + + /* Now see if we can use uxa_fill_region_tiled() */ + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, + ySrc, xMask, yMask, xDst, yDst, + width, height)) + goto done; + + /* pattern origin is the point in the destination drawable + * corresponding to (0,0) in the source */ + patOrg.x = xDst - xSrc; + patOrg.y = yDst - ySrc; + + ret = uxa_fill_region_tiled(pDst->pDrawable, ®ion, + (PixmapPtr)pSrc->pDrawable, + &patOrg, FB_ALLONES, GXcopy); + + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + if (ret) + goto done; + } + } + } + + /* Remove repeat in mask if useless */ + if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 && + (xMask + width) <= pMask->pDrawable->width && yMask >= 0 && + (yMask + height) <= pMask->pDrawable->height) + pMask->repeat = 0; + + if (uxa_screen->info->PrepareComposite && + !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) + { + Bool isSrcSolid; + + ret = uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, + yMask, xDst, yDst, width, height); + if (ret == 1) + goto done; + + /* For generic masks and solid src pictures, mach64 can do Over in two + * passes, similar to the component-alpha case. + */ + isSrcSolid = pSrc->pDrawable->width == 1 && + pSrc->pDrawable->height == 1 && + pSrc->repeat; + + /* If we couldn't do the Composite in a single pass, and it was a + * component-alpha Over, see if we can do it in two passes with + * an OutReverse and then an Add. + */ + if (ret == -1 && op == PictOpOver && pMask && + (pMask->componentAlpha || isSrcSolid)) { + ret = uxa_try_magic_two_pass_composite_helper(op, pSrc, pMask, pDst, + xSrc, ySrc, + xMask, yMask, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } + } + +fallback: +#if DEBUG_TRACE_FALL + uxa_print_composite_fallback (op, pSrc, pMask, pDst); +#endif + + uxa_check_composite (op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + +done: + pSrc->repeat = saveSrcRepeat; + if (pMask) + pMask->repeat = saveMaskRepeat; +} +#endif + +/** + * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead + * of PolyFillRect to initialize the pixmap after creating it, to prevent + * the pixmap from being migrated. + * + * See the comments about uxa_trapezoids and uxa_triangles. + */ +static PicturePtr +uxa_create_alpha_picture (ScreenPtr pScreen, + PicturePtr pDst, + PictFormatPtr pPictFormat, + CARD16 width, + CARD16 height) +{ + PixmapPtr pPixmap; + PicturePtr pPicture; + GCPtr pGC; + int error; + xRectangle rect; + + if (width > 32767 || height > 32767) + return 0; + + if (!pPictFormat) + { + if (pDst->polyEdge == PolyEdgeSharp) + pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + if (!pPictFormat) + return 0; + } + + pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + pPictFormat->depth, 0); + if (!pPixmap) + return 0; + pGC = GetScratchGC (pPixmap->drawable.depth, pScreen); + if (!pGC) + { + (*pScreen->DestroyPixmap) (pPixmap); + return 0; + } + ValidateGC (&pPixmap->drawable, pGC); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + uxa_check_poly_fill_rect (&pPixmap->drawable, pGC, 1, &rect); + FreeScratchGC (pGC); + pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat, + 0, 0, serverClient, &error); + (*pScreen->DestroyPixmap) (pPixmap); + return pPicture; +} + +/** + * uxa_trapezoids is essentially a copy of miTrapezoids that uses + * uxa_create_alpha_picture instead of miCreateAlphaPicture. + * + * The problem with miCreateAlphaPicture is that it calls PolyFillRect + * to initialize the contents after creating the pixmap, which + * causes the pixmap to be moved in for acceleration. The subsequent + * call to RasterizeTrapezoid won't be accelerated however, which + * forces the pixmap to be moved out again. + * + * uxa_create_alpha_picture avoids this roundtrip by using uxa_check_poly_fill_rect + * to initialize the contents. + */ +void +uxa_trapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + BoxRec bounds; + Bool direct = op == PictOpAdd && miIsSolidAlpha (pSrc); + + if (maskFormat || direct) { + miTrapezoidBounds (ntrap, traps, &bounds); + + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return; + } + + /* + * Check for solid alpha add + */ + if (direct) + { + DrawablePtr pDraw = pDst->pDrawable; + PixmapPtr pixmap = uxa_get_drawable_pixmap (pDraw); + int xoff, yoff; + + uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff); + + xoff += pDraw->x; + yoff += pDraw->y; + + uxa_prepare_access(pDraw, UXA_PREPARE_DEST); + + for (; ntrap; ntrap--, traps++) + (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0); + + uxa_finish_access(pDraw, UXA_PREPARE_DEST); + } + else if (maskFormat) + { + PicturePtr pPicture; + INT16 xDst, yDst; + INT16 xRel, yRel; + + xDst = traps[0].left.p1.x >> 16; + yDst = traps[0].left.p1.y >> 16; + + pPicture = uxa_create_alpha_picture (pScreen, pDst, maskFormat, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!pPicture) + return; + + uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST); + for (; ntrap; ntrap--, traps++) + (*ps->RasterizeTrapezoid) (pPicture, traps, + -bounds.x1, -bounds.y1); + uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST); + + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + CompositePicture (op, pSrc, pPicture, pDst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + FreePicture (pPicture, 0); + } + else + { + if (pDst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + for (; ntrap; ntrap--, traps++) + uxa_trapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); + } +} + +/** + * uxa_triangles is essentially a copy of miTriangles that uses + * uxa_create_alpha_picture instead of miCreateAlphaPicture. + * + * The problem with miCreateAlphaPicture is that it calls PolyFillRect + * to initialize the contents after creating the pixmap, which + * causes the pixmap to be moved in for acceleration. The subsequent + * call to AddTriangles won't be accelerated however, which forces the pixmap + * to be moved out again. + * + * uxa_create_alpha_picture avoids this roundtrip by using uxa_check_poly_fill_rect + * to initialize the contents. + */ +void +uxa_triangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tris) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + BoxRec bounds; + Bool direct = op == PictOpAdd && miIsSolidAlpha (pSrc); + + if (maskFormat || direct) { + miTriangleBounds (ntri, tris, &bounds); + + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return; + } + + /* + * Check for solid alpha add + */ + if (direct) + { + DrawablePtr pDraw = pDst->pDrawable; + uxa_prepare_access(pDraw, UXA_PREPARE_DEST); + (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); + uxa_finish_access(pDraw, UXA_PREPARE_DEST); + } + else if (maskFormat) + { + PicturePtr pPicture; + INT16 xDst, yDst; + INT16 xRel, yRel; + + xDst = tris[0].p1.x >> 16; + yDst = tris[0].p1.y >> 16; + + pPicture = uxa_create_alpha_picture (pScreen, pDst, maskFormat, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!pPicture) + return; + + uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST); + (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); + uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST); + + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + CompositePicture (op, pSrc, pPicture, pDst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); + FreePicture (pPicture, 0); + } + else + { + if (pDst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + + for (; ntri; ntri--, tris++) + uxa_triangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); + } +} diff --git a/uxa/uxa-unaccel.c b/uxa/uxa-unaccel.c new file mode 100644 index 00000000..27194208 --- /dev/null +++ b/uxa/uxa-unaccel.c @@ -0,0 +1,370 @@ +/* + * + * Copyright © 1999 Keith Packard + * + * 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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. + */ + +#include "uxa-priv.h" + +#ifdef RENDER +#include "mipict.h" +#endif + +/* + * These functions wrap the low-level fb rendering functions and + * synchronize framebuffer/accelerated drawing by stalling until + * the accelerator is idle + */ + +/** + * Calls uxa_prepare_access with UXA_PREPARE_SRC for the tile, if that is the + * current fill style. + * + * Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are + * 1bpp and never in fb, so we don't worry about them. + * We should worry about them for completeness sake and going forward. + */ +void +uxa_prepare_access_gc(GCPtr pGC) +{ + if (pGC->stipple) + uxa_prepare_access(&pGC->stipple->drawable, UXA_PREPARE_MASK); + if (pGC->fillStyle == FillTiled) + uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC); +} + +/** + * Finishes access to the tile in the GC, if used. + */ +void +uxa_finish_access_gc(GCPtr pGC) +{ + if (pGC->fillStyle == FillTiled) + uxa_finish_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_MASK); + if (pGC->stipple) + uxa_finish_access(&pGC->stipple->drawable, UXA_PREPARE_SRC); +} + +#if DEBUG_TRACE_FALL +char +uxa_drawable_location(DrawablePtr pDrawable) +{ + return uxa_drawable_is_offscreen(pDrawable) ? 's' : 'm'; +} +#endif /* DEBUG_TRACE_FALL */ + +void +uxa_check_fill_spans (DrawablePtr pDrawable, GCPtr pGC, int nspans, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access_gc (pGC); + fbFillSpans (pDrawable, pGC, nspans, ppt, pwidth, fSorted); + uxa_finish_access_gc (pGC); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); +} + +void +uxa_check_set_spans (DrawablePtr pDrawable, GCPtr pGC, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) +{ + UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + fbSetSpans (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); +} + +void +uxa_check_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, int format, + char *bits) +{ + UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); +} + +RegionPtr +uxa_check_copy_area (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int w, int h, int dstx, int dsty) +{ + RegionPtr ret; + + UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, + uxa_drawable_location(pSrc), uxa_drawable_location(pDst))); + uxa_prepare_access (pDst, UXA_PREPARE_DEST); + uxa_prepare_access (pSrc, UXA_PREPARE_SRC); + ret = fbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); + uxa_finish_access (pSrc, UXA_PREPARE_SRC); + uxa_finish_access (pDst, UXA_PREPARE_DEST); + + return ret; +} + +RegionPtr +uxa_check_copy_plane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int w, int h, int dstx, int dsty, + unsigned long bitPlane) +{ + RegionPtr ret; + + UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, + uxa_drawable_location(pSrc), uxa_drawable_location(pDst))); + uxa_prepare_access (pDst, UXA_PREPARE_DEST); + uxa_prepare_access (pSrc, UXA_PREPARE_SRC); + ret = fbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, + bitPlane); + uxa_finish_access (pSrc, UXA_PREPARE_SRC); + uxa_finish_access (pDst, UXA_PREPARE_DEST); + + return ret; +} + +void +uxa_check_poly_point (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr pptInit) +{ + UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + fbPolyPoint (pDrawable, pGC, mode, npt, pptInit); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); +} + +void +uxa_check_poly_lines (DrawablePtr pDrawable, GCPtr pGC, + int mode, int npt, DDXPointPtr ppt) +{ + UXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n", + pDrawable, uxa_drawable_location(pDrawable), + pGC->lineWidth, mode, npt)); + + if (pGC->lineWidth == 0) { + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access_gc (pGC); + fbPolyLine (pDrawable, pGC, mode, npt, ppt); + uxa_finish_access_gc (pGC); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + return; + } + /* fb calls mi functions in the lineWidth != 0 case. */ + fbPolyLine (pDrawable, pGC, mode, npt, ppt); +} + +void +uxa_check_poly_segment (DrawablePtr pDrawable, GCPtr pGC, + int nsegInit, xSegment *pSegInit) +{ + UXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable, + uxa_drawable_location(pDrawable), pGC->lineWidth, nsegInit)); + if (pGC->lineWidth == 0) { + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access_gc (pGC); + fbPolySegment (pDrawable, pGC, nsegInit, pSegInit); + uxa_finish_access_gc (pGC); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + return; + } + /* fb calls mi functions in the lineWidth != 0 case. */ + fbPolySegment (pDrawable, pGC, nsegInit, pSegInit); +} + +void +uxa_check_poly_arc (DrawablePtr pDrawable, GCPtr pGC, + int narcs, xArc *pArcs) +{ + UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); + + /* Disable this as fbPolyArc can call miZeroPolyArc which in turn + * can call accelerated functions, that as yet, haven't been notified + * with uxa_finish_access(). + */ +#if 0 + if (pGC->lineWidth == 0) + { + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access_gc (pGC); + fbPolyArc (pDrawable, pGC, narcs, pArcs); + uxa_finish_access_gc (pGC); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + return; + } +#endif + miPolyArc (pDrawable, pGC, narcs, pArcs); +} + +void +uxa_check_poly_fill_rect (DrawablePtr pDrawable, GCPtr pGC, + int nrect, xRectangle *prect) +{ + UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); + + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access_gc (pGC); + fbPolyFillRect (pDrawable, pGC, nrect, prect); + uxa_finish_access_gc (pGC); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); +} + +void +uxa_check_image_glyph_blt (DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + UXA_FALLBACK(("to %p (%c)\n", pDrawable, + uxa_drawable_location(pDrawable))); + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access_gc (pGC); + fbImageGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + uxa_finish_access_gc (pGC); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); +} + +void +uxa_check_poly_glyph_blt (DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + UXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable, + uxa_drawable_location(pDrawable), pGC->fillStyle, pGC->alu)); + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access_gc (pGC); + fbPolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + uxa_finish_access_gc (pGC); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); +} + +void +uxa_check_push_pixels (GCPtr pGC, PixmapPtr pBitmap, + DrawablePtr pDrawable, + int w, int h, int x, int y) +{ + UXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable, + uxa_drawable_location(&pBitmap->drawable), + uxa_drawable_location(pDrawable))); + uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (&pBitmap->drawable, UXA_PREPARE_SRC); + uxa_prepare_access_gc (pGC); + fbPushPixels (pGC, pBitmap, pDrawable, w, h, x, y); + uxa_finish_access_gc (pGC); + uxa_finish_access (&pBitmap->drawable, UXA_PREPARE_SRC); + uxa_finish_access (pDrawable, UXA_PREPARE_DEST); +} + +void +uxa_check_get_spans (DrawablePtr pDrawable, + int wMax, + DDXPointPtr ppt, + int *pwidth, + int nspans, + char *pdstStart) +{ + UXA_FALLBACK(("from %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); + uxa_prepare_access (pDrawable, UXA_PREPARE_SRC); + fbGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + uxa_finish_access (pDrawable, UXA_PREPARE_SRC); +} + +void +uxa_check_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) +{ + UXA_FALLBACK(("from picts %p/%p to pict %p\n", + pSrc, pMask, pDst)); + + uxa_prepare_access (pDst->pDrawable, UXA_PREPARE_DEST); + if (pSrc->pDrawable != NULL) + uxa_prepare_access (pSrc->pDrawable, UXA_PREPARE_SRC); + if (pMask && pMask->pDrawable != NULL) + uxa_prepare_access (pMask->pDrawable, UXA_PREPARE_MASK); + fbComposite (op, + pSrc, + pMask, + pDst, + xSrc, + ySrc, + xMask, + yMask, + xDst, + yDst, + width, + height); + if (pMask && pMask->pDrawable != NULL) + uxa_finish_access (pMask->pDrawable, UXA_PREPARE_MASK); + if (pSrc->pDrawable != NULL) + uxa_finish_access (pSrc->pDrawable, UXA_PREPARE_SRC); + uxa_finish_access (pDst->pDrawable, UXA_PREPARE_DEST); +} + +void +uxa_check_add_traps (PicturePtr pPicture, + INT16 x_off, + INT16 y_off, + int ntrap, + xTrap *traps) +{ + UXA_FALLBACK(("to pict %p (%c)\n", + uxa_drawable_location(pPicture->pDrawable))); + uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST); + fbAddTraps (pPicture, x_off, y_off, ntrap, traps); + uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST); +} + +/** + * Gets the 0,0 pixel of a pixmap. Used for doing solid fills of tiled pixmaps + * that happen to be 1x1. Pixmap must be at least 8bpp. + * + * XXX This really belongs in fb, so it can be aware of tiling and etc. + */ +CARD32 +uxa_get_pixmap_first_pixel (PixmapPtr pPixmap) +{ + CARD32 pixel; + void *fb; + + uxa_prepare_access (&pPixmap->drawable, UXA_PREPARE_SRC); + fb = pPixmap->devPrivate.ptr; + + switch (pPixmap->drawable.bitsPerPixel) { + case 32: + pixel = *(CARD32 *)fb; + break; + case 16: + pixel = *(CARD16 *)fb; + break; + default: + pixel = *(CARD8 *)fb; + break; + } + uxa_finish_access(&pPixmap->drawable, UXA_PREPARE_SRC); + + return pixel; +} diff --git a/uxa/uxa.c b/uxa/uxa.c new file mode 100644 index 00000000..9745f8bb --- /dev/null +++ b/uxa/uxa.c @@ -0,0 +1,573 @@ +/* + * Copyright © 2001 Keith Packard + * + * 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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. + */ + +/** @file + * This file covers the initialization and teardown of UXA, and has various + * functions not responsible for performing rendering, pixmap migration, or + * memory management. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "uxa-priv.h" +#include +#include "dixfontstr.h" +#include "uxa.h" + +DevPrivateKey uxa_screen_key = &uxa_screen_key; + +/** + * uxa_get_drawable_pixmap() returns a 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. Note that + * coordinate translation is needed when drawing to the backing pixmap of a + * redirected window, and the translation coordinates are provided by calling + * uxa_get_drawable_pixmap() on the drawable. + */ +PixmapPtr +uxa_get_drawable_pixmap(DrawablePtr pDrawable) +{ + if (pDrawable->type == DRAWABLE_WINDOW) + return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable); + else + return (PixmapPtr) pDrawable; +} + +/** + * Sets the offsets to add to coordinates to make them address the same bits in + * the backing drawable. These coordinates are nonzero only for redirected + * windows. + */ +void +uxa_get_drawable_deltas (DrawablePtr pDrawable, PixmapPtr pPixmap, + int *xp, int *yp) +{ +#ifdef COMPOSITE + if (pDrawable->type == DRAWABLE_WINDOW) { + *xp = -pPixmap->screen_x; + *yp = -pPixmap->screen_y; + return; + } +#endif + + *xp = 0; + *yp = 0; +} + +/** + * uxa_pixmap_is_offscreen() is used to determine if a pixmap is in offscreen + * memory, meaning that acceleration could probably be done to it, and that it + * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it + * with the CPU. + * + * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly + * deal with moving pixmaps in and out of system memory), UXA will give drivers + * pixmaps as arguments for which uxa_pixmap_is_offscreen() is TRUE. + * + * @return TRUE if the given drawable is in framebuffer memory. + */ +Bool +uxa_pixmap_is_offscreen(PixmapPtr p) +{ + ScreenPtr pScreen = p->drawable.pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + + if (uxa_screen->info->PixmapIsOffscreen) + return uxa_screen->info->PixmapIsOffscreen(p); + + return FALSE; +} + +/** + * uxa_drawable_is_offscreen() is a convenience wrapper for uxa_pixmap_is_offscreen(). + */ +Bool +uxa_drawable_is_offscreen (DrawablePtr pDrawable) +{ + return uxa_pixmap_is_offscreen (uxa_get_drawable_pixmap (pDrawable)); +} + +/** + * Returns the pixmap which backs a drawable, and the offsets to add to + * coordinates to make them address the same bits in the backing drawable. + */ +PixmapPtr +uxa_get_offscreen_pixmap (DrawablePtr drawable, int *xp, int *yp) +{ + PixmapPtr pixmap = uxa_get_drawable_pixmap (drawable); + + uxa_get_drawable_deltas (drawable, pixmap, xp, yp); + + if (uxa_pixmap_is_offscreen (pixmap)) + return pixmap; + else + return NULL; +} + + + +/** + * uxa_prepare_access() is UXA's wrapper for the driver's PrepareAccess() handler. + * + * It deals with waiting for synchronization with the card, determining if + * PrepareAccess() is necessary, and working around PrepareAccess() failure. + */ +void +uxa_prepare_access(DrawablePtr pDrawable, int index) +{ + ScreenPtr pScreen = pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable); + Bool offscreen = uxa_pixmap_is_offscreen(pPixmap); + + if (!offscreen) + return; + + /* XXX should be pPixmap eventually */ + uxa_wait_sync (pScreen); + + if (uxa_screen->info->PrepareAccess) + (*uxa_screen->info->PrepareAccess) (pPixmap, index); +} + +/** + * uxa_finish_access() is UXA's wrapper for the driver's FinishAccess() handler. + * + * It deals with calling the driver's FinishAccess() only if necessary. + */ +void +uxa_finish_access(DrawablePtr pDrawable, int index) +{ + ScreenPtr pScreen = pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable); + + if (uxa_screen->info->FinishAccess == NULL) + return; + + if (!uxa_pixmap_is_offscreen (pPixmap)) + return; + + (*uxa_screen->info->FinishAccess) (pPixmap, index); +} + +/** + * uxa_validate_gc() sets the ops to UXA's implementations, which may be + * accelerated or may sync the card and fall back to fb. + */ +static void +uxa_validate_gc (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + /* fbValidateGC will do direct access to pixmaps if the tiling has changed. + * Preempt fbValidateGC by doing its work and masking the change out, so + * that we can do the Prepare/FinishAccess. + */ +#ifdef FB_24_32BIT + if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) { + (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC)); + fbGetRotatedPixmap(pGC) = 0; + } + + if (pGC->fillStyle == FillTiled) { + PixmapPtr pOldTile, pNewTile; + + pOldTile = pGC->tile.pixmap; + if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel) + { + pNewTile = fbGetRotatedPixmap(pGC); + if (!pNewTile || + pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel) + { + if (pNewTile) + (*pGC->pScreen->DestroyPixmap) (pNewTile); + /* fb24_32ReformatTile will do direct access of a newly- + * allocated pixmap. This isn't a problem yet, since we don't + * put pixmaps in FB until at least one accelerated UXA op. + */ + uxa_prepare_access(&pOldTile->drawable, UXA_PREPARE_SRC); + pNewTile = fb24_32ReformatTile (pOldTile, + pDrawable->bitsPerPixel); + uxa_finish_access(&pOldTile->drawable, UXA_PREPARE_SRC); + } + if (pNewTile) + { + fbGetRotatedPixmap(pGC) = pOldTile; + pGC->tile.pixmap = pNewTile; + changes |= GCTile; + } + } + } +#endif + if (changes & GCTile) { + if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width * + pDrawable->bitsPerPixel)) + { + uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC); + fbPadPixmap (pGC->tile.pixmap); + uxa_finish_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC); + } + /* Mask out the GCTile change notification, now that we've done FB's + * job for it. + */ + changes &= ~GCTile; + } + + uxa_prepare_access_gc(pGC); + fbValidateGC (pGC, changes, pDrawable); + uxa_finish_access_gc(pGC); + + pGC->ops = (GCOps *) &uxa_ops; +} + +static GCFuncs uxaGCFuncs = { + uxa_validate_gc, + miChangeGC, + miCopyGC, + miDestroyGC, + miChangeClip, + miDestroyClip, + miCopyClip +}; + +/** + * uxa_create_gc makes a new GC and hooks up its funcs handler, so that + * uxa_validate_gc() will get called. + */ +static int +uxa_create_gc (GCPtr pGC) +{ + if (!fbCreateGC (pGC)) + return FALSE; + + pGC->funcs = &uxaGCFuncs; + + return TRUE; +} + +void +uxa_prepare_access_window(WindowPtr pWin) +{ + if (pWin->backgroundState == BackgroundPixmap) + uxa_prepare_access(&pWin->background.pixmap->drawable, UXA_PREPARE_SRC); + + if (pWin->borderIsPixel == FALSE) + uxa_prepare_access(&pWin->border.pixmap->drawable, UXA_PREPARE_SRC); +} + +void +uxa_finish_access_window(WindowPtr pWin) +{ + if (pWin->backgroundState == BackgroundPixmap) + uxa_finish_access(&pWin->background.pixmap->drawable, UXA_PREPARE_SRC); + + if (pWin->borderIsPixel == FALSE) + uxa_finish_access(&pWin->border.pixmap->drawable, UXA_PREPARE_SRC); +} + +static Bool +uxa_change_window_attributes(WindowPtr pWin, unsigned long mask) +{ + Bool ret; + + uxa_prepare_access_window(pWin); + ret = fbChangeWindowAttributes(pWin, mask); + uxa_finish_access_window(pWin); + return ret; +} + +static RegionPtr +uxa_bitmap_to_region(PixmapPtr pPix) +{ + RegionPtr ret; + uxa_prepare_access(&pPix->drawable, UXA_PREPARE_SRC); + ret = fbPixmapToRegion(pPix); + uxa_finish_access(&pPix->drawable, UXA_PREPARE_SRC); + return ret; +} + +/** + * uxa_close_screen() unwraps its wrapped screen functions and tears down UXA's + * screen private, before calling down to the next CloseSccreen. + */ +static Bool +uxa_close_screen(int i, ScreenPtr pScreen) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); +#endif + + uxa_glyphs_fini(pScreen); + + pScreen->CreateGC = uxa_screen->SavedCreateGC; + pScreen->CloseScreen = uxa_screen->SavedCloseScreen; + pScreen->GetImage = uxa_screen->SavedGetImage; + pScreen->GetSpans = uxa_screen->SavedGetSpans; + pScreen->CreatePixmap = uxa_screen->SavedCreatePixmap; + pScreen->DestroyPixmap = uxa_screen->SavedDestroyPixmap; + pScreen->CopyWindow = uxa_screen->SavedCopyWindow; + pScreen->ChangeWindowAttributes = uxa_screen->SavedChangeWindowAttributes; + pScreen->BitmapToRegion = uxa_screen->SavedBitmapToRegion; +#ifdef RENDER + if (ps) { + ps->Composite = uxa_screen->SavedComposite; + ps->Glyphs = uxa_screen->SavedGlyphs; + ps->Trapezoids = uxa_screen->SavedTrapezoids; + ps->AddTraps = uxa_screen->SavedAddTraps; + ps->Triangles = uxa_screen->SavedTriangles; + } +#endif + + xfree (uxa_screen); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +/** + * This function allocates a driver structure for UXA drivers to fill in. By + * having UXA allocate the structure, the driver structure can be extended + * without breaking ABI between UXA and the drivers. The driver's + * responsibility is to check beforehand that the UXA module has a matching + * major number and sufficient minor. Drivers are responsible for freeing the + * driver structure using xfree(). + * + * @return a newly allocated, zero-filled driver structure + */ +uxa_driver_t * +uxa_driver_alloc(void) +{ + return xcalloc(1, sizeof(uxa_driver_t)); +} + +/** + * @param pScreen screen being initialized + * @param pScreenInfo UXA driver record + * + * uxa_driver_init sets up UXA given a driver record filled in by the driver. + * pScreenInfo should have been allocated by uxa_driver_alloc(). See the + * comments in _UxaDriver for what must be filled in and what is optional. + * + * @return TRUE if UXA was successfully initialized. + */ +Bool +uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver) +{ + uxa_screen_t *uxa_screen; +#ifdef RENDER + PictureScreenPtr ps; +#endif + + if (!uxa_driver) + return FALSE; + + if (uxa_driver->uxa_major != UXA_VERSION_MAJOR || + uxa_driver->uxa_minor > UXA_VERSION_MINOR) + { + LogMessage(X_ERROR, "UXA(%d): driver's UXA version requirements " + "(%d.%d) are incompatible with UXA version (%d.%d)\n", + screen->myNum, + uxa_driver->uxa_major, uxa_driver->uxa_minor, + UXA_VERSION_MAJOR, UXA_VERSION_MINOR); + return FALSE; + } + + if (!uxa_driver->PrepareSolid) { + LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::PrepareSolid must be " + "non-NULL\n", screen->myNum); + return FALSE; + } + + if (!uxa_driver->PrepareCopy) { + LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::PrepareCopy must be " + "non-NULL\n", screen->myNum); + return FALSE; + } + + if (!uxa_driver->WaitMarker) { + LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::WaitMarker must be " + "non-NULL\n", screen->myNum); + return FALSE; + } + + /* If the driver doesn't set any max pitch values, we'll just assume + * that there's a limitation by pixels, and that it's the same as + * maxX. + * + * We want maxPitchPixels or maxPitchBytes to be set so we can check + * pixmaps against the max pitch in uxaCreatePixmap() -- it matters + * whether a pixmap is rejected because of its pitch or + * because of its width. + */ + if (!uxa_driver->maxPitchPixels && !uxa_driver->maxPitchBytes) + { + uxa_driver->maxPitchPixels = uxa_driver->maxX; + } + +#ifdef RENDER + ps = GetPictureScreenIfSet(screen); +#endif + + uxa_screen = xcalloc (sizeof (uxa_screen_t), 1); + + if (!uxa_screen) { + LogMessage(X_WARNING, "UXA(%d): Failed to allocate screen private\n", + screen->myNum); + return FALSE; + } + + uxa_screen->info = uxa_driver; + + dixSetPrivate(&screen->devPrivates, uxa_screen_key, uxa_screen); + +// exaDDXDriverInit(screen); + + /* + * Replace various fb screen functions + */ + uxa_screen->SavedCloseScreen = screen->CloseScreen; + screen->CloseScreen = uxa_close_screen; + + uxa_screen->SavedCreateGC = screen->CreateGC; + screen->CreateGC = uxa_create_gc; + + uxa_screen->SavedGetImage = screen->GetImage; + screen->GetImage = uxa_get_image; + + uxa_screen->SavedGetSpans = screen->GetSpans; + screen->GetSpans = uxa_check_get_spans; + + uxa_screen->SavedCopyWindow = screen->CopyWindow; + screen->CopyWindow = uxa_copy_window; + + uxa_screen->SavedChangeWindowAttributes = screen->ChangeWindowAttributes; + screen->ChangeWindowAttributes = uxa_change_window_attributes; + + uxa_screen->SavedBitmapToRegion = screen->BitmapToRegion; + screen->BitmapToRegion = uxa_bitmap_to_region; + +#ifdef RENDER + if (ps) { + uxa_screen->SavedComposite = ps->Composite; + ps->Composite = uxa_composite; + + uxa_screen->SavedGlyphs = ps->Glyphs; + ps->Glyphs = uxa_glyphs; + + uxa_screen->SavedTriangles = ps->Triangles; + ps->Triangles = uxa_triangles; + + uxa_screen->SavedTrapezoids = ps->Trapezoids; + ps->Trapezoids = uxa_trapezoids; + + uxa_screen->SavedAddTraps = ps->AddTraps; + ps->AddTraps = uxa_check_add_traps; + } +#endif + +#ifdef MITSHM + /* Re-register with the MI funcs, which don't allow shared pixmaps. + * Shared pixmaps are almost always a performance loss for us, but this + * still allows for SHM PutImage. + */ + ShmRegisterFuncs(screen, &uxa_shm_funcs); +#endif + + uxa_glyphs_init(screen); + + LogMessage(X_INFO, "UXA(%d): Driver registered support for the following" + " operations:\n", screen->myNum); + assert(uxa_driver->PrepareSolid != NULL); + LogMessage(X_INFO, " Solid\n"); + assert(uxa_driver->PrepareCopy != NULL); + LogMessage(X_INFO, " Copy\n"); + if (uxa_driver->PrepareComposite != NULL) { + LogMessage(X_INFO, " Composite (RENDER acceleration)\n"); + } + if (uxa_driver->UploadToScreen != NULL) { + LogMessage(X_INFO, " UploadToScreen\n"); + } + if (uxa_driver->DownloadFromScreen != NULL) { + LogMessage(X_INFO, " DownloadFromScreen\n"); + } + + return TRUE; +} + +/** + * uxa_driver_fini tears down UXA on a given screen. + * + * @param pScreen screen being torn down. + */ +void +uxa_driver_fini (ScreenPtr pScreen) +{ + /*right now does nothing*/ +} + +/** + * uxa_mark_sync() should be called after any asynchronous drawing by the hardware. + * + * @param pScreen screen which drawing occurred on + * + * uxa_mark_sync() sets a flag to indicate that some asynchronous drawing has + * happened and a WaitSync() will be necessary before relying on the contents of + * offscreen memory from the CPU's perspective. It also calls an optional + * driver MarkSync() callback, the return value of which may be used to do partial + * synchronization with the hardware in the future. + */ +void uxa_mark_sync(ScreenPtr pScreen) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + + uxa_screen->info->needsSync = TRUE; + if (uxa_screen->info->MarkSync != NULL) { + uxa_screen->info->lastMarker = (*uxa_screen->info->MarkSync)(pScreen); + } +} + +/** + * uxa_wait_sync() ensures that all drawing has been completed. + * + * @param pScreen screen being synchronized. + * + * Calls down into the driver to ensure that all previous drawing has completed. + * It should always be called before relying on the framebuffer contents + * reflecting previous drawing, from a CPU perspective. + */ +void uxa_wait_sync(ScreenPtr pScreen) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); + + if (uxa_screen->info->needsSync && !uxa_screen->swappedOut) { + (*uxa_screen->info->WaitMarker)(pScreen, uxa_screen->info->lastMarker); + uxa_screen->info->needsSync = FALSE; + } +} diff --git a/uxa/uxa.h b/uxa/uxa.h new file mode 100644 index 00000000..57e84f37 --- /dev/null +++ b/uxa/uxa.h @@ -0,0 +1,671 @@ +/* + * Copyright © 2000, 2008 Keith Packard + * 2004 Eric Anholt + * 2005 Zack Rusin + * + * 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 copyright holders not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. 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. + */ + +/** @file + * UXA - the unified memory acceleration architecture. + * + * This is the header containing the public API of UXA for uxa drivers. + */ + +#ifndef UXA_H +#define UXA_H + +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "gcstruct.h" +#include "picturestr.h" +#include "fb.h" + +#define UXA_VERSION_MAJOR 1 +#define UXA_VERSION_MINOR 0 +#define UXA_VERSION_RELEASE 0 + +/** + * The UxaDriver structure is allocated through uxa_driver_alloc(), and then + * fllled in by drivers. + */ +typedef struct _UxaDriver { + /** + * uxa_major and uxa_minor should be set by the driver to the version of + * UXA which the driver was compiled for (or configures itself at runtime + * to support). This allows UXA to extend the structure for new features + * without breaking ABI for drivers compiled against older versions. + */ + int uxa_major, uxa_minor; + + /** + * The flags field is bitfield of boolean values controlling UXA's behavior. + * + * The flags include UXA_TWO_BITBLT_DIRECTIONS. + */ + int flags; + + /** @{ */ + /** + * maxX controls the X coordinate limitation for rendering from the card. + * The driver should never receive a request for rendering beyond maxX + * in the X direction from the origin of a pixmap. + */ + int maxX; + + /** + * maxY controls the Y coordinate limitation for rendering from the card. + * The driver should never receive a request for rendering beyond maxY + * in the Y direction from the origin of a pixmap. + */ + int maxY; + /** @} */ + + /* private */ + Bool needsSync; + int lastMarker; + + /** @name Solid + * @{ + */ + /** + * PrepareSolid() sets up the driver for doing a solid fill. + * @param pPixmap Destination pixmap + * @param alu raster operation + * @param planemask write mask for the fill + * @param fg "foreground" color for the fill + * + * This call should set up the driver for doing a series of solid fills + * through the Solid() call. The alu raster op is one of the GX* + * graphics functions listed in X.h, and typically maps to a similar + * single-byte "ROP" setting in all hardware. The planemask controls + * which bits of the destination should be affected, and will only represent + * the bits up to the depth of pPixmap. The fg is the pixel value of the + * foreground color referred to in ROP descriptions. + * + * Note that many drivers will need to store some of the data in the driver + * private record, for sending to the hardware with each drawing command. + * + * The PrepareSolid() call is required of all drivers, but it may fail for any + * reason. Failure results in a fallback to software rendering. + */ + Bool (*PrepareSolid) (PixmapPtr pPixmap, + int alu, + Pixel planemask, + Pixel fg); + + /** + * Solid() performs a solid fill set up in the last PrepareSolid() call. + * + * @param pPixmap destination pixmap + * @param x1 left coordinate + * @param y1 top coordinate + * @param x2 right coordinate + * @param y2 bottom coordinate + * + * Performs the fill set up by the last PrepareSolid() call, covering the + * area from (x1,y1) to (x2,y2) in pPixmap. Note that the coordinates are + * in the coordinate space of the destination pixmap, so the driver will + * need to set up the hardware's offset and pitch for the destination + * coordinates according to the pixmap's offset and pitch within + * framebuffer. + * + * This call is required if PrepareSolid() ever succeeds. + */ + void (*Solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2); + + /** + * DoneSolid() finishes a set of solid fills. + * + * @param pPixmap destination pixmap. + * + * The DoneSolid() call is called at the end of a series of consecutive + * Solid() calls following a successful PrepareSolid(). This allows drivers + * to finish up emitting drawing commands that were buffered, or clean up + * state from PrepareSolid(). + * + * This call is required if PrepareSolid() ever succeeds. + */ + void (*DoneSolid) (PixmapPtr pPixmap); + /** @} */ + + /** @name Copy + * @{ + */ + /** + * PrepareCopy() sets up the driver for doing a copy within video + * memory. + * + * @param pSrcPixmap source pixmap + * @param pDstPixmap destination pixmap + * @param dx X copy direction + * @param dy Y copy direction + * @param alu raster operation + * @param planemask write mask for the fill + * + * This call should set up the driver for doing a series of copies from the + * the pSrcPixmap to the pDstPixmap. The dx flag will be positive if the + * hardware should do the copy from the left to the right, and dy will be + * positive if the copy should be done from the top to the bottom. This + * is to deal with self-overlapping copies when pSrcPixmap == pDstPixmap. + * If your hardware can only support blits that are (left to right, top to + * bottom) or (right to left, bottom to top), then you should set + * #UXA_TWO_BITBLT_DIRECTIONS, and UXA will break down Copy operations to + * ones that meet those requirements. The alu raster op is one of the GX* + * graphics functions listed in X.h, and typically maps to a similar + * single-byte "ROP" setting in all hardware. The planemask controls which + * bits of the destination should be affected, and will only represent the + * bits up to the depth of pPixmap. + * + * Note that many drivers will need to store some of the data in the driver + * private record, for sending to the hardware with each drawing command. + * + * The PrepareCopy() call is required of all drivers, but it may fail for any + * reason. Failure results in a fallback to software rendering. + */ + Bool (*PrepareCopy) (PixmapPtr pSrcPixmap, + PixmapPtr pDstPixmap, + int dx, + int dy, + int alu, + Pixel planemask); + + /** + * Copy() performs a copy set up in the last PrepareCopy call. + * + * @param pDstPixmap destination pixmap + * @param srcX source X coordinate + * @param srcY source Y coordinate + * @param dstX destination X coordinate + * @param dstY destination Y coordinate + * @param width width of the rectangle to be copied + * @param height height of the rectangle to be copied. + * + * Performs the copy set up by the last PrepareCopy() call, copying the + * rectangle from (srcX, srcY) to (srcX + width, srcY + width) in the source + * pixmap to the same-sized rectangle at (dstX, dstY) in the destination + * pixmap. Those rectangles may overlap in memory, if + * pSrcPixmap == pDstPixmap. Note that this call does not receive the + * pSrcPixmap as an argument -- if it's needed in this function, it should + * be stored in the driver private during PrepareCopy(). As with Solid(), + * the coordinates are in the coordinate space of each pixmap, so the driver + * will need to set up source and destination pitches and offsets from those + * pixmaps, probably using uxaGetPixmapOffset() and uxa_get_pixmap_pitch(). + * + * This call is required if PrepareCopy ever succeeds. + */ + void (*Copy) (PixmapPtr pDstPixmap, + int srcX, + int srcY, + int dstX, + int dstY, + int width, + int height); + + /** + * DoneCopy() finishes a set of copies. + * + * @param pPixmap destination pixmap. + * + * The DoneCopy() call is called at the end of a series of consecutive + * Copy() calls following a successful PrepareCopy(). This allows drivers + * to finish up emitting drawing commands that were buffered, or clean up + * state from PrepareCopy(). + * + * This call is required if PrepareCopy() ever succeeds. + */ + void (*DoneCopy) (PixmapPtr pDstPixmap); + /** @} */ + + /** @name Composite + * @{ + */ + /** + * CheckComposite() checks to see if a composite operation could be + * accelerated. + * + * @param op Render operation + * @param pSrcPicture source Picture + * @param pMaskPicture mask picture + * @param pDstPicture destination Picture + * + * The CheckComposite() call checks if the driver could handle acceleration + * of op with the given source, mask, and destination pictures. This allows + * drivers to check source and destination formats, supported operations, + * transformations, and component alpha state, and send operations it can't + * support to software rendering early on. This avoids costly pixmap + * migration to the wrong places when the driver can't accelerate + * operations. Note that because migration hasn't happened, the driver + * can't know during CheckComposite() what the offsets and pitches of the + * pixmaps are going to be. + * + * See PrepareComposite() for more details on likely issues that drivers + * will have in accelerating Composite operations. + * + * The CheckComposite() call is recommended if PrepareComposite() is + * implemented, but is not required. + */ + Bool (*CheckComposite) (int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture); + + /** + * PrepareComposite() sets up the driver for doing a Composite operation + * described in the Render extension protocol spec. + * + * @param op Render operation + * @param pSrcPicture source Picture + * @param pMaskPicture mask picture + * @param pDstPicture destination Picture + * @param pSrc source pixmap + * @param pMask mask pixmap + * @param pDst destination pixmap + * + * This call should set up the driver for doing a series of Composite + * operations, as described in the Render protocol spec, with the given + * pSrcPicture, pMaskPicture, and pDstPicture. The pSrc, pMask, and + * pDst are the pixmaps containing the pixel data, and should be used for + * setting the offset and pitch used for the coordinate spaces for each of + * the Pictures. + * + * Notes on interpreting Picture structures: + * - The Picture structures will always have a valid pDrawable. + * - The Picture structures will never have alphaMap set. + * - The mask Picture (and therefore pMask) may be NULL, in which case the + * operation is simply src OP dst instead of src IN mask OP dst, and + * mask coordinates should be ignored. + * - pMarkPicture may have componentAlpha set, which greatly changes + * the behavior of the Composite operation. componentAlpha has no effect + * when set on pSrcPicture or pDstPicture. + * - The source and mask Pictures may have a transformation set + * (Picture->transform != NULL), which means that the source coordinates + * should be transformed by that transformation, resulting in scaling, + * rotation, etc. The PictureTransformPoint() call can transform + * coordinates for you. Transforms have no effect on Pictures when used + * as a destination. + * - The source and mask pictures may have a filter set. PictFilterNearest + * and PictFilterBilinear are defined in the Render protocol, but others + * may be encountered, and must be handled correctly (usually by + * PrepareComposite failing, and falling back to software). Filters have + * no effect on Pictures when used as a destination. + * - The source and mask Pictures may have repeating set, which must be + * respected. Many chipsets will be unable to support repeating on + * pixmaps that have a width or height that is not a power of two. + * + * If your hardware can't support source pictures (textures) with + * non-power-of-two pitches, you should set #UXA_OFFSCREEN_ALIGN_POT. + * + * Note that many drivers will need to store some of the data in the driver + * private record, for sending to the hardware with each drawing command. + * + * The PrepareComposite() call is not required. However, it is highly + * recommended for performance of antialiased font rendering and performance + * of cairo applications. Failure results in a fallback to software + * rendering. + */ + Bool (*PrepareComposite) (int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture, + PixmapPtr pSrc, + PixmapPtr pMask, + PixmapPtr pDst); + + /** + * Composite() performs a Composite operation set up in the last + * PrepareComposite() call. + * + * @param pDstPixmap destination pixmap + * @param srcX source X coordinate + * @param srcY source Y coordinate + * @param maskX source X coordinate + * @param maskY source Y coordinate + * @param dstX destination X coordinate + * @param dstY destination Y coordinate + * @param width destination rectangle width + * @param height destination rectangle height + * + * Performs the Composite operation set up by the last PrepareComposite() + * call, to the rectangle from (dstX, dstY) to (dstX + width, dstY + height) + * in the destination Pixmap. Note that if a transformation was set on + * the source or mask Pictures, the source rectangles may not be the same + * size as the destination rectangles and filtering. Getting the coordinate + * transformation right at the subpixel level can be tricky, and rendercheck + * can test this for you. + * + * This call is required if PrepareComposite() ever succeeds. + */ + void (*Composite) (PixmapPtr pDst, + int srcX, + int srcY, + int maskX, + int maskY, + int dstX, + int dstY, + int width, + int height); + + /** + * DoneComposite() finishes a set of Composite operations. + * + * @param pPixmap destination pixmap. + * + * The DoneComposite() call is called at the end of a series of consecutive + * Composite() calls following a successful PrepareComposite(). This allows + * drivers to finish up emitting drawing commands that were buffered, or + * clean up state from PrepareComposite(). + * + * This call is required if PrepareComposite() ever succeeds. + */ + void (*DoneComposite) (PixmapPtr pDst); + /** @} */ + + /** + * UploadToScreen() loads a rectangle of data from src into pDst. + * + * @param pDst destination pixmap + * @param x destination X coordinate. + * @param y destination Y coordinate + * @param width width of the rectangle to be copied + * @param height height of the rectangle to be copied + * @param src pointer to the beginning of the source data + * @param src_pitch pitch (in bytes) of the lines of source data. + * + * UploadToScreen() copies data in system memory beginning at src (with + * pitch src_pitch) into the destination pixmap from (x, y) to + * (x + width, y + height). This is typically done with hostdata uploads, + * where the CPU sets up a blit command on the hardware with instructions + * that the blit data will be fed through some sort of aperture on the card. + * + * If UploadToScreen() is performed asynchronously, it is up to the driver + * to call uxa_mark_sync(). This is in contrast to most other acceleration + * calls in UXA. + * + * UploadToScreen() can aid in pixmap migration, but is most important for + * the performance of uxa_glyphs() (antialiased font drawing) by allowing + * pipelining of data uploads, avoiding a sync of the card after each glyph. + * + * @return TRUE if the driver successfully uploaded the data. FALSE + * indicates that UXA should fall back to doing the upload in software. + * + * UploadToScreen() is not required, but is recommended if Composite + * acceleration is supported. + */ + Bool (*UploadToScreen) (PixmapPtr pDst, + int x, + int y, + int w, + int h, + char *src, + int src_pitch); + + /** + * UploadToScratch() is used to upload a pixmap to a scratch area for + * acceleration. + * + * @param pSrc source pixmap in host memory + * @param pDst fake, scratch pixmap to be set up in offscreen memory. + * + * The UploadToScratch() call was added to support Xati before Xati had + * support for hostdata uploads and before uxa_glyphs() was written. It + * behaves incorrectly (uses an invalid pixmap as pDst), + * and UploadToScreen() should be implemented instead. + * + * Drivers implementing UploadToScratch() had to set up space (likely in a + * statically allocated area) in offscreen memory, copy pSrc to that + * scratch area, and adust pDst->devKind for the pitch and + * pDst->devPrivate.ptr for the pointer to that scratch area. The driver + * was responsible for syncing (as it was implemented using memcpy() in + * Xati), and only the data from the last UploadToScratch() was guaranteed + * to be valid at any given time. + * + * UploadToScratch() should not be implemented by drivers, and will likely + * be removed in a future version of UXA. + */ + Bool (*UploadToScratch) (PixmapPtr pSrc, + PixmapPtr pDst); + + /** + * DownloadFromScreen() loads a rectangle of data from pSrc into dst + * + * @param pSrc source pixmap + * @param x source X coordinate. + * @param y source Y coordinate + * @param width width of the rectangle to be copied + * @param height height of the rectangle to be copied + * @param dst pointer to the beginning of the destination data + * @param dst_pitch pitch (in bytes) of the lines of destination data. + * + * DownloadFromScreen() copies data from offscreen memory in pSrc from + * (x, y) to (x + width, y + height), to system memory starting at + * dst (with pitch dst_pitch). This would usually be done + * using scatter-gather DMA, supported by a DRM call, or by blitting to AGP + * and then synchronously reading from AGP. Because the implementation + * might be synchronous, UXA leaves it up to the driver to call + * uxa_mark_sync() if DownloadFromScreen() was asynchronous. This is in + * contrast to most other acceleration calls in UXA. + * + * DownloadFromScreen() can aid in the largest bottleneck in pixmap + * migration, which is the read from framebuffer when evicting pixmaps from + * framebuffer memory. Thus, it is highly recommended, even though + * implementations are typically complicated. + * + * @return TRUE if the driver successfully downloaded the data. FALSE + * indicates that UXA should fall back to doing the download in software. + * + * DownloadFromScreen() is not required, but is highly recommended. + */ + Bool (*DownloadFromScreen)(PixmapPtr pSrc, + int x, int y, + int w, int h, + char *dst, int dst_pitch); + + /** + * MarkSync() requests that the driver mark a synchronization point, + * returning an driver-defined integer marker which could be requested for + * synchronization to later in WaitMarker(). This might be used in the + * future to avoid waiting for full hardware stalls before accessing pixmap + * data with the CPU, but is not important in the current incarnation of + * UXA. + * + * Note that drivers should call uxa_mark_sync() when they have done some + * acceleration, rather than their own MarkSync() handler, as otherwise UXA + * will be unaware of the driver's acceleration and not sync to it during + * fallbacks. + * + * MarkSync() is optional. + */ + int (*MarkSync) (ScreenPtr pScreen); + + /** + * WaitMarker() waits for all rendering before the given marker to have + * completed. If the driver does not implement MarkSync(), marker is + * meaningless, and all rendering by the hardware should be completed before + * WaitMarker() returns. + * + * Note that drivers should call uxa_wait_sync() to wait for all acceleration + * to finish, as otherwise UXA will be unaware of the driver having + * synchronized, resulting in excessive WaitMarker() calls. + * + * WaitMarker() is required of all drivers. + */ + void (*WaitMarker) (ScreenPtr pScreen, int marker); + + /** @{ */ + /** + * PrepareAccess() is called before CPU access to an offscreen pixmap. + * + * @param pPix the pixmap being accessed + * @param index the index of the pixmap being accessed. + * + * PrepareAccess() will be called before CPU access to an offscreen pixmap. + * This can be used to set up hardware surfaces for byteswapping or + * untiling, or to adjust the pixmap's devPrivate.ptr for the purpose of + * making CPU access use a different aperture. + * + * The index is one of #UXA_PREPARE_DEST, #UXA_PREPARE_SRC, or + * #UXA_PREPARE_MASK, indicating which pixmap is in question. Since only up + * to three pixmaps will have PrepareAccess() called on them per operation, + * drivers can have a small, statically-allocated space to maintain state + * for PrepareAccess() and FinishAccess() in. Note that the same pixmap may + * have PrepareAccess() called on it more than once, for uxample when doing + * a copy within the same pixmap (so it gets PrepareAccess as() + * #UXA_PREPARE_DEST and then as #UXA_PREPARE_SRC). + * + * PrepareAccess() may fail. An uxample might be the case of hardware that + * can set up 1 or 2 surfaces for CPU access, but not 3. If PrepareAccess() + * fails, UXA will migrate the pixmap to system memory. + * DownloadFromScreen() must be implemented and must not fail if a driver + * wishes to fail in PrepareAccess(). PrepareAccess() must not fail when + * pPix is the visible screen, because the visible screen can not be + * migrated. + * + * @return TRUE if PrepareAccess() successfully prepared the pixmap for CPU + * drawing. + * @return FALSE if PrepareAccess() is unsuccessful and UXA should use + * DownloadFromScreen() to migate the pixmap out. + */ + Bool (*PrepareAccess)(PixmapPtr pPix, int index); + + /** + * FinishAccess() is called after CPU access to an offscreen pixmap. + * + * @param pPix the pixmap being accessed + * @param index the index of the pixmap being accessed. + * + * FinishAccess() will be called after finishing CPU access of an offscreen + * pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be + * called if PrepareAccess() failed and the pixmap was migrated out. + */ + void (*FinishAccess)(PixmapPtr pPix, int index); + + /** + * PixmapIsOffscreen() is an optional driver replacement to + * uxa_pixmap_is_offscreen(). Set to NULL if you want the standard behaviour + * of uxa_pixmap_is_offscreen(). + * + * @param pPix the pixmap + * @return TRUE if the given drawable is in framebuffer memory. + * + * uxa_pixmap_is_offscreen() is used to determine if a pixmap is in offscreen + * memory, meaning that acceleration could probably be done to it, and that it + * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it + * with the CPU. + * + * + */ + Bool (*PixmapIsOffscreen)(PixmapPtr pPix); + + /** @name PrepareAccess() and FinishAccess() indices + * @{ + */ + /** + * UXA_PREPARE_DEST is the index for a pixmap that may be drawn to or + * read from. + */ + #define UXA_PREPARE_DEST 0 + /** + * UXA_PREPARE_SRC is the index for a pixmap that may be read from + */ + #define UXA_PREPARE_SRC 1 + /** + * UXA_PREPARE_SRC is the index for a second pixmap that may be read + * from. + */ + #define UXA_PREPARE_MASK 2 + /** @} */ + + /** + * maxPitchPixels controls the pitch limitation for rendering from + * the card. + * The driver should never receive a request for rendering a pixmap + * that has a pitch (in pixels) beyond maxPitchPixels. + * + * Setting this field is optional -- if your hardware doesn't have + * a pitch limitation in pixels, don't set this. If neither this value + * nor maxPitchBytes is set, then maxPitchPixels is set to maxX. + * If set, it must not be smaller than maxX. + * + * @sa maxPitchBytes + */ + int maxPitchPixels; + + /** + * maxPitchBytes controls the pitch limitation for rendering from + * the card. + * The driver should never receive a request for rendering a pixmap + * that has a pitch (in bytes) beyond maxPitchBytes. + * + * Setting this field is optional -- if your hardware doesn't have + * a pitch limitation in bytes, don't set this. + * If set, it must not be smaller than maxX * 4. + * There's no default value for maxPitchBytes. + * + * @sa maxPitchPixels + */ + int maxPitchBytes; + + /** @} */ +} uxa_driver_t; + +/** @name UXA driver flags + * @{ + */ +/** + * UXA_TWO_BITBLT_DIRECTIONS indicates to UXA that the driver can only + * support copies that are (left-to-right, top-to-bottom) or + * (right-to-left, bottom-to-top). + */ +#define UXA_TWO_BITBLT_DIRECTIONS (1 << 2) + +/** @} */ + +uxa_driver_t * +uxa_driver_alloc(void); + +Bool +uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver); + +void +uxa_driver_fini(ScreenPtr pScreen); + +void +uxa_mark_sync(ScreenPtr pScreen); + +void +uxa_wait_sync(ScreenPtr pScreen); + +void +uxaEnableDisableFBAccess (int index, Bool enable); + +CARD32 +uxa_get_pixmap_first_pixel (PixmapPtr pPixmap); + +/** + * Returns TRUE if the given planemask covers all the significant bits in the + * pixel values for pDrawable. + */ +#define UXA_PM_IS_SOLID(_pDrawable, _pm) \ + (((_pm) & FbFullMask((_pDrawable)->depth)) == \ + FbFullMask((_pDrawable)->depth)) + +#endif /* UXA_H */ From b0b0998b5d52d105eb1e631f688aa8f1bd55ef39 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 30 Jul 2008 16:15:37 -0700 Subject: [PATCH 35/45] Make EXA functions work for UXA as well EXA and UXA have the same acceleration interface, but UXA doesn't provide pixmap stride information as it doesn't manage pixmaps. Move all of that into the driver structure so that the acceleration functions needn't reference the EXA structure. --- src/i830.h | 8 +++++ src/i830_accel.c | 48 +++++++++++++++++++++++++++++ src/i830_exa.c | 78 +++++++++++++++--------------------------------- 3 files changed, 80 insertions(+), 54 deletions(-) diff --git a/src/i830.h b/src/i830.h index 2fb8efaa..fe259197 100644 --- a/src/i830.h +++ b/src/i830.h @@ -527,9 +527,17 @@ typedef struct _I830Rec { #ifdef I830_USE_EXA ExaDriverPtr EXADriverPtr; +#endif +#ifdef I830_USE_UXA uxa_driver_t *uxa_driver; +#endif +#if defined(I830_USE_EXA) || defined(I830_USE_UXA) PixmapPtr pSrcPixmap; #endif + int accel_pixmap_pitch_alignment; + int accel_pixmap_offset_alignment; + int accel_max_x; + int accel_max_y; I830WriteIndexedByteFunc writeControl; I830ReadIndexedByteFunc readControl; diff --git a/src/i830_accel.c b/src/i830_accel.c index 579de31c..0ef565b8 100644 --- a/src/i830_accel.c +++ b/src/i830_accel.c @@ -282,6 +282,54 @@ I830AccelInit(ScreenPtr pScreen) ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); + /* Limits are described in the BLT engine chapter under Graphics Data Size + * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO, + * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO. + * + * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768. + * + * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled. + * i965 limits 3D surface to 4kB-aligned offset if tiled. + * i965 limits 3D surfaces to w,h of ?,8192. + * i965 limits 3D surface to pitch of 1B - 128kB. + * i965 limits 3D surface pitch alignment to 1 or 2 times the element size. + * i965 limits 3D surface pitch alignment to 512B if tiled. + * i965 limits 3D destination drawing rect to w,h of 8192,8192. + * + * i915 limits 3D textures to 4B-aligned offset if un-tiled. + * i915 limits 3D textures to ~4kB-aligned offset if tiled. + * i915 limits 3D textures to width,height of 2048,2048. + * i915 limits 3D textures to pitch of 16B - 8kB, in dwords. + * i915 limits 3D destination to ~4kB-aligned offset if tiled. + * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled. + * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled. + * i915 limits 3D destination to POT aligned pitch if tiled. + * i915 limits 3D destination drawing rect to w,h of 2048,2048. + * + * i845 limits 3D textures to 4B-aligned offset if un-tiled. + * i845 limits 3D textures to ~4kB-aligned offset if tiled. + * i845 limits 3D textures to width,height of 2048,2048. + * i845 limits 3D textures to pitch of 4B - 8kB, in dwords. + * i845 limits 3D destination to 4B-aligned offset if un-tiled. + * i845 limits 3D destination to ~4kB-aligned offset if tiled. + * i845 limits 3D destination to pitch of 8B - 8kB, in dwords. + * i845 limits 3D destination drawing rect to w,h of 2048,2048. + * + * For the tiled issues, the only tiled buffer we draw to should be + * the front, which will have an appropriate pitch/offset already set up, + * so EXA doesn't need to worry. + */ + if (IS_I965G(pI830)) { + pI830->accel_pixmap_offset_alignment = 4 * 2; + pI830->accel_pixmap_pitch_alignment = 16; + pI830->accel_max_x = 8192; + pI830->accel_max_y = 8192; + } else { + pI830->accel_pixmap_offset_alignment = 4; + pI830->accel_pixmap_pitch_alignment = 16; + pI830->accel_max_x = 2048; + pI830->accel_max_y = 2048; + } switch (pI830->accel) { #ifdef I830_USE_UXA case ACCEL_UXA: diff --git a/src/i830_exa.c b/src/i830_exa.c index a6705f48..f00e4f94 100644 --- a/src/i830_exa.c +++ b/src/i830_exa.c @@ -121,6 +121,21 @@ i830_pixmap_tiled(PixmapPtr pPixmap) return FALSE; } +static unsigned long +i830_pixmap_pitch(PixmapPtr pixmap) +{ + return pixmap->devKind; +} + +static int +i830_pixmap_pitch_is_aligned(PixmapPtr pixmap) +{ + ScrnInfoPtr pScrn = xf86Screens[pixmap->drawable.pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + return i830_pixmap_pitch(pixmap) % pI830->accel_pixmap_pitch_alignment == 0; +} + static Bool i830_exa_pixmap_is_offscreen(PixmapPtr pPixmap) { @@ -172,9 +187,9 @@ I830EXAPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) i830_exa_check_pitch_2d(pPixmap); - pitch = exaGetPixmapPitch(pPixmap); + pitch = i830_pixmap_pitch(pPixmap); - if (pitch % pI830->EXADriverPtr->pixmapPitchAlign != 0) + if (!i830_pixmap_pitch_is_aligned(pPixmap)) I830FALLBACK("pixmap pitch not aligned"); pI830->BR[13] = (I830PatternROP[alu] & 0xff) << 16 ; @@ -202,7 +217,7 @@ I830EXASolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) unsigned long pitch; uint32_t cmd; - pitch = exaGetPixmapPitch(pPixmap); + pitch = i830_pixmap_pitch(pPixmap); { BEGIN_BATCH(6); @@ -286,8 +301,8 @@ I830EXACopy(PixmapPtr pDstPixmap, int src_x1, int src_y1, int dst_x1, dst_x2 = dst_x1 + w; dst_y2 = dst_y1 + h; - dst_pitch = exaGetPixmapPitch(pDstPixmap); - src_pitch = exaGetPixmapPitch(pI830->pSrcPixmap); + dst_pitch = i830_pixmap_pitch(pDstPixmap); + src_pitch = i830_pixmap_pitch(pI830->pSrcPixmap); { BEGIN_BATCH(8); @@ -466,55 +481,10 @@ I830EXAInit(ScreenPtr pScreen) pI830->EXADriverPtr->offScreenBase, pI830->EXADriverPtr->memorySize); - - /* Limits are described in the BLT engine chapter under Graphics Data Size - * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO, - * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO. - * - * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768. - * - * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled. - * i965 limits 3D surface to 4kB-aligned offset if tiled. - * i965 limits 3D surfaces to w,h of ?,8192. - * i965 limits 3D surface to pitch of 1B - 128kB. - * i965 limits 3D surface pitch alignment to 1 or 2 times the element size. - * i965 limits 3D surface pitch alignment to 512B if tiled. - * i965 limits 3D destination drawing rect to w,h of 8192,8192. - * - * i915 limits 3D textures to 4B-aligned offset if un-tiled. - * i915 limits 3D textures to ~4kB-aligned offset if tiled. - * i915 limits 3D textures to width,height of 2048,2048. - * i915 limits 3D textures to pitch of 16B - 8kB, in dwords. - * i915 limits 3D destination to ~4kB-aligned offset if tiled. - * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled. - * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled. - * i915 limits 3D destination to POT aligned pitch if tiled. - * i915 limits 3D destination drawing rect to w,h of 2048,2048. - * - * i845 limits 3D textures to 4B-aligned offset if un-tiled. - * i845 limits 3D textures to ~4kB-aligned offset if tiled. - * i845 limits 3D textures to width,height of 2048,2048. - * i845 limits 3D textures to pitch of 4B - 8kB, in dwords. - * i845 limits 3D destination to 4B-aligned offset if un-tiled. - * i845 limits 3D destination to ~4kB-aligned offset if tiled. - * i845 limits 3D destination to pitch of 8B - 8kB, in dwords. - * i845 limits 3D destination drawing rect to w,h of 2048,2048. - * - * For the tiled issues, the only tiled buffer we draw to should be - * the front, which will have an appropriate pitch/offset already set up, - * so EXA doesn't need to worry. - */ - if (IS_I965G(pI830)) { - pI830->EXADriverPtr->pixmapOffsetAlign = 4 * 2; - pI830->EXADriverPtr->pixmapPitchAlign = 16; - pI830->EXADriverPtr->maxX = 8192; - pI830->EXADriverPtr->maxY = 8192; - } else { - pI830->EXADriverPtr->pixmapOffsetAlign = 4; - pI830->EXADriverPtr->pixmapPitchAlign = 16; - pI830->EXADriverPtr->maxX = 2048; - pI830->EXADriverPtr->maxY = 2048; - } + pI830->EXADriverPtr->pixmapOffsetAlign = pI830->accel_pixmap_offset_alignment; + pI830->EXADriverPtr->pixmapPitchAlign = pI830->accel_pixmap_pitch_alignment; + pI830->EXADriverPtr->maxX = pI830->accel_max_x; + pI830->EXADriverPtr->maxY = pI830->accel_max_y; /* Sync */ pI830->EXADriverPtr->WaitMarker = I830EXASync; From 4cc20b7f6e25f4be4598f8edbe0077117126b4ee Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Aug 2008 01:42:48 -0700 Subject: [PATCH 36/45] Don't call sync on prepare_access -- just let the driver deal with it. Let the driver do whatever sync is necessary from the prepare_access hook rather than forcing a full sync. --- uxa/uxa.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/uxa/uxa.c b/uxa/uxa.c index 9745f8bb..7201e7c6 100644 --- a/uxa/uxa.c +++ b/uxa/uxa.c @@ -151,9 +151,6 @@ uxa_prepare_access(DrawablePtr pDrawable, int index) if (!offscreen) return; - /* XXX should be pPixmap eventually */ - uxa_wait_sync (pScreen); - if (uxa_screen->info->PrepareAccess) (*uxa_screen->info->PrepareAccess) (pPixmap, index); } From 12df8f40d2fb41f5446db1b49beeb442da18bee2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Aug 2008 01:43:44 -0700 Subject: [PATCH 37/45] Use dri_bo for all object allocations, including pixmaps under uxa --- src/i830.h | 15 ++- src/i830_accel.c | 2 +- src/i830_batchbuffer.h | 22 +++- src/i830_dri.c | 11 +- src/i830_dri.h | 1 - src/i830_driver.c | 18 ++- src/i830_exa.c | 279 +++++++++++++++++++++++++++-------------- src/i830_memory.c | 69 ++++------ src/i830_render.c | 4 +- src/i915_render.c | 10 +- src/i915_video.c | 2 +- 11 files changed, 258 insertions(+), 175 deletions(-) diff --git a/src/i830.h b/src/i830.h index fe259197..dbcf3c0f 100644 --- a/src/i830.h +++ b/src/i830.h @@ -80,15 +80,22 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #endif #include "dri_bufmgr.h" #include "intel_bufmgr.h" +#include "i915_drm.h" #ifdef I830_USE_EXA #include "exa.h" -#include "uxa.h" Bool I830EXAInit(ScreenPtr pScreen); -Bool i830_uxa_init(ScreenPtr pScreen); unsigned long long I830TexOffsetStart(PixmapPtr pPix); #endif +#ifdef I830_USE_UXA +#include "uxa.h" +Bool i830_uxa_init(ScreenPtr pScreen); +dri_bo *i830_uxa_get_pixmap_bo (PixmapPtr pixmap); +void i830_uxa_create_screen_resources(ScreenPtr pScreen); +void i830_uxa_block_handler (ScreenPtr pScreen); +#endif + #ifdef I830_USE_XAA Bool I830XAAInit(ScreenPtr pScreen); #endif @@ -194,7 +201,7 @@ struct _i830_memory { i830_memory *prev; /** @} */ - uint32_t gem_handle; + dri_bo *bo; uint32_t alignment; uint32_t gem_name; Bool lifetime_fixed_offset; @@ -530,6 +537,7 @@ typedef struct _I830Rec { #endif #ifdef I830_USE_UXA uxa_driver_t *uxa_driver; + Bool need_flush; #endif #if defined(I830_USE_EXA) || defined(I830_USE_UXA) PixmapPtr pSrcPixmap; @@ -818,6 +826,7 @@ Bool i830_allocate_2d_memory(ScrnInfoPtr pScrn); Bool i830_allocate_texture_memory(ScrnInfoPtr pScrn); Bool i830_allocate_pwrctx(ScrnInfoPtr pScrn); Bool i830_allocate_3d_memory(ScrnInfoPtr pScrn); +void i830_init_bufmgr(ScrnInfoPtr pScrn); #ifdef INTEL_XVMC Bool i830_allocate_xvmc_buffer(ScrnInfoPtr pScrn, const char *name, i830_memory **buffer, unsigned long size, int flags); diff --git a/src/i830_accel.c b/src/i830_accel.c index 0ef565b8..a3018187 100644 --- a/src/i830_accel.c +++ b/src/i830_accel.c @@ -67,7 +67,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. unsigned long intel_get_pixmap_offset(PixmapPtr pPix) { -#ifdef I830_USE_EXA +#if defined(I830_USE_EXA) || defined(I830_USE_UXA) ScreenPtr pScreen = pPix->drawable.pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); diff --git a/src/i830_batchbuffer.h b/src/i830_batchbuffer.h index c9b84215..4c1198d6 100644 --- a/src/i830_batchbuffer.h +++ b/src/i830_batchbuffer.h @@ -74,12 +74,24 @@ intel_batch_emit_reloc (I830Ptr pI830, } static inline void -intel_batch_emit_reloc_pixmap(I830Ptr pI830, PixmapPtr pPixmap, uint32_t delta) +intel_batch_emit_reloc_pixmap(I830Ptr pI830, PixmapPtr pPixmap, + uint32_t read_domains, uint32_t write_domain, + uint32_t delta) { +#if I830_USE_UXA + dri_bo *bo = i830_uxa_get_pixmap_bo(pPixmap); +#endif + uint32_t offset; assert(pI830->batch_ptr != NULL); assert(intel_batch_space(pI830) >= 4); - *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = - intel_get_pixmap_offset(pPixmap) + delta; +#if I830_USE_UXA + if (bo) { + intel_batch_emit_reloc(pI830, bo, read_domains, write_domain, delta); + return; + } +#endif + offset = intel_get_pixmap_offset(pPixmap); + *(uint32_t *)(pI830->batch_ptr + pI830->batch_used) = offset + delta; pI830->batch_used += 4; } @@ -88,8 +100,8 @@ intel_batch_emit_reloc_pixmap(I830Ptr pI830, PixmapPtr pPixmap, uint32_t delta) #define OUT_RELOC(bo, read_domains, write_domains, delta) \ intel_batch_emit_reloc (pI830, bo, read_domains, write_domains, delta) -#define OUT_RELOC_PIXMAP(pPixmap, delta) \ - intel_batch_emit_reloc_pixmap(pI830, pPixmap, delta) +#define OUT_RELOC_PIXMAP(pPixmap, reads, write, delta) \ + intel_batch_emit_reloc_pixmap(pI830, pPixmap, reads, write, delta) union intfloat { float f; diff --git a/src/i830_dri.c b/src/i830_dri.c index 0e5d81dd..d40ada56 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -1514,23 +1514,18 @@ I830DRIClipNotify(ScreenPtr pScreen, WindowPtr *ppWin, int num) static int i830_name_buffer (ScrnInfoPtr pScrn, i830_memory *mem) { - if (mem && mem->gem_handle) + if (mem && mem->bo) { - I830Ptr pI830 = I830PTR(pScrn); - struct drm_gem_flink flink; - int ret; - if (!mem->gem_name) { - flink.handle = mem->gem_handle; - ret = ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_FLINK, &flink); + int ret; + ret = intel_bo_flink(mem->bo, &mem->gem_name); if (ret != 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[drm] failed to name buffer %d\n", -errno); return -1; } - mem->gem_name = flink.name; } return mem->gem_name; } diff --git a/src/i830_dri.h b/src/i830_dri.h index b6a83662..83ddd857 100644 --- a/src/i830_dri.h +++ b/src/i830_dri.h @@ -59,5 +59,4 @@ typedef struct { int dummy; } I830DRIContextRec, *I830DRIContextPtr; - #endif diff --git a/src/i830_driver.c b/src/i830_driver.c index ed974ce2..a810f112 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -849,7 +849,7 @@ i830_update_front_offset(ScrnInfoPtr pScrn) /* If we are still in ScreenInit, there is no screen pixmap to be updated * yet. We'll fix it up at CreateScreenResources. */ - if (!pI830->starting) { + if (!pI830->starting && pI830->accel != ACCEL_UXA) { if (!pScreen->ModifyPixmapHeader(pScreen->GetScreenPixmap(pScreen), -1, -1, -1, -1, -1, (pointer)(pI830->FbBase + @@ -876,6 +876,10 @@ i830CreateScreenResources(ScreenPtr pScreen) i830_update_front_offset(pScrn); +#ifdef I830_USE_UXA + if (pI830->accel == ACCEL_UXA) + i830_uxa_create_screen_resources(pScreen); +#endif return TRUE; } @@ -2534,6 +2538,8 @@ I830BlockHandler(int i, #endif } + if (pI830->accel == ACCEL_UXA) + i830_uxa_block_handler (pScreen); /* * Check for FIFO underruns at block time (which amounts to just * periodically). If this happens, it means our DSPARB or some other @@ -2774,12 +2780,13 @@ i830_fake_fence_wait(void *priv, unsigned int fence) return 0; } -static void +void i830_init_bufmgr(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); - assert(pI830->FbBase != NULL); + if (pI830->bufmgr) return; + if (pI830->memory_manager) { int batch_size; @@ -2792,6 +2799,7 @@ i830_init_bufmgr(ScrnInfoPtr pScrn) pI830->bufmgr = intel_bufmgr_gem_init(pI830->drmSubFD, batch_size); intel_bufmgr_gem_enable_reuse(pI830->bufmgr); } else { + assert(pI830->FbBase != NULL); pI830->bufmgr = intel_bufmgr_fake_init(pI830->fake_bufmgr_mem->offset, pI830->FbBase + pI830->fake_bufmgr_mem->offset, @@ -3412,7 +3420,7 @@ I830LeaveVT(int scrnIndex, int flags) } #endif /* XF86DRI */ - if (pI830->useEXA && IS_I965G(pI830)) + if ((pI830->accel == ACCEL_EXA || pI830->accel == ACCEL_UXA) && IS_I965G(pI830)) gen4_render_state_cleanup(pScrn); if (pI830->AccelInfoRec) @@ -3465,7 +3473,7 @@ I830EnterVT(int scrnIndex, int flags) intel_batch_init(pScrn); - if (pI830->useEXA && IS_I965G(pI830)) + if ((pI830->accel == ACCEL_EXA || pI830->accel == ACCEL_UXA) && IS_I965G(pI830)) gen4_render_state_init(pScrn); if (i830_check_error_state(pScrn)) { diff --git a/src/i830_exa.c b/src/i830_exa.c index f00e4f94..72a1e8d5 100644 --- a/src/i830_exa.c +++ b/src/i830_exa.c @@ -179,6 +179,7 @@ I830EXAPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) I830Ptr pI830 = I830PTR(pScrn); unsigned long pitch; + I830FALLBACK("solid"); if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planemask)) I830FALLBACK("planemask is not solid"); @@ -238,7 +239,7 @@ I830EXASolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) OUT_BATCH(pI830->BR[13] | pitch); OUT_BATCH((y1 << 16) | (x1 & 0xffff)); OUT_BATCH((y2 << 16) | (x2 & 0xffff)); - OUT_RELOC_PIXMAP(pPixmap, 0); + OUT_RELOC_PIXMAP(pPixmap, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH(pI830->BR[16]); ADVANCE_BATCH(); } @@ -265,6 +266,7 @@ I830EXAPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); + I830FALLBACK("copy"); if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planemask)) I830FALLBACK("planemask is not solid"); @@ -331,10 +333,10 @@ I830EXACopy(PixmapPtr pDstPixmap, int src_x1, int src_y1, int dst_x1, OUT_BATCH(pI830->BR[13] | dst_pitch); OUT_BATCH((dst_y1 << 16) | (dst_x1 & 0xffff)); OUT_BATCH((dst_y2 << 16) | (dst_x2 & 0xffff)); - OUT_RELOC_PIXMAP(pDstPixmap, 0); + OUT_RELOC_PIXMAP(pDstPixmap, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH((src_y1 << 16) | (src_x1 & 0xffff)); OUT_BATCH(src_pitch); - OUT_RELOC_PIXMAP(pI830->pSrcPixmap, 0); + OUT_RELOC_PIXMAP(pI830->pSrcPixmap, I915_GEM_DOMAIN_RENDER, 0, 0); ADVANCE_BATCH(); } @@ -538,129 +540,212 @@ I830EXAInit(ScreenPtr pScreen) return TRUE; } -static Bool -i830_uxa_pixmap_is_offscreen(PixmapPtr pPixmap) -{ - ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; - I830Ptr pI830 = I830PTR(pScrn); +static DevPrivateKey uxa_pixmap_key = &uxa_pixmap_key; - /* XXX for now, eventually we'll support 'real' off-screen pixmaps */ - if ((void *)pPixmap->devPrivate.ptr >= (void *)pI830->FbBase && - (void *)pPixmap->devPrivate.ptr < - (void *)(pI830->FbBase + pI830->FbMapSize)) - { - return TRUE; - } else { - return FALSE; +static void +i830_uxa_set_pixmap_bo (PixmapPtr pixmap, dri_bo *bo) +{ + dixSetPrivate(&pixmap->devPrivates, uxa_pixmap_key, bo); +} + +dri_bo * +i830_uxa_get_pixmap_bo (PixmapPtr pixmap) +{ + return dixLookupPrivate(&pixmap->devPrivates, uxa_pixmap_key); +} + +static Bool +i830_uxa_prepare_access (PixmapPtr pixmap, int index) +{ + dri_bo *bo = i830_uxa_get_pixmap_bo (pixmap); + + if (bo) { + if (dri_bo_map (bo, index == UXA_PREPARE_DEST) != 0) + return FALSE; + assert (pixmap->devPrivate.ptr == bo->virtual); + pixmap->devPrivate.ptr = bo->virtual; + } + return TRUE; +} + +void +i830_uxa_block_handler (ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + I830Ptr i830 = I830PTR(scrn); + + if (i830->need_flush) { + dri_bo_wait_rendering (i830->front_buffer->bo); + i830->need_flush = FALSE; } } +static void +i830_uxa_finish_access (PixmapPtr pixmap, int index) +{ + dri_bo *bo = i830_uxa_get_pixmap_bo (pixmap); + + if (bo) { + ScreenPtr screen = pixmap->drawable.pScreen; + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + I830Ptr i830 = I830PTR(scrn); + + dri_bo_unmap (bo); + if (bo == i830->front_buffer->bo) + i830->need_flush = TRUE; + } +} + +static Bool +i830_uxa_pixmap_is_offscreen(PixmapPtr pPixmap) +{ + return i830_uxa_get_pixmap_bo (pPixmap) != NULL; +} + +static PixmapPtr +i830_uxa_create_pixmap (ScreenPtr screen, int w, int h, int depth, unsigned usage) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + I830Ptr i830 = I830PTR(scrn); + dri_bo *bo; + int stride; + PixmapPtr pixmap; + + if (w > 32767 || h > 32767) + return NullPixmap; + + pixmap = fbCreatePixmap (screen, 0, 0, depth, usage); + + if (w && h) + { + stride = ROUND_TO((w * pixmap->drawable.bitsPerPixel + 7) / 8, + i830->accel_pixmap_pitch_alignment); + + bo = dri_bo_alloc (i830->bufmgr, "pixmap", stride * h, + i830->accel_pixmap_offset_alignment); + if (!bo) { + fbDestroyPixmap (pixmap); + return NullPixmap; + } + + if (dri_bo_map (bo, FALSE) != 0) { + fbDestroyPixmap (pixmap); + dri_bo_unreference (bo); + return NullPixmap; + } + + screen->ModifyPixmapHeader (pixmap, w, h, 0, 0, stride, + (pointer) bo->virtual); + + dri_bo_unmap (bo); + i830_uxa_set_pixmap_bo (pixmap, bo); + } + + return pixmap; +} + +static Bool +i830_uxa_destroy_pixmap (PixmapPtr pixmap) +{ + if (pixmap->refcnt == 1) { + dri_bo *bo = i830_uxa_get_pixmap_bo (pixmap); + + if (bo) { + dri_bo_unmap (bo); + dri_bo_unreference (bo); + } + } + fbDestroyPixmap (pixmap); + return TRUE; +} + +void i830_uxa_create_screen_resources(ScreenPtr pScreen) +{ + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + I830Ptr i830 = I830PTR(scrn); + dri_bo *bo = i830->front_buffer->bo; + + if (bo != NULL) { + PixmapPtr pixmap = pScreen->GetScreenPixmap(pScreen); + dri_bo_map (bo, i830->front_buffer->alignment); + pixmap->devPrivate.ptr = bo->virtual; + dri_bo_unmap (bo); + i830_uxa_set_pixmap_bo (pixmap, bo); + } +} Bool i830_uxa_init (ScreenPtr pScreen) { - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - I830Ptr pI830 = I830PTR(pScrn); + ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; + I830Ptr i830 = I830PTR(scrn); - pI830->uxa_driver = uxa_driver_alloc(); - if (pI830->uxa_driver == NULL) { - pI830->accel = ACCEL_NONE; + if (!dixRequestPrivate(uxa_pixmap_key, 0)) + return FALSE; + + i830->uxa_driver = uxa_driver_alloc(); + if (i830->uxa_driver == NULL) { + i830->accel = ACCEL_NONE; return FALSE; } - memset(pI830->uxa_driver, 0, sizeof(*pI830->uxa_driver)); + memset(i830->uxa_driver, 0, sizeof(*i830->uxa_driver)); - pI830->bufferOffset = 0; - pI830->uxa_driver->uxa_major = 1; - pI830->uxa_driver->uxa_minor = 0; + i830->bufferOffset = 0; + i830->uxa_driver->uxa_major = 1; + i830->uxa_driver->uxa_minor = 0; - /* Limits are described in the BLT engine chapter under Graphics Data Size - * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO, - * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO. - * - * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768. - * - * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled. - * i965 limits 3D surface to 4kB-aligned offset if tiled. - * i965 limits 3D surfaces to w,h of ?,8192. - * i965 limits 3D surface to pitch of 1B - 128kB. - * i965 limits 3D surface pitch alignment to 1 or 2 times the element size. - * i965 limits 3D surface pitch alignment to 512B if tiled. - * i965 limits 3D destination drawing rect to w,h of 8192,8192. - * - * i915 limits 3D textures to 4B-aligned offset if un-tiled. - * i915 limits 3D textures to ~4kB-aligned offset if tiled. - * i915 limits 3D textures to width,height of 2048,2048. - * i915 limits 3D textures to pitch of 16B - 8kB, in dwords. - * i915 limits 3D destination to ~4kB-aligned offset if tiled. - * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled. - * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled. - * i915 limits 3D destination to POT aligned pitch if tiled. - * i915 limits 3D destination drawing rect to w,h of 2048,2048. - * - * i845 limits 3D textures to 4B-aligned offset if un-tiled. - * i845 limits 3D textures to ~4kB-aligned offset if tiled. - * i845 limits 3D textures to width,height of 2048,2048. - * i845 limits 3D textures to pitch of 4B - 8kB, in dwords. - * i845 limits 3D destination to 4B-aligned offset if un-tiled. - * i845 limits 3D destination to ~4kB-aligned offset if tiled. - * i845 limits 3D destination to pitch of 8B - 8kB, in dwords. - * i845 limits 3D destination drawing rect to w,h of 2048,2048. - * - * For the tiled issues, the only tiled buffer we draw to should be - * the front, which will have an appropriate pitch/offset already set up, - * so EXA doesn't need to worry. - */ - if (IS_I965G(pI830)) { - pI830->uxa_driver->maxX = 8192; - pI830->uxa_driver->maxY = 8192; - } else { - pI830->uxa_driver->maxX = 2048; - pI830->uxa_driver->maxY = 2048; - } + i830->uxa_driver->maxX = i830->accel_max_x; + i830->uxa_driver->maxY = i830->accel_max_y; /* Sync */ - pI830->uxa_driver->WaitMarker = I830EXASync; + i830->uxa_driver->WaitMarker = I830EXASync; /* Solid fill */ - pI830->uxa_driver->PrepareSolid = I830EXAPrepareSolid; - pI830->uxa_driver->Solid = I830EXASolid; - pI830->uxa_driver->DoneSolid = I830EXADoneSolid; + i830->uxa_driver->PrepareSolid = I830EXAPrepareSolid; + i830->uxa_driver->Solid = I830EXASolid; + i830->uxa_driver->DoneSolid = I830EXADoneSolid; /* Copy */ - pI830->uxa_driver->PrepareCopy = I830EXAPrepareCopy; - pI830->uxa_driver->Copy = I830EXACopy; - pI830->uxa_driver->DoneCopy = I830EXADoneCopy; + i830->uxa_driver->PrepareCopy = I830EXAPrepareCopy; + i830->uxa_driver->Copy = I830EXACopy; + i830->uxa_driver->DoneCopy = I830EXADoneCopy; /* Composite */ - if (!IS_I9XX(pI830)) { - pI830->uxa_driver->CheckComposite = i830_check_composite; - pI830->uxa_driver->PrepareComposite = i830_prepare_composite; - pI830->uxa_driver->Composite = i830_composite; - pI830->uxa_driver->DoneComposite = i830_done_composite; - } else if (IS_I915G(pI830) || IS_I915GM(pI830) || - IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) + if (!IS_I9XX(i830)) { + i830->uxa_driver->CheckComposite = i830_check_composite; + i830->uxa_driver->PrepareComposite = i830_prepare_composite; + i830->uxa_driver->Composite = i830_composite; + i830->uxa_driver->DoneComposite = i830_done_composite; + } else if (IS_I915G(i830) || IS_I915GM(i830) || + IS_I945G(i830) || IS_I945GM(i830) || IS_G33CLASS(i830)) { - pI830->uxa_driver->CheckComposite = i915_check_composite; - pI830->uxa_driver->PrepareComposite = i915_prepare_composite; - pI830->uxa_driver->Composite = i830_composite; - pI830->uxa_driver->DoneComposite = i830_done_composite; + i830->uxa_driver->CheckComposite = i915_check_composite; + i830->uxa_driver->PrepareComposite = i915_prepare_composite; + i830->uxa_driver->Composite = i830_composite; + i830->uxa_driver->DoneComposite = i830_done_composite; } else { - pI830->uxa_driver->CheckComposite = i965_check_composite; - pI830->uxa_driver->PrepareComposite = i965_prepare_composite; - pI830->uxa_driver->Composite = i965_composite; - pI830->uxa_driver->DoneComposite = i830_done_composite; + i830->uxa_driver->CheckComposite = i965_check_composite; + i830->uxa_driver->PrepareComposite = i965_prepare_composite; + i830->uxa_driver->Composite = i965_composite; + i830->uxa_driver->DoneComposite = i830_done_composite; } - pI830->uxa_driver->PixmapIsOffscreen = i830_uxa_pixmap_is_offscreen; - if(!uxa_driver_init(pScreen, pI830->uxa_driver)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, + i830->uxa_driver->PrepareAccess = i830_uxa_prepare_access; + i830->uxa_driver->FinishAccess = i830_uxa_finish_access; + i830->uxa_driver->PixmapIsOffscreen = i830_uxa_pixmap_is_offscreen; + + if(!uxa_driver_init(pScreen, i830->uxa_driver)) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, "UXA initialization failed\n"); - xfree(pI830->uxa_driver); - pI830->accel = ACCEL_NONE; + xfree(i830->uxa_driver); + i830->accel = ACCEL_NONE; return FALSE; } - I830SelectBuffer(pScrn, I830_SELECT_FRONT); + pScreen->CreatePixmap = i830_uxa_create_pixmap; + pScreen->DestroyPixmap = i830_uxa_destroy_pixmap; + + I830SelectBuffer(scrn, I830_SELECT_FRONT); return TRUE; } diff --git a/src/i830_memory.c b/src/i830_memory.c index c1748b3e..ff5def69 100644 --- a/src/i830_memory.c +++ b/src/i830_memory.c @@ -166,24 +166,16 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem) return TRUE; #ifdef XF86DRI - if (mem->gem_handle != 0) { - I830Ptr pI830 = I830PTR(pScrn); - struct drm_i915_gem_pin pin; - int ret; - - pin.handle = mem->gem_handle; - pin.alignment = mem->alignment; - - ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_PIN, &pin); - if (ret != 0) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Failed to pin %s: %s\n", - mem->name, strerror(errno)); + if (mem->bo != NULL) { + if (intel_bo_pin (mem->bo, mem->alignment) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to pin %s: %s\n", + mem->name, strerror(errno)); return FALSE; } mem->bound = TRUE; - mem->offset = pin.offset; + mem->offset = mem->bo->offset; mem->end = mem->offset + mem->size; } #endif @@ -219,15 +211,8 @@ i830_unbind_memory(ScrnInfoPtr pScrn, i830_memory *mem) i830_clear_tiling(pScrn, mem->fence_nr); #ifdef XF86DRI - if (mem->gem_handle != 0) { - I830Ptr pI830 = I830PTR(pScrn); - struct drm_i915_gem_unpin unpin; - int ret; - - unpin.handle = mem->gem_handle; - ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_UNPIN, &unpin); - - if (ret == 0) { + if (mem->bo != NULL) { + if (intel_bo_unpin (mem->bo) == 0) { mem->bound = FALSE; /* Give buffer obviously wrong offset/end until it's re-pinned. */ mem->offset = -1; @@ -257,12 +242,9 @@ i830_free_memory(ScrnInfoPtr pScrn, i830_memory *mem) i830_unbind_memory(pScrn, mem); #ifdef XF86DRI - if (mem->gem_handle != 0) { + if (mem->bo != NULL) { I830Ptr pI830 = I830PTR(pScrn); - struct drm_gem_close close; - - close.handle = mem->gem_handle; - ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_CLOSE, &close); + dri_bo_unreference (mem->bo); if (pI830->bo_list == mem) { pI830->bo_list = mem->next; if (mem->next) @@ -493,6 +475,7 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size) i830_free_memory(pScrn, pI830->memory_manager); pI830->memory_manager = NULL; } + i830_init_bufmgr(pScrn); } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to allocate space for kernel memory manager\n"); @@ -735,8 +718,6 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, { I830Ptr pI830 = I830PTR(pScrn); i830_memory *mem; - int ret; - struct drm_i915_gem_create create; assert((flags & NEED_PHYSICAL_ADDR) == 0); @@ -754,16 +735,13 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, return NULL; } - memset(&create, 0, sizeof(create)); - create.size = size; + mem->bo = dri_bo_alloc (pI830->bufmgr, name, size, align); - ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_CREATE, &create); - if (ret) { + if (!mem->bo) { xfree(mem->name); xfree(mem); return NULL; } - mem->gem_handle = create.handle; /* Give buffer obviously wrong offset/end until it's pinned. */ mem->offset = -1; @@ -777,10 +755,7 @@ i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name, /* Bind it if we currently control the VT */ if (pScrn->vtSema) { if (!i830_bind_memory(pScrn, mem)) { - struct drm_gem_close close; - - close.handle = mem->gem_handle; - ioctl(pI830->drmSubFD, DRM_IOCTL_GEM_CLOSE, &close); + dri_bo_unreference (mem->bo); xfree(mem->name); xfree(mem); return NULL; @@ -908,19 +883,17 @@ i830_allocate_memory_tiled(ScrnInfoPtr pScrn, const char *name, mem->fence_nr = -1; #ifdef XF86DRI - if (mem->gem_handle != 0) { - struct drm_i915_gem_set_tiling set_tiling; - int ret; + if (mem->bo != 0) { + uint32_t tiling_mode = I915_TILING_NONE; + int ret; - set_tiling.handle = mem->gem_handle; if (tile_format == TILE_XMAJOR) - set_tiling.tiling_mode = I915_TILING_X; + tiling_mode = I915_TILING_X; else - set_tiling.tiling_mode = I915_TILING_Y; + tiling_mode = I915_TILING_Y; - ret = ioctl(pI830->drmSubFD, DRM_IOCTL_I915_GEM_SET_TILING, - &set_tiling); - if (ret != 0 || set_tiling.tiling_mode == I915_TILING_NONE) { + ret = intel_bo_set_tiling (mem->bo, &tiling_mode); + if (ret != 0 || tiling_mode == I915_TILING_NONE) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set tiling on %s: %s\n", mem->name, diff --git a/src/i830_render.c b/src/i830_render.c index d5cab3f3..4b42ea37 100644 --- a/src/i830_render.c +++ b/src/i830_render.c @@ -313,7 +313,7 @@ i830_texture_setup(PicturePtr pPict, PixmapPtr pPix, int unit) BEGIN_BATCH(10); OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | LOAD_TEXTURE_MAP(unit) | 4); - OUT_RELOC_PIXMAP(pPix, TM0S0_USE_FENCE); + OUT_RELOC_PIXMAP(pPix, I915_GEM_DOMAIN_SAMPLER, 0, TM0S0_USE_FENCE); OUT_BATCH(((pPix->drawable.height - 1) << TM0S1_HEIGHT_SHIFT) | ((pPix->drawable.width - 1) << TM0S1_WIDTH_SHIFT) | format); OUT_BATCH((pitch/4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D); @@ -444,7 +444,7 @@ i830_prepare_composite(int op, PicturePtr pSrcPicture, OUT_BATCH(_3DSTATE_BUF_INFO_CMD); OUT_BATCH(BUF_3D_ID_COLOR_BACK| BUF_3D_USE_FENCE | BUF_3D_PITCH(dst_pitch)); - OUT_RELOC_PIXMAP(pDst, 0); + OUT_RELOC_PIXMAP(pDst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH(MI_NOOP); OUT_BATCH(_3DSTATE_DST_BUF_VARS_CMD); diff --git a/src/i915_render.c b/src/i915_render.c index 54197bfd..78376354 100644 --- a/src/i915_render.c +++ b/src/i915_render.c @@ -322,6 +322,8 @@ i915_prepare_composite(int op, PicturePtr pSrcPicture, Bool is_affine_src, is_affine_mask; Bool is_nearest = FALSE; + return FALSE; + i830_exa_check_pitch_3d(pSrc); if (pMask) i830_exa_check_pitch_3d(pMask); @@ -360,7 +362,7 @@ i915_prepare_composite(int op, PicturePtr pSrcPicture, BEGIN_BATCH(10); OUT_BATCH(_3DSTATE_MAP_STATE | 3); OUT_BATCH(0x00000001); /* map 0 */ - OUT_RELOC_PIXMAP(pSrc, 0); + OUT_RELOC_PIXMAP(pSrc, I915_GEM_DOMAIN_SAMPLER, 0, 0); OUT_BATCH(pI830->mapstate[1]); OUT_BATCH(pI830->mapstate[2]); @@ -374,10 +376,10 @@ i915_prepare_composite(int op, PicturePtr pSrcPicture, BEGIN_BATCH(16); OUT_BATCH(_3DSTATE_MAP_STATE | 6); OUT_BATCH(0x00000003); /* map 0,1 */ - OUT_RELOC_PIXMAP(pSrc, 0); + OUT_RELOC_PIXMAP(pSrc, I915_GEM_DOMAIN_SAMPLER, 0, 0); OUT_BATCH(pI830->mapstate[1]); OUT_BATCH(pI830->mapstate[2]); - OUT_RELOC_PIXMAP(pMask, 0); + OUT_RELOC_PIXMAP(pMask, I915_GEM_DOMAIN_SAMPLER, 0, 0); OUT_BATCH(pI830->mapstate[4]); OUT_BATCH(pI830->mapstate[5]); @@ -398,7 +400,7 @@ i915_prepare_composite(int op, PicturePtr pSrcPicture, OUT_BATCH(_3DSTATE_BUF_INFO_CMD); OUT_BATCH(BUF_3D_ID_COLOR_BACK| BUF_3D_USE_FENCE| BUF_3D_PITCH(dst_pitch)); - OUT_RELOC_PIXMAP(pDst, 0); + OUT_RELOC_PIXMAP(pDst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH(_3DSTATE_DST_BUF_VARS_CMD); OUT_BATCH(dst_format); diff --git a/src/i915_video.c b/src/i915_video.c index e2954a76..7761a454 100644 --- a/src/i915_video.c +++ b/src/i915_video.c @@ -130,7 +130,7 @@ I915DisplayVideoTextured(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, int id, OUT_BATCH(_3DSTATE_BUF_INFO_CMD); OUT_BATCH(BUF_3D_ID_COLOR_BACK | BUF_3D_USE_FENCE | BUF_3D_PITCH(intel_get_pixmap_pitch(pPixmap))); - OUT_RELOC_PIXMAP(pPixmap, 0); + OUT_RELOC_PIXMAP(pPixmap, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); ADVANCE_BATCH(); if (!planar) { From 66706718553cd272eab6f817b5a059df3e0a4347 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Aug 2008 04:10:21 -0700 Subject: [PATCH 38/45] Add throttling --- src/i830_driver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/i830_driver.c b/src/i830_driver.c index a810f112..bef3bb83 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -2531,6 +2531,10 @@ I830BlockHandler(int i, * fashion. */ intel_batch_flush(pScrn); +#ifdef XF86DRI + if (pI830->memory_manager) + drmCommandNone(pI830->drmSubFD, DRM_I915_GEM_THROTTLE); +#endif pI830->need_mi_flush = FALSE; #ifdef XF86DRI From c155bb3cb17a3bd3b2e90be52cd1fc90147c4e17 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Aug 2008 04:11:13 -0700 Subject: [PATCH 39/45] Add batch flush in i830_uxa_prepare_access --- src/i830_exa.c | 13 ++++--------- src/i915_render.c | 2 -- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/i830_exa.c b/src/i830_exa.c index 72a1e8d5..7609239d 100644 --- a/src/i830_exa.c +++ b/src/i830_exa.c @@ -179,7 +179,6 @@ I830EXAPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) I830Ptr pI830 = I830PTR(pScrn); unsigned long pitch; - I830FALLBACK("solid"); if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planemask)) I830FALLBACK("planemask is not solid"); @@ -266,7 +265,6 @@ I830EXAPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); - I830FALLBACK("copy"); if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planemask)) I830FALLBACK("planemask is not solid"); @@ -560,10 +558,10 @@ i830_uxa_prepare_access (PixmapPtr pixmap, int index) dri_bo *bo = i830_uxa_get_pixmap_bo (pixmap); if (bo) { + intel_batch_flush(xf86Screens[pixmap->drawable.pScreen->myNum]); if (dri_bo_map (bo, index == UXA_PREPARE_DEST) != 0) return FALSE; - assert (pixmap->devPrivate.ptr == bo->virtual); - pixmap->devPrivate.ptr = bo->virtual; + pixmap->devPrivate.ptr = bo->virtual; } return TRUE; } @@ -597,9 +595,9 @@ i830_uxa_finish_access (PixmapPtr pixmap, int index) } static Bool -i830_uxa_pixmap_is_offscreen(PixmapPtr pPixmap) +i830_uxa_pixmap_is_offscreen(PixmapPtr pixmap) { - return i830_uxa_get_pixmap_bo (pPixmap) != NULL; + return i830_uxa_get_pixmap_bo (pixmap) != NULL; } static PixmapPtr @@ -667,9 +665,6 @@ void i830_uxa_create_screen_resources(ScreenPtr pScreen) if (bo != NULL) { PixmapPtr pixmap = pScreen->GetScreenPixmap(pScreen); - dri_bo_map (bo, i830->front_buffer->alignment); - pixmap->devPrivate.ptr = bo->virtual; - dri_bo_unmap (bo); i830_uxa_set_pixmap_bo (pixmap, bo); } } diff --git a/src/i915_render.c b/src/i915_render.c index 78376354..970c42ad 100644 --- a/src/i915_render.c +++ b/src/i915_render.c @@ -322,8 +322,6 @@ i915_prepare_composite(int op, PicturePtr pSrcPicture, Bool is_affine_src, is_affine_mask; Bool is_nearest = FALSE; - return FALSE; - i830_exa_check_pitch_3d(pSrc); if (pMask) i830_exa_check_pitch_3d(pMask); From fc4d9c55a7fa8001786c1e4da10f005406c57ece Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Aug 2008 18:17:20 -0700 Subject: [PATCH 40/45] Change PrepareAccess to take access mode rather than index --- src/i830_exa.c | 53 ++++++++++++-------------- uxa/uxa-accel.c | 25 ++++++------ uxa/uxa-priv.h | 4 +- uxa/uxa-render.c | 16 ++++---- uxa/uxa-unaccel.c | 96 +++++++++++++++++++++++------------------------ uxa/uxa.c | 28 +++++++------- uxa/uxa.h | 36 +++++------------- 7 files changed, 116 insertions(+), 142 deletions(-) diff --git a/src/i830_exa.c b/src/i830_exa.c index 7609239d..08d73b5d 100644 --- a/src/i830_exa.c +++ b/src/i830_exa.c @@ -553,19 +553,36 @@ i830_uxa_get_pixmap_bo (PixmapPtr pixmap) } static Bool -i830_uxa_prepare_access (PixmapPtr pixmap, int index) +i830_uxa_prepare_access (PixmapPtr pixmap, uxa_access_t access) { dri_bo *bo = i830_uxa_get_pixmap_bo (pixmap); if (bo) { intel_batch_flush(xf86Screens[pixmap->drawable.pScreen->myNum]); - if (dri_bo_map (bo, index == UXA_PREPARE_DEST) != 0) + if (dri_bo_map (bo, access == UXA_ACCESS_RW) != 0) return FALSE; pixmap->devPrivate.ptr = bo->virtual; } return TRUE; } +static void +i830_uxa_finish_access (PixmapPtr pixmap) +{ + dri_bo *bo = i830_uxa_get_pixmap_bo (pixmap); + + if (bo) { + ScreenPtr screen = pixmap->drawable.pScreen; + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + I830Ptr i830 = I830PTR(scrn); + + dri_bo_unmap (bo); + pixmap->devPrivate.ptr = NULL; + if (bo == i830->front_buffer->bo) + i830->need_flush = TRUE; + } +} + void i830_uxa_block_handler (ScreenPtr screen) { @@ -578,22 +595,6 @@ i830_uxa_block_handler (ScreenPtr screen) } } -static void -i830_uxa_finish_access (PixmapPtr pixmap, int index) -{ - dri_bo *bo = i830_uxa_get_pixmap_bo (pixmap); - - if (bo) { - ScreenPtr screen = pixmap->drawable.pScreen; - ScrnInfoPtr scrn = xf86Screens[screen->myNum]; - I830Ptr i830 = I830PTR(scrn); - - dri_bo_unmap (bo); - if (bo == i830->front_buffer->bo) - i830->need_flush = TRUE; - } -} - static Bool i830_uxa_pixmap_is_offscreen(PixmapPtr pixmap) { @@ -626,16 +627,8 @@ i830_uxa_create_pixmap (ScreenPtr screen, int w, int h, int depth, unsigned usag return NullPixmap; } - if (dri_bo_map (bo, FALSE) != 0) { - fbDestroyPixmap (pixmap); - dri_bo_unreference (bo); - return NullPixmap; - } - - screen->ModifyPixmapHeader (pixmap, w, h, 0, 0, stride, - (pointer) bo->virtual); + screen->ModifyPixmapHeader (pixmap, w, h, 0, 0, stride, NULL); - dri_bo_unmap (bo); i830_uxa_set_pixmap_bo (pixmap, bo); } @@ -648,10 +641,8 @@ i830_uxa_destroy_pixmap (PixmapPtr pixmap) if (pixmap->refcnt == 1) { dri_bo *bo = i830_uxa_get_pixmap_bo (pixmap); - if (bo) { - dri_bo_unmap (bo); + if (bo) dri_bo_unreference (bo); - } } fbDestroyPixmap (pixmap); return TRUE; @@ -705,6 +696,7 @@ i830_uxa_init (ScreenPtr pScreen) i830->uxa_driver->Copy = I830EXACopy; i830->uxa_driver->DoneCopy = I830EXADoneCopy; +#if 0 /* Composite */ if (!IS_I9XX(i830)) { i830->uxa_driver->CheckComposite = i830_check_composite; @@ -724,6 +716,7 @@ i830_uxa_init (ScreenPtr pScreen) i830->uxa_driver->Composite = i965_composite; i830->uxa_driver->DoneComposite = i830_done_composite; } +#endif i830->uxa_driver->PrepareAccess = i830_uxa_prepare_access; i830->uxa_driver->FinishAccess = i830_uxa_finish_access; diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c index 7c7b3e9b..20a56574 100644 --- a/uxa/uxa-accel.c +++ b/uxa/uxa-accel.c @@ -189,8 +189,7 @@ uxa_do_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int dstXoff, dstYoff; if (!access_prepared) { - uxa_prepare_access(pDrawable, UXA_PREPARE_DEST); - + uxa_prepare_access(pDrawable, UXA_ACCESS_RW); access_prepared = TRUE; } @@ -210,7 +209,7 @@ uxa_do_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, } if (access_prepared) - uxa_finish_access(pDrawable, UXA_PREPARE_DEST); + uxa_finish_access(pDrawable); else uxa_mark_sync(pDrawable->pScreen); @@ -240,10 +239,10 @@ uxa_do_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, if (!pPixmap) return FALSE; - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); fbCopyArea((DrawablePtr)pPixmap, pDrawable, pGC, sx, sy, sw, sh, dx, dy); - uxa_finish_access(pDrawable, UXA_PREPARE_DEST); + uxa_finish_access(pDrawable); FreeScratchPixmapHeader(pPixmap); @@ -266,10 +265,10 @@ uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int form { if (!uxa_do_shm_put_image(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data)) { - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data); - uxa_finish_access(pDrawable, UXA_PREPARE_DEST); + uxa_finish_access(pDrawable); } } @@ -474,12 +473,12 @@ fallback: UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable, uxa_drawable_location(pSrcDrawable), uxa_drawable_location(pDstDrawable))); - uxa_prepare_access (pDstDrawable, UXA_PREPARE_DEST); - uxa_prepare_access (pSrcDrawable, UXA_PREPARE_SRC); + uxa_prepare_access (pDstDrawable, UXA_ACCESS_RW); + uxa_prepare_access (pSrcDrawable, UXA_ACCESS_RO); fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse, upsidedown, bitplane, closure); - uxa_finish_access (pSrcDrawable, UXA_PREPARE_SRC); - uxa_finish_access (pDstDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pSrcDrawable); + uxa_finish_access (pDstDrawable); } RegionPtr @@ -1029,9 +1028,9 @@ fallback: UXA_FALLBACK(("from %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); - uxa_prepare_access (pDrawable, UXA_PREPARE_SRC); + uxa_prepare_access (pDrawable, UXA_ACCESS_RO); fbGetImage (pDrawable, x, y, w, h, format, planeMask, d); - uxa_finish_access (pDrawable, UXA_PREPARE_SRC); + uxa_finish_access (pDrawable); out: return; diff --git a/uxa/uxa-priv.h b/uxa/uxa-priv.h index acc82bba..1e4f4ead 100644 --- a/uxa/uxa-priv.h +++ b/uxa/uxa-priv.h @@ -350,10 +350,10 @@ uxa_check_composite (CARD8 op, /* uxa.c */ void -uxa_prepare_access(DrawablePtr pDrawable, int index); +uxa_prepare_access(DrawablePtr pDrawable, uxa_access_t access); void -uxa_finish_access(DrawablePtr pDrawable, int index); +uxa_finish_access(DrawablePtr pDrawable); void uxa_get_drawable_deltas (DrawablePtr pDrawable, PixmapPtr pPixmap, diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c index 38e6088f..9c79fce5 100644 --- a/uxa/uxa-render.c +++ b/uxa/uxa-render.c @@ -926,12 +926,12 @@ uxa_trapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, xoff += pDraw->x; yoff += pDraw->y; - uxa_prepare_access(pDraw, UXA_PREPARE_DEST); + uxa_prepare_access(pDraw, UXA_ACCESS_RW); for (; ntrap; ntrap--, traps++) (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0); - uxa_finish_access(pDraw, UXA_PREPARE_DEST); + uxa_finish_access(pDraw); } else if (maskFormat) { @@ -948,11 +948,11 @@ uxa_trapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, if (!pPicture) return; - uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW); for (; ntrap; ntrap--, traps++) (*ps->RasterizeTrapezoid) (pPicture, traps, -bounds.x1, -bounds.y1); - uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST); + uxa_finish_access(pPicture->pDrawable); xRel = bounds.x1 + xSrc - xDst; yRel = bounds.y1 + ySrc - yDst; @@ -1009,9 +1009,9 @@ uxa_triangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, if (direct) { DrawablePtr pDraw = pDst->pDrawable; - uxa_prepare_access(pDraw, UXA_PREPARE_DEST); + uxa_prepare_access(pDraw, UXA_ACCESS_RW); (*ps->AddTriangles) (pDst, 0, 0, ntri, tris); - uxa_finish_access(pDraw, UXA_PREPARE_DEST); + uxa_finish_access(pDraw); } else if (maskFormat) { @@ -1028,9 +1028,9 @@ uxa_triangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, if (!pPicture) return; - uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW); (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); - uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST); + uxa_finish_access(pPicture->pDrawable); xRel = bounds.x1 + xSrc - xDst; yRel = bounds.y1 + ySrc - yDst; diff --git a/uxa/uxa-unaccel.c b/uxa/uxa-unaccel.c index 27194208..01c13224 100644 --- a/uxa/uxa-unaccel.c +++ b/uxa/uxa-unaccel.c @@ -45,9 +45,9 @@ void uxa_prepare_access_gc(GCPtr pGC) { if (pGC->stipple) - uxa_prepare_access(&pGC->stipple->drawable, UXA_PREPARE_MASK); + uxa_prepare_access(&pGC->stipple->drawable, UXA_ACCESS_RO); if (pGC->fillStyle == FillTiled) - uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC); + uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_ACCESS_RO); } /** @@ -57,9 +57,9 @@ void uxa_finish_access_gc(GCPtr pGC) { if (pGC->fillStyle == FillTiled) - uxa_finish_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_MASK); + uxa_finish_access(&pGC->tile.pixmap->drawable); if (pGC->stipple) - uxa_finish_access(&pGC->stipple->drawable, UXA_PREPARE_SRC); + uxa_finish_access(&pGC->stipple->drawable); } #if DEBUG_TRACE_FALL @@ -75,11 +75,11 @@ uxa_check_fill_spans (DrawablePtr pDrawable, GCPtr pGC, int nspans, DDXPointPtr ppt, int *pwidth, int fSorted) { UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); uxa_prepare_access_gc (pGC); fbFillSpans (pDrawable, pGC, nspans, ppt, pwidth, fSorted); uxa_finish_access_gc (pGC); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pDrawable); } void @@ -87,9 +87,9 @@ uxa_check_set_spans (DrawablePtr pDrawable, GCPtr pGC, char *psrc, DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) { UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); fbSetSpans (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pDrawable); } void @@ -98,9 +98,9 @@ uxa_check_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, char *bits) { UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pDrawable); } RegionPtr @@ -111,11 +111,11 @@ uxa_check_copy_area (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, uxa_drawable_location(pSrc), uxa_drawable_location(pDst))); - uxa_prepare_access (pDst, UXA_PREPARE_DEST); - uxa_prepare_access (pSrc, UXA_PREPARE_SRC); + uxa_prepare_access (pDst, UXA_ACCESS_RW); + uxa_prepare_access (pSrc, UXA_ACCESS_RO); ret = fbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); - uxa_finish_access (pSrc, UXA_PREPARE_SRC); - uxa_finish_access (pDst, UXA_PREPARE_DEST); + uxa_finish_access (pSrc); + uxa_finish_access (pDst); return ret; } @@ -129,12 +129,12 @@ uxa_check_copy_plane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst, uxa_drawable_location(pSrc), uxa_drawable_location(pDst))); - uxa_prepare_access (pDst, UXA_PREPARE_DEST); - uxa_prepare_access (pSrc, UXA_PREPARE_SRC); + uxa_prepare_access (pDst, UXA_ACCESS_RW); + uxa_prepare_access (pSrc, UXA_ACCESS_RO); ret = fbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, bitPlane); - uxa_finish_access (pSrc, UXA_PREPARE_SRC); - uxa_finish_access (pDst, UXA_PREPARE_DEST); + uxa_finish_access (pSrc); + uxa_finish_access (pDst); return ret; } @@ -144,9 +144,9 @@ uxa_check_poly_point (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr pptInit) { UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); fbPolyPoint (pDrawable, pGC, mode, npt, pptInit); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pDrawable); } void @@ -158,11 +158,11 @@ uxa_check_poly_lines (DrawablePtr pDrawable, GCPtr pGC, pGC->lineWidth, mode, npt)); if (pGC->lineWidth == 0) { - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); uxa_prepare_access_gc (pGC); fbPolyLine (pDrawable, pGC, mode, npt, ppt); uxa_finish_access_gc (pGC); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pDrawable); return; } /* fb calls mi functions in the lineWidth != 0 case. */ @@ -176,11 +176,11 @@ uxa_check_poly_segment (DrawablePtr pDrawable, GCPtr pGC, UXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable, uxa_drawable_location(pDrawable), pGC->lineWidth, nsegInit)); if (pGC->lineWidth == 0) { - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); uxa_prepare_access_gc (pGC); fbPolySegment (pDrawable, pGC, nsegInit, pSegInit); uxa_finish_access_gc (pGC); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pDrawable); return; } /* fb calls mi functions in the lineWidth != 0 case. */ @@ -200,11 +200,11 @@ uxa_check_poly_arc (DrawablePtr pDrawable, GCPtr pGC, #if 0 if (pGC->lineWidth == 0) { - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); uxa_prepare_access_gc (pGC); fbPolyArc (pDrawable, pGC, narcs, pArcs); uxa_finish_access_gc (pGC); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pDrawable); return; } #endif @@ -217,11 +217,11 @@ uxa_check_poly_fill_rect (DrawablePtr pDrawable, GCPtr pGC, { UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); uxa_prepare_access_gc (pGC); fbPolyFillRect (pDrawable, pGC, nrect, prect); uxa_finish_access_gc (pGC); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pDrawable); } void @@ -231,11 +231,11 @@ uxa_check_image_glyph_blt (DrawablePtr pDrawable, GCPtr pGC, { UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); uxa_prepare_access_gc (pGC); fbImageGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); uxa_finish_access_gc (pGC); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pDrawable); } void @@ -245,11 +245,11 @@ uxa_check_poly_glyph_blt (DrawablePtr pDrawable, GCPtr pGC, { UXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable, uxa_drawable_location(pDrawable), pGC->fillStyle, pGC->alu)); - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); uxa_prepare_access_gc (pGC); fbPolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); uxa_finish_access_gc (pGC); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pDrawable); } void @@ -260,13 +260,13 @@ uxa_check_push_pixels (GCPtr pGC, PixmapPtr pBitmap, UXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable, uxa_drawable_location(&pBitmap->drawable), uxa_drawable_location(pDrawable))); - uxa_prepare_access (pDrawable, UXA_PREPARE_DEST); - uxa_prepare_access (&pBitmap->drawable, UXA_PREPARE_SRC); + uxa_prepare_access (pDrawable, UXA_ACCESS_RW); + uxa_prepare_access (&pBitmap->drawable, UXA_ACCESS_RO); uxa_prepare_access_gc (pGC); fbPushPixels (pGC, pBitmap, pDrawable, w, h, x, y); uxa_finish_access_gc (pGC); - uxa_finish_access (&pBitmap->drawable, UXA_PREPARE_SRC); - uxa_finish_access (pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (&pBitmap->drawable); + uxa_finish_access (pDrawable); } void @@ -278,9 +278,9 @@ uxa_check_get_spans (DrawablePtr pDrawable, char *pdstStart) { UXA_FALLBACK(("from %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable))); - uxa_prepare_access (pDrawable, UXA_PREPARE_SRC); + uxa_prepare_access (pDrawable, UXA_ACCESS_RO); fbGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); - uxa_finish_access (pDrawable, UXA_PREPARE_SRC); + uxa_finish_access (pDrawable); } void @@ -300,11 +300,11 @@ uxa_check_composite (CARD8 op, UXA_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst)); - uxa_prepare_access (pDst->pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access (pDst->pDrawable, UXA_ACCESS_RW); if (pSrc->pDrawable != NULL) - uxa_prepare_access (pSrc->pDrawable, UXA_PREPARE_SRC); + uxa_prepare_access (pSrc->pDrawable, UXA_ACCESS_RO); if (pMask && pMask->pDrawable != NULL) - uxa_prepare_access (pMask->pDrawable, UXA_PREPARE_MASK); + uxa_prepare_access (pMask->pDrawable, UXA_ACCESS_RO); fbComposite (op, pSrc, pMask, @@ -318,10 +318,10 @@ uxa_check_composite (CARD8 op, width, height); if (pMask && pMask->pDrawable != NULL) - uxa_finish_access (pMask->pDrawable, UXA_PREPARE_MASK); + uxa_finish_access (pMask->pDrawable); if (pSrc->pDrawable != NULL) - uxa_finish_access (pSrc->pDrawable, UXA_PREPARE_SRC); - uxa_finish_access (pDst->pDrawable, UXA_PREPARE_DEST); + uxa_finish_access (pSrc->pDrawable); + uxa_finish_access (pDst->pDrawable); } void @@ -333,9 +333,9 @@ uxa_check_add_traps (PicturePtr pPicture, { UXA_FALLBACK(("to pict %p (%c)\n", uxa_drawable_location(pPicture->pDrawable))); - uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST); + uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW); fbAddTraps (pPicture, x_off, y_off, ntrap, traps); - uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST); + uxa_finish_access(pPicture->pDrawable); } /** @@ -350,7 +350,7 @@ uxa_get_pixmap_first_pixel (PixmapPtr pPixmap) CARD32 pixel; void *fb; - uxa_prepare_access (&pPixmap->drawable, UXA_PREPARE_SRC); + uxa_prepare_access (&pPixmap->drawable, UXA_ACCESS_RO); fb = pPixmap->devPrivate.ptr; switch (pPixmap->drawable.bitsPerPixel) { @@ -364,7 +364,7 @@ uxa_get_pixmap_first_pixel (PixmapPtr pPixmap) pixel = *(CARD8 *)fb; break; } - uxa_finish_access(&pPixmap->drawable, UXA_PREPARE_SRC); + uxa_finish_access(&pPixmap->drawable); return pixel; } diff --git a/uxa/uxa.c b/uxa/uxa.c index 7201e7c6..5fe0f32f 100644 --- a/uxa/uxa.c +++ b/uxa/uxa.c @@ -141,7 +141,7 @@ uxa_get_offscreen_pixmap (DrawablePtr drawable, int *xp, int *yp) * PrepareAccess() is necessary, and working around PrepareAccess() failure. */ void -uxa_prepare_access(DrawablePtr pDrawable, int index) +uxa_prepare_access(DrawablePtr pDrawable, uxa_access_t access) { ScreenPtr pScreen = pDrawable->pScreen; uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); @@ -152,7 +152,7 @@ uxa_prepare_access(DrawablePtr pDrawable, int index) return; if (uxa_screen->info->PrepareAccess) - (*uxa_screen->info->PrepareAccess) (pPixmap, index); + (*uxa_screen->info->PrepareAccess) (pPixmap, access); } /** @@ -161,7 +161,7 @@ uxa_prepare_access(DrawablePtr pDrawable, int index) * It deals with calling the driver's FinishAccess() only if necessary. */ void -uxa_finish_access(DrawablePtr pDrawable, int index) +uxa_finish_access(DrawablePtr pDrawable) { ScreenPtr pScreen = pDrawable->pScreen; uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); @@ -173,7 +173,7 @@ uxa_finish_access(DrawablePtr pDrawable, int index) if (!uxa_pixmap_is_offscreen (pPixmap)) return; - (*uxa_screen->info->FinishAccess) (pPixmap, index); + (*uxa_screen->info->FinishAccess) (pPixmap); } /** @@ -209,10 +209,10 @@ uxa_validate_gc (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) * allocated pixmap. This isn't a problem yet, since we don't * put pixmaps in FB until at least one accelerated UXA op. */ - uxa_prepare_access(&pOldTile->drawable, UXA_PREPARE_SRC); + uxa_prepare_access(&pOldTile->drawable, UXA_ACCESS_RO); pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel); - uxa_finish_access(&pOldTile->drawable, UXA_PREPARE_SRC); + uxa_finish_access(&pOldTile->drawable); } if (pNewTile) { @@ -227,9 +227,9 @@ uxa_validate_gc (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width * pDrawable->bitsPerPixel)) { - uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC); + uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_ACCESS_RW); fbPadPixmap (pGC->tile.pixmap); - uxa_finish_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC); + uxa_finish_access(&pGC->tile.pixmap->drawable); } /* Mask out the GCTile change notification, now that we've done FB's * job for it. @@ -273,20 +273,20 @@ void uxa_prepare_access_window(WindowPtr pWin) { if (pWin->backgroundState == BackgroundPixmap) - uxa_prepare_access(&pWin->background.pixmap->drawable, UXA_PREPARE_SRC); + uxa_prepare_access(&pWin->background.pixmap->drawable, UXA_ACCESS_RO); if (pWin->borderIsPixel == FALSE) - uxa_prepare_access(&pWin->border.pixmap->drawable, UXA_PREPARE_SRC); + uxa_prepare_access(&pWin->border.pixmap->drawable, UXA_ACCESS_RO); } void uxa_finish_access_window(WindowPtr pWin) { if (pWin->backgroundState == BackgroundPixmap) - uxa_finish_access(&pWin->background.pixmap->drawable, UXA_PREPARE_SRC); + uxa_finish_access(&pWin->background.pixmap->drawable); if (pWin->borderIsPixel == FALSE) - uxa_finish_access(&pWin->border.pixmap->drawable, UXA_PREPARE_SRC); + uxa_finish_access(&pWin->border.pixmap->drawable); } static Bool @@ -304,9 +304,9 @@ static RegionPtr uxa_bitmap_to_region(PixmapPtr pPix) { RegionPtr ret; - uxa_prepare_access(&pPix->drawable, UXA_PREPARE_SRC); + uxa_prepare_access(&pPix->drawable, UXA_ACCESS_RO); ret = fbPixmapToRegion(pPix); - uxa_finish_access(&pPix->drawable, UXA_PREPARE_SRC); + uxa_finish_access(&pPix->drawable); return ret; } diff --git a/uxa/uxa.h b/uxa/uxa.h index 57e84f37..32d5a5a2 100644 --- a/uxa/uxa.h +++ b/uxa/uxa.h @@ -43,6 +43,11 @@ #define UXA_VERSION_MINOR 0 #define UXA_VERSION_RELEASE 0 +typedef enum { + UXA_ACCESS_RO, + UXA_ACCESS_RW +} uxa_access_t; + /** * The UxaDriver structure is allocated through uxa_driver_alloc(), and then * fllled in by drivers. @@ -251,11 +256,7 @@ typedef struct _UxaDriver { * of op with the given source, mask, and destination pictures. This allows * drivers to check source and destination formats, supported operations, * transformations, and component alpha state, and send operations it can't - * support to software rendering early on. This avoids costly pixmap - * migration to the wrong places when the driver can't accelerate - * operations. Note that because migration hasn't happened, the driver - * can't know during CheckComposite() what the offsets and pitches of the - * pixmaps are going to be. + * support to software rendering early on. * * See PrepareComposite() for more details on likely issues that drivers * will have in accelerating Composite operations. @@ -544,7 +545,7 @@ typedef struct _UxaDriver { * @return FALSE if PrepareAccess() is unsuccessful and UXA should use * DownloadFromScreen() to migate the pixmap out. */ - Bool (*PrepareAccess)(PixmapPtr pPix, int index); + Bool (*PrepareAccess)(PixmapPtr pPix, uxa_access_t access); /** * FinishAccess() is called after CPU access to an offscreen pixmap. @@ -554,9 +555,9 @@ typedef struct _UxaDriver { * * FinishAccess() will be called after finishing CPU access of an offscreen * pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be - * called if PrepareAccess() failed and the pixmap was migrated out. + * called if PrepareAccess() failed. */ - void (*FinishAccess)(PixmapPtr pPix, int index); + void (*FinishAccess)(PixmapPtr pPix); /** * PixmapIsOffscreen() is an optional driver replacement to @@ -575,25 +576,6 @@ typedef struct _UxaDriver { */ Bool (*PixmapIsOffscreen)(PixmapPtr pPix); - /** @name PrepareAccess() and FinishAccess() indices - * @{ - */ - /** - * UXA_PREPARE_DEST is the index for a pixmap that may be drawn to or - * read from. - */ - #define UXA_PREPARE_DEST 0 - /** - * UXA_PREPARE_SRC is the index for a pixmap that may be read from - */ - #define UXA_PREPARE_SRC 1 - /** - * UXA_PREPARE_SRC is the index for a second pixmap that may be read - * from. - */ - #define UXA_PREPARE_MASK 2 - /** @} */ - /** * maxPitchPixels controls the pitch limitation for rendering from * the card. From b2d058d80ccd08d9e02ef866ee7a95b58686f6a3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Aug 2008 23:43:13 -0700 Subject: [PATCH 41/45] Rename uxa using _ instead of caps --- src/i830.h | 1 + src/i830_driver.c | 12 +- src/i830_exa.c | 97 +++++++++++----- src/i830_render.c | 11 -- uxa/uxa-accel.c | 119 +++++++++---------- uxa/uxa-glyphs.c | 16 +-- uxa/uxa-priv.h | 1 - uxa/uxa-render.c | 149 +++++++++--------------- uxa/uxa.c | 98 +++++----------- uxa/uxa.h | 287 +++++++++++++++++----------------------------- 10 files changed, 322 insertions(+), 469 deletions(-) diff --git a/src/i830.h b/src/i830.h index dbcf3c0f..d87e5d97 100644 --- a/src/i830.h +++ b/src/i830.h @@ -538,6 +538,7 @@ typedef struct _I830Rec { #ifdef I830_USE_UXA uxa_driver_t *uxa_driver; Bool need_flush; + Bool need_sync; #endif #if defined(I830_USE_EXA) || defined(I830_USE_UXA) PixmapPtr pSrcPixmap; diff --git a/src/i830_driver.c b/src/i830_driver.c index bef3bb83..6b8f9987 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -3887,9 +3887,9 @@ i830WaitSync(ScrnInfoPtr pScrn) #endif #ifdef I830_USE_UXA case ACCEL_UXA: - if (pI830->uxa_driver) { - ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; - uxa_wait_sync(pScreen); + if (pI830->uxa_driver && pI830->need_sync) { + pI830->need_sync = FALSE; + I830Sync(pScrn); } break; #endif @@ -3920,10 +3920,8 @@ i830MarkSync(ScrnInfoPtr pScrn) #endif #ifdef I830_USE_UXA case ACCEL_UXA: - if (pI830->uxa_driver) { - ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; - exaMarkSync(pScreen); - } + if (pI830->uxa_driver) + pI830->need_sync = TRUE; break; #endif default: diff --git a/src/i830_exa.c b/src/i830_exa.c index 08d73b5d..87a7e6cc 100644 --- a/src/i830_exa.c +++ b/src/i830_exa.c @@ -42,6 +42,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #endif #define ALWAYS_SYNC 0 +#define ALWAYS_FLUSH 0 #ifdef DEBUG_I830FALLBACK #define I830FALLBACK(s, arg...) \ @@ -247,11 +248,16 @@ I830EXASolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) static void I830EXADoneSolid(PixmapPtr pPixmap) { -#if ALWAYS_SYNC +#if ALWAYS_SYNC || ALWAYS_FLUSH || 1 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; +#if ALWAYS_FLUSH || 1 + intel_batch_flush(pScrn); +#endif +#if ALWAYS_SYNC I830Sync(pScrn); #endif +#endif } /** @@ -343,11 +349,37 @@ I830EXACopy(PixmapPtr pDstPixmap, int src_x1, int src_y1, int dst_x1, static void I830EXADoneCopy(PixmapPtr pDstPixmap) { -#if ALWAYS_SYNC +#if ALWAYS_SYNC || ALWAYS_FLUSH ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; +#if ALWAYS_FLUSH + intel_batch_flush(pScrn); +#endif +#if ALWAYS_SYNC I830Sync(pScrn); #endif +#endif +} + + +/** + * Do any cleanup from the Composite operation. + * + * This is shared between i830 through i965. + */ +void +i830_done_composite(PixmapPtr pDst) +{ +#if ALWAYS_SYNC || ALWAYS_FLUSH + ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; + +#if ALWAYS_FLUSH + intel_batch_flush(pScrn); +#endif +#if ALWAYS_SYNC + I830Sync(pScrn); +#endif +#endif } #define xFixedToFloat(val) \ @@ -558,7 +590,15 @@ i830_uxa_prepare_access (PixmapPtr pixmap, uxa_access_t access) dri_bo *bo = i830_uxa_get_pixmap_bo (pixmap); if (bo) { - intel_batch_flush(xf86Screens[pixmap->drawable.pScreen->myNum]); + ScreenPtr screen = pixmap->drawable.pScreen; + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + I830Ptr i830 = I830PTR(scrn); + + intel_batch_flush(scrn); + if (i830->need_sync) { + I830Sync(scrn); + i830->need_sync = FALSE; + } if (dri_bo_map (bo, access == UXA_ACCESS_RW) != 0) return FALSE; pixmap->devPrivate.ptr = bo->virtual; @@ -680,47 +720,42 @@ i830_uxa_init (ScreenPtr pScreen) i830->uxa_driver->uxa_major = 1; i830->uxa_driver->uxa_minor = 0; - i830->uxa_driver->maxX = i830->accel_max_x; - i830->uxa_driver->maxY = i830->accel_max_y; - - /* Sync */ - i830->uxa_driver->WaitMarker = I830EXASync; + i830->uxa_driver->max_x = i830->accel_max_x; + i830->uxa_driver->max_y = i830->accel_max_y; /* Solid fill */ - i830->uxa_driver->PrepareSolid = I830EXAPrepareSolid; - i830->uxa_driver->Solid = I830EXASolid; - i830->uxa_driver->DoneSolid = I830EXADoneSolid; + i830->uxa_driver->prepare_solid = I830EXAPrepareSolid; + i830->uxa_driver->solid = I830EXASolid; + i830->uxa_driver->done_solid = I830EXADoneSolid; /* Copy */ - i830->uxa_driver->PrepareCopy = I830EXAPrepareCopy; - i830->uxa_driver->Copy = I830EXACopy; - i830->uxa_driver->DoneCopy = I830EXADoneCopy; + i830->uxa_driver->prepare_copy = I830EXAPrepareCopy; + i830->uxa_driver->copy = I830EXACopy; + i830->uxa_driver->done_copy = I830EXADoneCopy; -#if 0 /* Composite */ if (!IS_I9XX(i830)) { - i830->uxa_driver->CheckComposite = i830_check_composite; - i830->uxa_driver->PrepareComposite = i830_prepare_composite; - i830->uxa_driver->Composite = i830_composite; - i830->uxa_driver->DoneComposite = i830_done_composite; + i830->uxa_driver->check_composite = i830_check_composite; + i830->uxa_driver->prepare_composite = i830_prepare_composite; + i830->uxa_driver->composite = i830_composite; + i830->uxa_driver->done_composite = i830_done_composite; } else if (IS_I915G(i830) || IS_I915GM(i830) || IS_I945G(i830) || IS_I945GM(i830) || IS_G33CLASS(i830)) { - i830->uxa_driver->CheckComposite = i915_check_composite; - i830->uxa_driver->PrepareComposite = i915_prepare_composite; - i830->uxa_driver->Composite = i830_composite; - i830->uxa_driver->DoneComposite = i830_done_composite; + i830->uxa_driver->check_composite = i915_check_composite; + i830->uxa_driver->prepare_composite = i915_prepare_composite; + i830->uxa_driver->composite = i830_composite; + i830->uxa_driver->done_composite = i830_done_composite; } else { - i830->uxa_driver->CheckComposite = i965_check_composite; - i830->uxa_driver->PrepareComposite = i965_prepare_composite; - i830->uxa_driver->Composite = i965_composite; - i830->uxa_driver->DoneComposite = i830_done_composite; + i830->uxa_driver->check_composite = i965_check_composite; + i830->uxa_driver->prepare_composite = i965_prepare_composite; + i830->uxa_driver->composite = i965_composite; + i830->uxa_driver->done_composite = i830_done_composite; } -#endif - i830->uxa_driver->PrepareAccess = i830_uxa_prepare_access; - i830->uxa_driver->FinishAccess = i830_uxa_finish_access; - i830->uxa_driver->PixmapIsOffscreen = i830_uxa_pixmap_is_offscreen; + i830->uxa_driver->prepare_access = i830_uxa_prepare_access; + i830->uxa_driver->finish_access = i830_uxa_finish_access; + i830->uxa_driver->pixmap_is_offscreen = i830_uxa_pixmap_is_offscreen; if(!uxa_driver_init(pScreen, i830->uxa_driver)) { xf86DrvMsg(scrn->scrnIndex, X_INFO, diff --git a/src/i830_render.c b/src/i830_render.c index 4b42ea37..c1ce856a 100644 --- a/src/i830_render.c +++ b/src/i830_render.c @@ -733,14 +733,3 @@ i830_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, ADVANCE_BATCH(); } - -/** - * Do any cleanup from the Composite operation. - * - * This is shared between i830 through i965. - */ -void -i830_done_composite(PixmapPtr pDst) -{ - /* NO-OP */ -} diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c index 20a56574..edc68f2a 100644 --- a/uxa/uxa-accel.c +++ b/uxa/uxa-accel.c @@ -37,7 +37,7 @@ static void uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, - DDXPointPtr ppt, int *pwidth, int fSorted) + DDXPointPtr ppt, int *pwidth, int fSorted) { ScreenPtr pScreen = pDrawable->pScreen; uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); @@ -52,10 +52,10 @@ uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, if (uxa_screen->swappedOut || pGC->fillStyle != FillSolid || !(pPixmap = uxa_get_offscreen_pixmap (pDrawable, &off_x, &off_y)) || - !(*uxa_screen->info->PrepareSolid) (pPixmap, - pGC->alu, - pGC->planemask, - pGC->fgPixel)) + !(*uxa_screen->info->prepare_solid) (pPixmap, + pGC->alu, + pGC->planemask, + pGC->fgPixel)) { uxa_check_fill_spans (pDrawable, pGC, n, ppt, pwidth, fSorted); return; @@ -89,9 +89,9 @@ uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, nbox = REGION_NUM_RECTS (pClip); if (nbox == 1) { - (*uxa_screen->info->Solid) (pPixmap, - fullX1 + off_x, fullY1 + off_y, - fullX2 + off_x, fullY1 + 1 + off_y); + (*uxa_screen->info->solid) (pPixmap, + fullX1 + off_x, fullY1 + off_y, + fullX2 + off_x, fullY1 + 1 + off_y); } else { @@ -107,22 +107,21 @@ uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, if (partX2 > fullX2) partX2 = fullX2; if (partX2 > partX1) { - (*uxa_screen->info->Solid) (pPixmap, - partX1 + off_x, fullY1 + off_y, - partX2 + off_x, fullY1 + 1 + off_y); + (*uxa_screen->info->solid) (pPixmap, + partX1 + off_x, fullY1 + off_y, + partX2 + off_x, fullY1 + 1 + off_y); } } pbox++; } } } - (*uxa_screen->info->DoneSolid) (pPixmap); - uxa_mark_sync(pScreen); + (*uxa_screen->info->done_solid) (pPixmap); } static Bool uxa_do_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, - int w, int h, int format, char *bits, int src_stride) + int w, int h, int format, char *bits, int src_stride) { uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen); PixmapPtr pPix = uxa_get_drawable_pixmap (pDrawable); @@ -146,7 +145,7 @@ uxa_do_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, pPix = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff); - if (!pPix || !uxa_screen->info->UploadToScreen) + if (!pPix || !uxa_screen->info->put_image) return FALSE; x += pDrawable->x; @@ -177,8 +176,8 @@ uxa_do_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, continue; src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8); - ok = uxa_screen->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff, - x2 - x1, y2 - y1, src, src_stride); + ok = uxa_screen->info->put_image(pPix, x1 + xoff, y1 + yoff, + x2 - x1, y2 - y1, src, src_stride); /* If we fail to accelerate the upload, fall back to using unaccelerated * fb calls. */ @@ -210,8 +209,6 @@ uxa_do_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, if (access_prepared) uxa_finish_access(pDrawable); - else - uxa_mark_sync(pDrawable->pScreen); return TRUE; } @@ -226,8 +223,8 @@ uxa_do_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, int src_stride = PixmapBytePad(w, depth); if (uxa_do_put_image(pDrawable, pGC, depth, dx, dy, sw, sh, format, data + - sy * src_stride + sx * BitsPerPixel(depth) / 8, - src_stride)) + sy * src_stride + sx * BitsPerPixel(depth) / 8, + src_stride)) return TRUE; if (format == ZPixmap) @@ -235,12 +232,12 @@ uxa_do_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, PixmapPtr pPixmap; pPixmap = GetScratchPixmapHeader(pDrawable->pScreen, w, h, depth, - BitsPerPixel(depth), PixmapBytePad(w, depth), (pointer)data); + BitsPerPixel(depth), PixmapBytePad(w, depth), + (pointer)data); if (!pPixmap) return FALSE; uxa_prepare_access (pDrawable, UXA_ACCESS_RW); - fbCopyArea((DrawablePtr)pPixmap, pDrawable, pGC, sx, sy, sw, sh, dx, dy); uxa_finish_access(pDrawable); @@ -260,11 +257,11 @@ uxa_do_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, */ void uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format, - int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, - char *data) + int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, + char *data) { if (!uxa_do_shm_put_image(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, - dx, dy, data)) { + dx, dy, data)) { uxa_prepare_access (pDrawable, UXA_ACCESS_RW); fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data); @@ -316,9 +313,9 @@ uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, /* Do a xdir = ydir = -1 blit instead. */ if (dirsetup != -1) { if (dirsetup != 0) - uxa_screen->info->DoneCopy(pDstPixmap); + uxa_screen->info->done_copy(pDstPixmap); dirsetup = -1; - if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap, + if (!(*uxa_screen->info->prepare_copy)(pSrcPixmap, pDstPixmap, -1, -1, pGC ? pGC->alu : GXcopy, @@ -326,7 +323,7 @@ uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, FB_ALLONES)) return FALSE; } - (*uxa_screen->info->Copy)(pDstPixmap, + (*uxa_screen->info->copy)(pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy, dst_off_x + pbox->x1, @@ -337,9 +334,9 @@ uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, /* Do a xdir = ydir = 1 blit instead. */ if (dirsetup != 1) { if (dirsetup != 0) - uxa_screen->info->DoneCopy(pDstPixmap); + uxa_screen->info->done_copy(pDstPixmap); dirsetup = 1; - if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap, + if (!(*uxa_screen->info->prepare_copy)(pSrcPixmap, pDstPixmap, 1, 1, pGC ? pGC->alu : GXcopy, @@ -347,7 +344,7 @@ uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, FB_ALLONES)) return FALSE; } - (*uxa_screen->info->Copy)(pDstPixmap, + (*uxa_screen->info->copy)(pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy, dst_off_x + pbox->x1, @@ -362,9 +359,9 @@ uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, int i; if (dirsetup != 1) { if (dirsetup != 0) - uxa_screen->info->DoneCopy(pDstPixmap); + uxa_screen->info->done_copy(pDstPixmap); dirsetup = 1; - if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap, + if (!(*uxa_screen->info->prepare_copy)(pSrcPixmap, pDstPixmap, 1, 1, pGC ? pGC->alu : GXcopy, @@ -373,7 +370,7 @@ uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, return FALSE; } for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) - (*uxa_screen->info->Copy)(pDstPixmap, + (*uxa_screen->info->copy)(pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy + i, dst_off_x + pbox->x1, @@ -387,9 +384,9 @@ uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, int i; if (dirsetup != -1) { if (dirsetup != 0) - uxa_screen->info->DoneCopy(pDstPixmap); + uxa_screen->info->done_copy(pDstPixmap); dirsetup = -1; - if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap, + if (!(*uxa_screen->info->prepare_copy)(pSrcPixmap, pDstPixmap, -1, -1, pGC ? pGC->alu : GXcopy, @@ -398,7 +395,7 @@ uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, return FALSE; } for (i = 0; i < pbox->y2 - pbox->y1; i++) - (*uxa_screen->info->Copy)(pDstPixmap, + (*uxa_screen->info->copy)(pDstPixmap, src_off_x + pbox->x1 + dx, src_off_y + pbox->y1 + dy + i, dst_off_x + pbox->x1, @@ -407,8 +404,7 @@ uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, } } if (dirsetup != 0) - uxa_screen->info->DoneCopy(pDstPixmap); - uxa_mark_sync(pDstDrawable->pScreen); + uxa_screen->info->done_copy(pDstPixmap); return TRUE; } @@ -447,7 +443,7 @@ uxa_copy_n_to_n (DrawablePtr pSrcDrawable, if (!uxa_pixmap_is_offscreen(pSrcPixmap) || !uxa_pixmap_is_offscreen(pDstPixmap) || - !(*uxa_screen->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, + !(*uxa_screen->info->prepare_copy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, upsidedown ? -1 : 1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) { @@ -456,7 +452,7 @@ uxa_copy_n_to_n (DrawablePtr pSrcDrawable, while (nbox--) { - (*uxa_screen->info->Copy) (pDstPixmap, + (*uxa_screen->info->copy) (pDstPixmap, pbox->x1 + dx + src_off_x, pbox->y1 + dy + src_off_y, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, @@ -464,8 +460,7 @@ uxa_copy_n_to_n (DrawablePtr pSrcDrawable, pbox++; } - (*uxa_screen->info->DoneCopy) (pDstPixmap); - uxa_mark_sync (pDstDrawable->pScreen); + (*uxa_screen->info->done_copy) (pDstPixmap); return; @@ -704,7 +699,7 @@ uxa_poly_fill_rect(DrawablePtr pDrawable, } if (!uxa_pixmap_is_offscreen (pPixmap) || - !(*uxa_screen->info->PrepareSolid) (pPixmap, + !(*uxa_screen->info->prepare_solid) (pPixmap, pGC->alu, pGC->planemask, pGC->fgPixel)) @@ -747,7 +742,7 @@ fallback: n = REGION_NUM_RECTS (pClip); if (n == 1) { - (*uxa_screen->info->Solid) (pPixmap, + (*uxa_screen->info->solid) (pPixmap, fullX1 + xoff, fullY1 + yoff, fullX2 + xoff, fullY2 + yoff); } @@ -777,15 +772,14 @@ fallback: pbox++; if (partX1 < partX2 && partY1 < partY2) { - (*uxa_screen->info->Solid) (pPixmap, + (*uxa_screen->info->solid) (pPixmap, partX1 + xoff, partY1 + yoff, partX2 + xoff, partY2 + yoff); } } } } - (*uxa_screen->info->DoneSolid) (pPixmap); - uxa_mark_sync(pDrawable->pScreen); + (*uxa_screen->info->done_solid) (pPixmap); out: REGION_UNINIT(pScreen, pReg); @@ -858,7 +852,7 @@ uxa_fill_region_solid (DrawablePtr pDrawable, REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); if (uxa_pixmap_is_offscreen (pPixmap) && - (*uxa_screen->info->PrepareSolid) (pPixmap, alu, planemask, pixel)) + (*uxa_screen->info->prepare_solid) (pPixmap, alu, planemask, pixel)) { int nbox; BoxPtr pBox; @@ -868,12 +862,11 @@ uxa_fill_region_solid (DrawablePtr pDrawable, while (nbox--) { - (*uxa_screen->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, + (*uxa_screen->info->solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2, pBox->y2); pBox++; } - (*uxa_screen->info->DoneSolid) (pPixmap); - uxa_mark_sync(pDrawable->pScreen); + (*uxa_screen->info->done_solid) (pPixmap); ret = TRUE; } @@ -906,7 +899,7 @@ uxa_fill_region_tiled (DrawablePtr pDrawable, tileHeight = pTile->drawable.height; /* If we're filling with a solid color, grab it out and go to - * FillRegionSolid, saving numerous copies. + * FillRegionsolid, saving numerous copies. */ if (tileWidth == 1 && tileHeight == 1) return uxa_fill_region_solid(pDrawable, pRegion, @@ -922,7 +915,7 @@ uxa_fill_region_tiled (DrawablePtr pDrawable, if (!pPixmap || !uxa_pixmap_is_offscreen(pTile)) goto out; - if ((*uxa_screen->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) + if ((*uxa_screen->info->prepare_copy) (pTile, pPixmap, 1, 1, alu, planemask)) { while (nbox--) { @@ -951,7 +944,7 @@ uxa_fill_region_tiled (DrawablePtr pDrawable, w = width; width -= w; - (*uxa_screen->info->Copy) (pPixmap, tileX, tileY, dstX, dstY, + (*uxa_screen->info->copy) (pPixmap, tileX, tileY, dstX, dstY, w, h); dstX += w; tileX = 0; @@ -961,8 +954,7 @@ uxa_fill_region_tiled (DrawablePtr pDrawable, } pBox++; } - (*uxa_screen->info->DoneCopy) (pPixmap); - uxa_mark_sync(pDrawable->pScreen); + (*uxa_screen->info->done_copy) (pPixmap); ret = TRUE; } @@ -1003,7 +995,7 @@ uxa_get_image (DrawablePtr pDrawable, int x, int y, int w, int h, pPix = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff); - if (pPix == NULL || uxa_screen->info->DownloadFromScreen == NULL) + if (pPix == NULL || uxa_screen->info->get_image == NULL) goto fallback; /* Only cover the ZPixmap, solid copy case. */ @@ -1016,13 +1008,11 @@ uxa_get_image (DrawablePtr pDrawable, int x, int y, int w, int h, if (pDrawable->bitsPerPixel < 8) goto fallback; - ok = uxa_screen->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff, + ok = uxa_screen->info->get_image(pPix, pDrawable->x + x + xoff, pDrawable->y + y + yoff, w, h, d, PixmapBytePad(w, pDrawable->depth)); - if (ok) { - uxa_wait_sync(pDrawable->pScreen); - goto out; - } + if (ok) + return; fallback: UXA_FALLBACK(("from %p (%c)\n", pDrawable, @@ -1032,6 +1022,5 @@ fallback: fbGetImage (pDrawable, x, y, w, h, format, planeMask, d); uxa_finish_access (pDrawable); -out: return; } diff --git a/uxa/uxa-glyphs.c b/uxa/uxa-glyphs.c index 3c446405..364fcfbc 100644 --- a/uxa/uxa-glyphs.c +++ b/uxa/uxa-glyphs.c @@ -362,7 +362,7 @@ uxa_glyph_cache_upload_glyph(ScreenPtr pScreen, PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable; int cacheXoff, cacheYoff; - if (!uxa_screen->info->UploadToScreen || uxa_screen->swappedOut) + if (!uxa_screen->info->put_image || uxa_screen->swappedOut) return FALSE; /* If the glyph pixmap is already uploaded, no point in doing @@ -378,13 +378,13 @@ uxa_glyph_cache_upload_glyph(ScreenPtr pScreen, if (!pCachePixmap) return FALSE; - if (!uxa_screen->info->UploadToScreen(pCachePixmap, - CACHE_X(pos) + cacheXoff, - CACHE_Y(pos) + cacheYoff, - pGlyph->info.width, - pGlyph->info.height, - (char *)pGlyphPixmap->devPrivate.ptr, - pGlyphPixmap->devKind)) + if (!uxa_screen->info->put_image(pCachePixmap, + CACHE_X(pos) + cacheXoff, + CACHE_Y(pos) + cacheYoff, + pGlyph->info.width, + pGlyph->info.height, + (char *)pGlyphPixmap->devPrivate.ptr, + pGlyphPixmap->devKind)) return FALSE; return TRUE; diff --git a/uxa/uxa-priv.h b/uxa/uxa-priv.h index 1e4f4ead..c50ab3af 100644 --- a/uxa/uxa-priv.h +++ b/uxa/uxa-priv.h @@ -117,7 +117,6 @@ typedef struct { #define UXA_NUM_GLYPH_CACHES 4 -typedef void (*EnableDisableFBAccessProcPtr)(int, Bool); typedef struct { uxa_driver_t *info; CreateGCProcPtr SavedCreateGC; diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c index 9c79fce5..94e18a55 100644 --- a/uxa/uxa-render.c +++ b/uxa/uxa-render.c @@ -291,7 +291,7 @@ uxa_try_driver_solid_fill(PicturePtr pSrc, return -1; } - if (!(*uxa_screen->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) + if (!(*uxa_screen->info->prepare_solid) (pDstPix, GXcopy, 0xffffffff, pixel)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return -1; @@ -302,60 +302,46 @@ uxa_try_driver_solid_fill(PicturePtr pSrc, while (nbox--) { - (*uxa_screen->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2); + (*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2); pbox++; } - (*uxa_screen->info->DoneSolid) (pDstPix); - uxa_mark_sync(pDst->pDrawable->pScreen); + (*uxa_screen->info->done_solid) (pDstPix); REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 1; } static int -uxa_try_driver_composite_rects(CARD8 op, - PicturePtr pSrc, - PicturePtr pDst, - int nrect, - uxa_composite_rect_t *rects) +uxa_try_driver_composite_rects(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + int nrect, + uxa_composite_rect_t *rects) { uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); int src_off_x, src_off_y, dst_off_x, dst_off_y; PixmapPtr pSrcPix, pDstPix; - struct _Pixmap scratch; - if (!uxa_screen->info->PrepareComposite) + if (!uxa_screen->info->prepare_composite) return -1; - pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable); - - pDstPix = uxa_get_drawable_pixmap(pDst->pDrawable); - - if (uxa_screen->info->CheckComposite && - !(*uxa_screen->info->CheckComposite) (op, pSrc, NULL, pDst)) + if (uxa_screen->info->check_composite && + !(*uxa_screen->info->check_composite) (op, pSrc, NULL, pDst)) { return -1; } - uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); - - pSrcPix = uxa_get_offscreen_pixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (!uxa_pixmap_is_offscreen(pDstPix)) + pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); + if (!pDstPix) return 0; - - if (!pSrcPix && uxa_screen->info->UploadToScratch) - { - pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable); - if ((*uxa_screen->info->UploadToScratch) (pSrcPix, &scratch)) - pSrcPix = &scratch; - } + pSrcPix = uxa_get_offscreen_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y); if (!pSrcPix) return 0; - if (!(*uxa_screen->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix, - NULL, pDstPix)) + if (!(*uxa_screen->info->prepare_composite) (op, pSrc, NULL, pDst, pSrcPix, + NULL, pDstPix)) return -1; while (nrect--) @@ -384,14 +370,14 @@ uxa_try_driver_composite_rects(CARD8 op, while (nbox--) { - (*uxa_screen->info->Composite) (pDstPix, - pbox->x1 + xSrc, - pbox->y1 + ySrc, - 0, 0, - pbox->x1, - pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); + (*uxa_screen->info->composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + 0, 0, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); pbox++; } @@ -400,9 +386,7 @@ uxa_try_driver_composite_rects(CARD8 op, rects++; } - - (*uxa_screen->info->DoneComposite) (pDstPix); - uxa_mark_sync(pDst->pDrawable->pScreen); + (*uxa_screen->info->done_composite) (pDstPix); return 1; } @@ -467,12 +451,6 @@ uxa_try_driver_composite(CARD8 op, int nbox; int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; - struct _Pixmap scratch; - - pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable); - pDstPix = uxa_get_drawable_pixmap(pDst->pDrawable); - if (pMask) - pMaskPix = uxa_get_drawable_pixmap(pMask->pDrawable); xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; @@ -485,8 +463,8 @@ uxa_try_driver_composite(CARD8 op, xSrc += pSrc->pDrawable->x; ySrc += pSrc->pDrawable->y; - if (uxa_screen->info->CheckComposite && - !(*uxa_screen->info->CheckComposite) (op, pSrc, pMask, pDst)) + if (uxa_screen->info->check_composite && + !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst)) { return -1; } @@ -496,37 +474,23 @@ uxa_try_driver_composite(CARD8 op, width, height)) return 1; - uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); + pDstPix = uxa_get_offscreen_pixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); + + pSrcPix = uxa_get_offscreen_pixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + + if (pMask) + pMaskPix = uxa_get_offscreen_pixmap (pMask->pDrawable, &mask_off_x, + &mask_off_y); + + if (!pDstPix || !pSrcPix || (pMask && !pMaskPix)) { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 0; + } REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); - pSrcPix = uxa_get_offscreen_pixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (pMask) - pMaskPix = uxa_get_offscreen_pixmap (pMask->pDrawable, &mask_off_x, - &mask_off_y); - - if (!uxa_pixmap_is_offscreen(pDstPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; - } - - if (!pSrcPix && (!pMask || pMaskPix) && uxa_screen->info->UploadToScratch) { - pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable); - if ((*uxa_screen->info->UploadToScratch) (pSrcPix, &scratch)) - pSrcPix = &scratch; - } else if (pSrcPix && pMask && !pMaskPix && uxa_screen->info->UploadToScratch) { - pMaskPix = uxa_get_drawable_pixmap (pMask->pDrawable); - if ((*uxa_screen->info->UploadToScratch) (pMaskPix, &scratch)) - pMaskPix = &scratch; - } - - if (!pSrcPix || (pMask && !pMaskPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); - return 0; - } - - if (!(*uxa_screen->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, - pMaskPix, pDstPix)) + if (!(*uxa_screen->info->prepare_composite) (op, pSrc, pMask, pDst, pSrcPix, + pMaskPix, pDstPix)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return -1; @@ -543,19 +507,18 @@ uxa_try_driver_composite(CARD8 op, while (nbox--) { - (*uxa_screen->info->Composite) (pDstPix, - pbox->x1 + xSrc, - pbox->y1 + ySrc, - pbox->x1 + xMask, - pbox->y1 + yMask, - pbox->x1, - pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); + (*uxa_screen->info->composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + pbox->x1 + xMask, + pbox->y1 + yMask, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); pbox++; } - (*uxa_screen->info->DoneComposite) (pDstPix); - uxa_mark_sync(pDst->pDrawable->pScreen); + (*uxa_screen->info->done_composite) (pDstPix); REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 1; @@ -628,10 +591,10 @@ uxa_try_magic_two_pass_composite_helper(CARD8 op, assert(op == PictOpOver); - if (uxa_screen->info->CheckComposite && - (!(*uxa_screen->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, + if (uxa_screen->info->check_composite && + (!(*uxa_screen->info->check_composite)(PictOpOutReverse, pSrc, pMask, pDst) || - !(*uxa_screen->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst))) + !(*uxa_screen->info->check_composite)(PictOpAdd, pSrc, pMask, pDst))) { return -1; } @@ -735,7 +698,7 @@ uxa_composite(CARD8 op, DDXPointRec patOrg; /* Let's see if the driver can do the repeat in one go */ - if (uxa_screen->info->PrepareComposite && !pSrc->alphaMap && + if (uxa_screen->info->prepare_composite && !pSrc->alphaMap && !pDst->alphaMap) { ret = uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, @@ -779,7 +742,7 @@ uxa_composite(CARD8 op, (yMask + height) <= pMask->pDrawable->height) pMask->repeat = 0; - if (uxa_screen->info->PrepareComposite && + if (uxa_screen->info->prepare_composite && !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) { Bool isSrcSolid; diff --git a/uxa/uxa.c b/uxa/uxa.c index 5fe0f32f..c76cb1d2 100644 --- a/uxa/uxa.c +++ b/uxa/uxa.c @@ -100,8 +100,8 @@ uxa_pixmap_is_offscreen(PixmapPtr p) ScreenPtr pScreen = p->drawable.pScreen; uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - if (uxa_screen->info->PixmapIsOffscreen) - return uxa_screen->info->PixmapIsOffscreen(p); + if (uxa_screen->info->pixmap_is_offscreen) + return uxa_screen->info->pixmap_is_offscreen(p); return FALSE; } @@ -151,14 +151,14 @@ uxa_prepare_access(DrawablePtr pDrawable, uxa_access_t access) if (!offscreen) return; - if (uxa_screen->info->PrepareAccess) - (*uxa_screen->info->PrepareAccess) (pPixmap, access); + if (uxa_screen->info->prepare_access) + (*uxa_screen->info->prepare_access) (pPixmap, access); } /** - * uxa_finish_access() is UXA's wrapper for the driver's FinishAccess() handler. + * uxa_finish_access() is UXA's wrapper for the driver's finish_access() handler. * - * It deals with calling the driver's FinishAccess() only if necessary. + * It deals with calling the driver's finish_access() only if necessary. */ void uxa_finish_access(DrawablePtr pDrawable) @@ -167,13 +167,13 @@ uxa_finish_access(DrawablePtr pDrawable) uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable); - if (uxa_screen->info->FinishAccess == NULL) + if (uxa_screen->info->finish_access == NULL) return; if (!uxa_pixmap_is_offscreen (pPixmap)) return; - (*uxa_screen->info->FinishAccess) (pPixmap); + (*uxa_screen->info->finish_access) (pPixmap); } /** @@ -185,7 +185,7 @@ uxa_validate_gc (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) { /* fbValidateGC will do direct access to pixmaps if the tiling has changed. * Preempt fbValidateGC by doing its work and masking the change out, so - * that we can do the Prepare/FinishAccess. + * that we can do the Prepare/finish_access. */ #ifdef FB_24_32BIT if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) { @@ -396,20 +396,14 @@ uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver) return FALSE; } - if (!uxa_driver->PrepareSolid) { - LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::PrepareSolid must be " + if (!uxa_driver->prepare_solid) { + LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::prepare_solid must be " "non-NULL\n", screen->myNum); return FALSE; } - if (!uxa_driver->PrepareCopy) { - LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::PrepareCopy must be " - "non-NULL\n", screen->myNum); - return FALSE; - } - - if (!uxa_driver->WaitMarker) { - LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::WaitMarker must be " + if (!uxa_driver->prepare_copy) { + LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::prepare_copy must be " "non-NULL\n", screen->myNum); return FALSE; } @@ -418,14 +412,14 @@ uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver) * that there's a limitation by pixels, and that it's the same as * maxX. * - * We want maxPitchPixels or maxPitchBytes to be set so we can check + * We want max_pitch_pixels or max_pitch_bytes to be set so we can check * pixmaps against the max pitch in uxaCreatePixmap() -- it matters * whether a pixmap is rejected because of its pitch or * because of its width. */ - if (!uxa_driver->maxPitchPixels && !uxa_driver->maxPitchBytes) + if (!uxa_driver->max_pitch_pixels && !uxa_driver->max_pitch_bytes) { - uxa_driver->maxPitchPixels = uxa_driver->maxX; + uxa_driver->max_pitch_pixels = uxa_driver->max_x; } #ifdef RENDER @@ -501,18 +495,18 @@ uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver) LogMessage(X_INFO, "UXA(%d): Driver registered support for the following" " operations:\n", screen->myNum); - assert(uxa_driver->PrepareSolid != NULL); - LogMessage(X_INFO, " Solid\n"); - assert(uxa_driver->PrepareCopy != NULL); - LogMessage(X_INFO, " Copy\n"); - if (uxa_driver->PrepareComposite != NULL) { - LogMessage(X_INFO, " Composite (RENDER acceleration)\n"); + assert(uxa_driver->prepare_solid != NULL); + LogMessage(X_INFO, " solid\n"); + assert(uxa_driver->prepare_copy != NULL); + LogMessage(X_INFO, " copy\n"); + if (uxa_driver->prepare_composite != NULL) { + LogMessage(X_INFO, " composite (RENDER acceleration)\n"); } - if (uxa_driver->UploadToScreen != NULL) { - LogMessage(X_INFO, " UploadToScreen\n"); + if (uxa_driver->put_image != NULL) { + LogMessage(X_INFO, " put_image\n"); } - if (uxa_driver->DownloadFromScreen != NULL) { - LogMessage(X_INFO, " DownloadFromScreen\n"); + if (uxa_driver->get_image != NULL) { + LogMessage(X_INFO, " get_image\n"); } return TRUE; @@ -528,43 +522,3 @@ uxa_driver_fini (ScreenPtr pScreen) { /*right now does nothing*/ } - -/** - * uxa_mark_sync() should be called after any asynchronous drawing by the hardware. - * - * @param pScreen screen which drawing occurred on - * - * uxa_mark_sync() sets a flag to indicate that some asynchronous drawing has - * happened and a WaitSync() will be necessary before relying on the contents of - * offscreen memory from the CPU's perspective. It also calls an optional - * driver MarkSync() callback, the return value of which may be used to do partial - * synchronization with the hardware in the future. - */ -void uxa_mark_sync(ScreenPtr pScreen) -{ - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - - uxa_screen->info->needsSync = TRUE; - if (uxa_screen->info->MarkSync != NULL) { - uxa_screen->info->lastMarker = (*uxa_screen->info->MarkSync)(pScreen); - } -} - -/** - * uxa_wait_sync() ensures that all drawing has been completed. - * - * @param pScreen screen being synchronized. - * - * Calls down into the driver to ensure that all previous drawing has completed. - * It should always be called before relying on the framebuffer contents - * reflecting previous drawing, from a CPU perspective. - */ -void uxa_wait_sync(ScreenPtr pScreen) -{ - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - - if (uxa_screen->info->needsSync && !uxa_screen->swappedOut) { - (*uxa_screen->info->WaitMarker)(pScreen, uxa_screen->info->lastMarker); - uxa_screen->info->needsSync = FALSE; - } -} diff --git a/uxa/uxa.h b/uxa/uxa.h index 32d5a5a2..22889b7c 100644 --- a/uxa/uxa.h +++ b/uxa/uxa.h @@ -70,36 +70,36 @@ typedef struct _UxaDriver { /** @{ */ /** - * maxX controls the X coordinate limitation for rendering from the card. - * The driver should never receive a request for rendering beyond maxX + * max_x controls the X coordinate limitation for rendering from the card. + * The driver should never receive a request for rendering beyond max_x * in the X direction from the origin of a pixmap. */ - int maxX; + int max_x; /** - * maxY controls the Y coordinate limitation for rendering from the card. - * The driver should never receive a request for rendering beyond maxY + * max_y controls the Y coordinate limitation for rendering from the card. + * The driver should never receive a request for rendering beyond max_y * in the Y direction from the origin of a pixmap. */ - int maxY; + int max_y; /** @} */ /* private */ Bool needsSync; int lastMarker; - /** @name Solid + /** @name solid * @{ */ /** - * PrepareSolid() sets up the driver for doing a solid fill. + * prepare_solid() sets up the driver for doing a solid fill. * @param pPixmap Destination pixmap * @param alu raster operation * @param planemask write mask for the fill * @param fg "foreground" color for the fill * * This call should set up the driver for doing a series of solid fills - * through the Solid() call. The alu raster op is one of the GX* + * through the solid() call. The alu raster op is one of the GX* * graphics functions listed in X.h, and typically maps to a similar * single-byte "ROP" setting in all hardware. The planemask controls * which bits of the destination should be affected, and will only represent @@ -109,16 +109,16 @@ typedef struct _UxaDriver { * Note that many drivers will need to store some of the data in the driver * private record, for sending to the hardware with each drawing command. * - * The PrepareSolid() call is required of all drivers, but it may fail for any + * The prepare_solid() call is required of all drivers, but it may fail for any * reason. Failure results in a fallback to software rendering. */ - Bool (*PrepareSolid) (PixmapPtr pPixmap, + Bool (*prepare_solid) (PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg); /** - * Solid() performs a solid fill set up in the last PrepareSolid() call. + * solid() performs a solid fill set up in the last prepare_solid() call. * * @param pPixmap destination pixmap * @param x1 left coordinate @@ -126,37 +126,37 @@ typedef struct _UxaDriver { * @param x2 right coordinate * @param y2 bottom coordinate * - * Performs the fill set up by the last PrepareSolid() call, covering the + * Performs the fill set up by the last prepare_solid() call, covering the * area from (x1,y1) to (x2,y2) in pPixmap. Note that the coordinates are * in the coordinate space of the destination pixmap, so the driver will * need to set up the hardware's offset and pitch for the destination * coordinates according to the pixmap's offset and pitch within * framebuffer. * - * This call is required if PrepareSolid() ever succeeds. + * This call is required if prepare_solid() ever succeeds. */ - void (*Solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2); + void (*solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2); /** - * DoneSolid() finishes a set of solid fills. + * done_solid() finishes a set of solid fills. * * @param pPixmap destination pixmap. * - * The DoneSolid() call is called at the end of a series of consecutive - * Solid() calls following a successful PrepareSolid(). This allows drivers + * The done_solid() call is called at the end of a series of consecutive + * solid() calls following a successful prepare_solid(). This allows drivers * to finish up emitting drawing commands that were buffered, or clean up - * state from PrepareSolid(). + * state from prepare_solid(). * - * This call is required if PrepareSolid() ever succeeds. + * This call is required if prepare_solid() ever succeeds. */ - void (*DoneSolid) (PixmapPtr pPixmap); + void (*done_solid) (PixmapPtr pPixmap); /** @} */ - /** @name Copy + /** @name copy * @{ */ /** - * PrepareCopy() sets up the driver for doing a copy within video + * prepare_copy() sets up the driver for doing a copy within video * memory. * * @param pSrcPixmap source pixmap @@ -173,7 +173,7 @@ typedef struct _UxaDriver { * is to deal with self-overlapping copies when pSrcPixmap == pDstPixmap. * If your hardware can only support blits that are (left to right, top to * bottom) or (right to left, bottom to top), then you should set - * #UXA_TWO_BITBLT_DIRECTIONS, and UXA will break down Copy operations to + * #UXA_TWO_BITBLT_DIRECTIONS, and UXA will break down copy operations to * ones that meet those requirements. The alu raster op is one of the GX* * graphics functions listed in X.h, and typically maps to a similar * single-byte "ROP" setting in all hardware. The planemask controls which @@ -183,10 +183,10 @@ typedef struct _UxaDriver { * Note that many drivers will need to store some of the data in the driver * private record, for sending to the hardware with each drawing command. * - * The PrepareCopy() call is required of all drivers, but it may fail for any + * The prepare_copy() call is required of all drivers, but it may fail for any * reason. Failure results in a fallback to software rendering. */ - Bool (*PrepareCopy) (PixmapPtr pSrcPixmap, + Bool (*prepare_copy) (PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int dx, int dy, @@ -194,7 +194,7 @@ typedef struct _UxaDriver { Pixel planemask); /** - * Copy() performs a copy set up in the last PrepareCopy call. + * copy() performs a copy set up in the last prepare_copy call. * * @param pDstPixmap destination pixmap * @param srcX source X coordinate @@ -204,20 +204,20 @@ typedef struct _UxaDriver { * @param width width of the rectangle to be copied * @param height height of the rectangle to be copied. * - * Performs the copy set up by the last PrepareCopy() call, copying the + * Performs the copy set up by the last prepare_copy() call, copying the * rectangle from (srcX, srcY) to (srcX + width, srcY + width) in the source * pixmap to the same-sized rectangle at (dstX, dstY) in the destination * pixmap. Those rectangles may overlap in memory, if * pSrcPixmap == pDstPixmap. Note that this call does not receive the * pSrcPixmap as an argument -- if it's needed in this function, it should - * be stored in the driver private during PrepareCopy(). As with Solid(), + * be stored in the driver private during prepare_copy(). As with solid(), * the coordinates are in the coordinate space of each pixmap, so the driver * will need to set up source and destination pitches and offsets from those * pixmaps, probably using uxaGetPixmapOffset() and uxa_get_pixmap_pitch(). * - * This call is required if PrepareCopy ever succeeds. + * This call is required if prepare_copy ever succeeds. */ - void (*Copy) (PixmapPtr pDstPixmap, + void (*copy) (PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, @@ -226,25 +226,25 @@ typedef struct _UxaDriver { int height); /** - * DoneCopy() finishes a set of copies. + * done_copy() finishes a set of copies. * * @param pPixmap destination pixmap. * - * The DoneCopy() call is called at the end of a series of consecutive - * Copy() calls following a successful PrepareCopy(). This allows drivers + * The done_copy() call is called at the end of a series of consecutive + * copy() calls following a successful prepare_copy(). This allows drivers * to finish up emitting drawing commands that were buffered, or clean up - * state from PrepareCopy(). + * state from prepare_copy(). * - * This call is required if PrepareCopy() ever succeeds. + * This call is required if prepare_copy() ever succeeds. */ - void (*DoneCopy) (PixmapPtr pDstPixmap); + void (*done_copy) (PixmapPtr pDstPixmap); /** @} */ - /** @name Composite + /** @name composite * @{ */ /** - * CheckComposite() checks to see if a composite operation could be + * check_composite() checks to see if a composite operation could be * accelerated. * * @param op Render operation @@ -252,25 +252,25 @@ typedef struct _UxaDriver { * @param pMaskPicture mask picture * @param pDstPicture destination Picture * - * The CheckComposite() call checks if the driver could handle acceleration + * The check_composite() call checks if the driver could handle acceleration * of op with the given source, mask, and destination pictures. This allows * drivers to check source and destination formats, supported operations, * transformations, and component alpha state, and send operations it can't * support to software rendering early on. * - * See PrepareComposite() for more details on likely issues that drivers - * will have in accelerating Composite operations. + * See prepare_composite() for more details on likely issues that drivers + * will have in accelerating composite operations. * - * The CheckComposite() call is recommended if PrepareComposite() is + * The check_composite() call is recommended if prepare_composite() is * implemented, but is not required. */ - Bool (*CheckComposite) (int op, + Bool (*check_composite) (int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture); /** - * PrepareComposite() sets up the driver for doing a Composite operation + * prepare_composite() sets up the driver for doing a composite operation * described in the Render extension protocol spec. * * @param op Render operation @@ -281,7 +281,7 @@ typedef struct _UxaDriver { * @param pMask mask pixmap * @param pDst destination pixmap * - * This call should set up the driver for doing a series of Composite + * This call should set up the driver for doing a series of composite * operations, as described in the Render protocol spec, with the given * pSrcPicture, pMaskPicture, and pDstPicture. The pSrc, pMask, and * pDst are the pixmaps containing the pixel data, and should be used for @@ -295,7 +295,7 @@ typedef struct _UxaDriver { * operation is simply src OP dst instead of src IN mask OP dst, and * mask coordinates should be ignored. * - pMarkPicture may have componentAlpha set, which greatly changes - * the behavior of the Composite operation. componentAlpha has no effect + * the behavior of the composite operation. componentAlpha has no effect * when set on pSrcPicture or pDstPicture. * - The source and mask Pictures may have a transformation set * (Picture->transform != NULL), which means that the source coordinates @@ -306,7 +306,7 @@ typedef struct _UxaDriver { * - The source and mask pictures may have a filter set. PictFilterNearest * and PictFilterBilinear are defined in the Render protocol, but others * may be encountered, and must be handled correctly (usually by - * PrepareComposite failing, and falling back to software). Filters have + * prepare_composite failing, and falling back to software). Filters have * no effect on Pictures when used as a destination. * - The source and mask Pictures may have repeating set, which must be * respected. Many chipsets will be unable to support repeating on @@ -318,12 +318,12 @@ typedef struct _UxaDriver { * Note that many drivers will need to store some of the data in the driver * private record, for sending to the hardware with each drawing command. * - * The PrepareComposite() call is not required. However, it is highly + * The prepare_composite() call is not required. However, it is highly * recommended for performance of antialiased font rendering and performance * of cairo applications. Failure results in a fallback to software * rendering. */ - Bool (*PrepareComposite) (int op, + Bool (*prepare_composite) (int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture, @@ -332,8 +332,8 @@ typedef struct _UxaDriver { PixmapPtr pDst); /** - * Composite() performs a Composite operation set up in the last - * PrepareComposite() call. + * composite() performs a composite operation set up in the last + * prepare_composite() call. * * @param pDstPixmap destination pixmap * @param srcX source X coordinate @@ -345,7 +345,7 @@ typedef struct _UxaDriver { * @param width destination rectangle width * @param height destination rectangle height * - * Performs the Composite operation set up by the last PrepareComposite() + * Performs the composite operation set up by the last prepare_composite() * call, to the rectangle from (dstX, dstY) to (dstX + width, dstY + height) * in the destination Pixmap. Note that if a transformation was set on * the source or mask Pictures, the source rectangles may not be the same @@ -353,9 +353,9 @@ typedef struct _UxaDriver { * transformation right at the subpixel level can be tricky, and rendercheck * can test this for you. * - * This call is required if PrepareComposite() ever succeeds. + * This call is required if prepare_composite() ever succeeds. */ - void (*Composite) (PixmapPtr pDst, + void (*composite) (PixmapPtr pDst, int srcX, int srcY, int maskX, @@ -366,22 +366,22 @@ typedef struct _UxaDriver { int height); /** - * DoneComposite() finishes a set of Composite operations. + * done_composite() finishes a set of composite operations. * * @param pPixmap destination pixmap. * - * The DoneComposite() call is called at the end of a series of consecutive - * Composite() calls following a successful PrepareComposite(). This allows + * The done_composite() call is called at the end of a series of consecutive + * composite() calls following a successful prepare_composite(). This allows * drivers to finish up emitting drawing commands that were buffered, or - * clean up state from PrepareComposite(). + * clean up state from prepare_composite(). * - * This call is required if PrepareComposite() ever succeeds. + * This call is required if prepare_composite() ever succeeds. */ - void (*DoneComposite) (PixmapPtr pDst); + void (*done_composite) (PixmapPtr pDst); /** @} */ /** - * UploadToScreen() loads a rectangle of data from src into pDst. + * put_image() loads a rectangle of data from src into pDst. * * @param pDst destination pixmap * @param x destination X coordinate. @@ -391,27 +391,23 @@ typedef struct _UxaDriver { * @param src pointer to the beginning of the source data * @param src_pitch pitch (in bytes) of the lines of source data. * - * UploadToScreen() copies data in system memory beginning at src (with + * put_image() copies data in system memory beginning at src (with * pitch src_pitch) into the destination pixmap from (x, y) to * (x + width, y + height). This is typically done with hostdata uploads, * where the CPU sets up a blit command on the hardware with instructions * that the blit data will be fed through some sort of aperture on the card. * - * If UploadToScreen() is performed asynchronously, it is up to the driver - * to call uxa_mark_sync(). This is in contrast to most other acceleration - * calls in UXA. - * - * UploadToScreen() can aid in pixmap migration, but is most important for - * the performance of uxa_glyphs() (antialiased font drawing) by allowing - * pipelining of data uploads, avoiding a sync of the card after each glyph. + * put_image() is most important for the performance of uxa_glyphs() + * (antialiased font drawing) by allowing pipelining of data uploads, + * avoiding a sync of the card after each glyph. * * @return TRUE if the driver successfully uploaded the data. FALSE * indicates that UXA should fall back to doing the upload in software. * - * UploadToScreen() is not required, but is recommended if Composite + * put_image() is not required, but is recommended if composite * acceleration is supported. */ - Bool (*UploadToScreen) (PixmapPtr pDst, + Bool (*put_image) (PixmapPtr pDst, int x, int y, int w, @@ -420,33 +416,7 @@ typedef struct _UxaDriver { int src_pitch); /** - * UploadToScratch() is used to upload a pixmap to a scratch area for - * acceleration. - * - * @param pSrc source pixmap in host memory - * @param pDst fake, scratch pixmap to be set up in offscreen memory. - * - * The UploadToScratch() call was added to support Xati before Xati had - * support for hostdata uploads and before uxa_glyphs() was written. It - * behaves incorrectly (uses an invalid pixmap as pDst), - * and UploadToScreen() should be implemented instead. - * - * Drivers implementing UploadToScratch() had to set up space (likely in a - * statically allocated area) in offscreen memory, copy pSrc to that - * scratch area, and adust pDst->devKind for the pitch and - * pDst->devPrivate.ptr for the pointer to that scratch area. The driver - * was responsible for syncing (as it was implemented using memcpy() in - * Xati), and only the data from the last UploadToScratch() was guaranteed - * to be valid at any given time. - * - * UploadToScratch() should not be implemented by drivers, and will likely - * be removed in a future version of UXA. - */ - Bool (*UploadToScratch) (PixmapPtr pSrc, - PixmapPtr pDst); - - /** - * DownloadFromScreen() loads a rectangle of data from pSrc into dst + * get_image() loads a rectangle of data from pSrc into dst * * @param pSrc source pixmap * @param x source X coordinate. @@ -456,108 +426,72 @@ typedef struct _UxaDriver { * @param dst pointer to the beginning of the destination data * @param dst_pitch pitch (in bytes) of the lines of destination data. * - * DownloadFromScreen() copies data from offscreen memory in pSrc from + * get_image() copies data from offscreen memory in pSrc from * (x, y) to (x + width, y + height), to system memory starting at * dst (with pitch dst_pitch). This would usually be done * using scatter-gather DMA, supported by a DRM call, or by blitting to AGP * and then synchronously reading from AGP. Because the implementation * might be synchronous, UXA leaves it up to the driver to call - * uxa_mark_sync() if DownloadFromScreen() was asynchronous. This is in + * uxa_mark_sync() if get_image() was asynchronous. This is in * contrast to most other acceleration calls in UXA. * - * DownloadFromScreen() can aid in the largest bottleneck in pixmap - * migration, which is the read from framebuffer when evicting pixmaps from - * framebuffer memory. Thus, it is highly recommended, even though - * implementations are typically complicated. - * * @return TRUE if the driver successfully downloaded the data. FALSE * indicates that UXA should fall back to doing the download in software. * - * DownloadFromScreen() is not required, but is highly recommended. + * get_image() is not required, but is highly recommended. */ - Bool (*DownloadFromScreen)(PixmapPtr pSrc, + Bool (*get_image)(PixmapPtr pSrc, int x, int y, int w, int h, char *dst, int dst_pitch); - /** - * MarkSync() requests that the driver mark a synchronization point, - * returning an driver-defined integer marker which could be requested for - * synchronization to later in WaitMarker(). This might be used in the - * future to avoid waiting for full hardware stalls before accessing pixmap - * data with the CPU, but is not important in the current incarnation of - * UXA. - * - * Note that drivers should call uxa_mark_sync() when they have done some - * acceleration, rather than their own MarkSync() handler, as otherwise UXA - * will be unaware of the driver's acceleration and not sync to it during - * fallbacks. - * - * MarkSync() is optional. - */ - int (*MarkSync) (ScreenPtr pScreen); - - /** - * WaitMarker() waits for all rendering before the given marker to have - * completed. If the driver does not implement MarkSync(), marker is - * meaningless, and all rendering by the hardware should be completed before - * WaitMarker() returns. - * - * Note that drivers should call uxa_wait_sync() to wait for all acceleration - * to finish, as otherwise UXA will be unaware of the driver having - * synchronized, resulting in excessive WaitMarker() calls. - * - * WaitMarker() is required of all drivers. - */ - void (*WaitMarker) (ScreenPtr pScreen, int marker); - /** @{ */ /** - * PrepareAccess() is called before CPU access to an offscreen pixmap. + * prepare_access() is called before CPU access to an offscreen pixmap. * * @param pPix the pixmap being accessed * @param index the index of the pixmap being accessed. * - * PrepareAccess() will be called before CPU access to an offscreen pixmap. + * prepare_access() will be called before CPU access to an offscreen pixmap. * This can be used to set up hardware surfaces for byteswapping or * untiling, or to adjust the pixmap's devPrivate.ptr for the purpose of * making CPU access use a different aperture. * * The index is one of #UXA_PREPARE_DEST, #UXA_PREPARE_SRC, or * #UXA_PREPARE_MASK, indicating which pixmap is in question. Since only up - * to three pixmaps will have PrepareAccess() called on them per operation, + * to three pixmaps will have prepare_access() called on them per operation, * drivers can have a small, statically-allocated space to maintain state - * for PrepareAccess() and FinishAccess() in. Note that the same pixmap may - * have PrepareAccess() called on it more than once, for uxample when doing - * a copy within the same pixmap (so it gets PrepareAccess as() + * for prepare_access() and finish_access() in. Note that the same pixmap may + * have prepare_access() called on it more than once, for uxample when doing + * a copy within the same pixmap (so it gets prepare_access as() * #UXA_PREPARE_DEST and then as #UXA_PREPARE_SRC). * - * PrepareAccess() may fail. An uxample might be the case of hardware that - * can set up 1 or 2 surfaces for CPU access, but not 3. If PrepareAccess() + * prepare_access() may fail. An uxample might be the case of hardware that + * can set up 1 or 2 surfaces for CPU access, but not 3. If prepare_access() * fails, UXA will migrate the pixmap to system memory. - * DownloadFromScreen() must be implemented and must not fail if a driver - * wishes to fail in PrepareAccess(). PrepareAccess() must not fail when + * get_image() must be implemented and must not fail if a driver + * wishes to fail in prepare_access(). prepare_access() must not fail when * pPix is the visible screen, because the visible screen can not be * migrated. * - * @return TRUE if PrepareAccess() successfully prepared the pixmap for CPU + * @return TRUE if prepare_access() successfully prepared the pixmap for CPU * drawing. - * @return FALSE if PrepareAccess() is unsuccessful and UXA should use - * DownloadFromScreen() to migate the pixmap out. + * @return FALSE if prepare_access() is unsuccessful and UXA should use + * get_image() to migate the pixmap out. */ - Bool (*PrepareAccess)(PixmapPtr pPix, uxa_access_t access); + Bool (*prepare_access)(PixmapPtr pPix, uxa_access_t access); /** - * FinishAccess() is called after CPU access to an offscreen pixmap. + * finish_access() is called after CPU access to an offscreen pixmap. * * @param pPix the pixmap being accessed * @param index the index of the pixmap being accessed. * - * FinishAccess() will be called after finishing CPU access of an offscreen - * pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be - * called if PrepareAccess() failed. + * finish_access() will be called after finishing CPU access of an offscreen + * pixmap set up by prepare_access(). Note that the finish_access() will not be + * called if prepare_access() failed. */ - void (*FinishAccess)(PixmapPtr pPix); + void (*finish_access)(PixmapPtr pPix); /** * PixmapIsOffscreen() is an optional driver replacement to @@ -569,42 +503,42 @@ typedef struct _UxaDriver { * * uxa_pixmap_is_offscreen() is used to determine if a pixmap is in offscreen * memory, meaning that acceleration could probably be done to it, and that it - * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it + * will need to be wrapped by prepare_access()/finish_access() when accessing it * with the CPU. * * */ - Bool (*PixmapIsOffscreen)(PixmapPtr pPix); + Bool (*pixmap_is_offscreen)(PixmapPtr pPix); /** - * maxPitchPixels controls the pitch limitation for rendering from + * max_pitch_pixels controls the pitch limitation for rendering from * the card. * The driver should never receive a request for rendering a pixmap - * that has a pitch (in pixels) beyond maxPitchPixels. + * that has a pitch (in pixels) beyond max_pitch_pixels. * * Setting this field is optional -- if your hardware doesn't have * a pitch limitation in pixels, don't set this. If neither this value - * nor maxPitchBytes is set, then maxPitchPixels is set to maxX. - * If set, it must not be smaller than maxX. + * nor max_pitch_bytes is set, then max_pitch_pixels is set to max_x. + * If set, it must not be smaller than max_x. * - * @sa maxPitchBytes + * @sa max_pitch_bytes */ - int maxPitchPixels; + int max_pitch_pixels; /** - * maxPitchBytes controls the pitch limitation for rendering from + * max_pitch_bytes controls the pitch limitation for rendering from * the card. * The driver should never receive a request for rendering a pixmap - * that has a pitch (in bytes) beyond maxPitchBytes. + * that has a pitch (in bytes) beyond max_pitch_bytes. * * Setting this field is optional -- if your hardware doesn't have * a pitch limitation in bytes, don't set this. - * If set, it must not be smaller than maxX * 4. - * There's no default value for maxPitchBytes. + * If set, it must not be smaller than max_x * 4. + * There's no default value for max_pitch_bytes. * - * @sa maxPitchPixels + * @sa max_pitch_pixels */ - int maxPitchBytes; + int max_pitch_bytes; /** @} */ } uxa_driver_t; @@ -630,15 +564,6 @@ uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver); void uxa_driver_fini(ScreenPtr pScreen); -void -uxa_mark_sync(ScreenPtr pScreen); - -void -uxa_wait_sync(ScreenPtr pScreen); - -void -uxaEnableDisableFBAccess (int index, Bool enable); - CARD32 uxa_get_pixmap_first_pixel (PixmapPtr pPixmap); From 8f10bfb127bfe73d83d58f1f306fb9a4dfd825d6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 5 Aug 2008 22:34:24 -0700 Subject: [PATCH 42/45] Use EXA by default instead of UXA until we have GTT mapping --- src/i830_driver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/i830_driver.c b/src/i830_driver.c index 6b8f9987..6cc2352d 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -1582,12 +1582,12 @@ I830PreInit(ScrnInfoPtr pScrn, int flags) #ifdef I830_USE_XAA pI830->accel = ACCEL_XAA; #endif -#ifdef I830_USE_EXA - pI830->accel = ACCEL_EXA; -#endif #ifdef I830_USE_UXA pI830->accel = ACCEL_UXA; #endif +#ifdef I830_USE_EXA + pI830->accel = ACCEL_EXA; +#endif #if I830_USE_XAA + I830_USE_EXA + I830_USE_UXA >= 2 from = X_DEFAULT; if ((s = (char *)xf86GetOptValString(pI830->Options, From 68f0872db6ec4d5dc3b524ee08ecad0aa125acd9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 5 Aug 2008 22:36:03 -0700 Subject: [PATCH 43/45] [uxa] Check xalloc returns and deal with failure Failing xalloc in a rendering function means just dropping the drawing on the floor (that's what we've always done). --- uxa/uxa-accel.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c index edc68f2a..b25a8faa 100644 --- a/uxa/uxa-accel.c +++ b/uxa/uxa-accel.c @@ -508,6 +508,8 @@ uxa_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, } prect = xalloc(sizeof(xRectangle) * npt); + if (!prect) + return; for (i = 0; i < npt; i++) { prect[i].x = ppt[i].x; prect[i].y = ppt[i].y; @@ -543,6 +545,8 @@ uxa_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, } prect = xalloc(sizeof(xRectangle) * (npt - 1)); + if (!prect) + return; x1 = ppt[0].x; y1 = ppt[0].y; /* If we have any non-horizontal/vertical, fall back. */ @@ -612,6 +616,8 @@ uxa_poly_segment (DrawablePtr pDrawable, GCPtr pGC, int nseg, } prect = xalloc(sizeof(xRectangle) * nseg); + if (!prect) + return; for (i = 0; i < nseg; i++) { if (pSeg[i].x1 < pSeg[i].x2) { prect[i].x = pSeg[i].x1; From fc3e287e6b6db21b113aa40ec4d397802c067f8b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 5 Aug 2008 22:50:01 -0700 Subject: [PATCH 44/45] [uxa] Remove unused pixmap size limits. All size-related rendering limits should be managed by the driver in the pixmap_is_offscreen call. There's no need for uxa to even know these values. --- src/i830_exa.c | 3 --- uxa/uxa.c | 14 -------------- uxa/uxa.h | 50 -------------------------------------------------- 3 files changed, 67 deletions(-) diff --git a/src/i830_exa.c b/src/i830_exa.c index 87a7e6cc..20417410 100644 --- a/src/i830_exa.c +++ b/src/i830_exa.c @@ -720,9 +720,6 @@ i830_uxa_init (ScreenPtr pScreen) i830->uxa_driver->uxa_major = 1; i830->uxa_driver->uxa_minor = 0; - i830->uxa_driver->max_x = i830->accel_max_x; - i830->uxa_driver->max_y = i830->accel_max_y; - /* Solid fill */ i830->uxa_driver->prepare_solid = I830EXAPrepareSolid; i830->uxa_driver->solid = I830EXASolid; diff --git a/uxa/uxa.c b/uxa/uxa.c index c76cb1d2..aac3d686 100644 --- a/uxa/uxa.c +++ b/uxa/uxa.c @@ -408,20 +408,6 @@ uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver) return FALSE; } - /* If the driver doesn't set any max pitch values, we'll just assume - * that there's a limitation by pixels, and that it's the same as - * maxX. - * - * We want max_pitch_pixels or max_pitch_bytes to be set so we can check - * pixmaps against the max pitch in uxaCreatePixmap() -- it matters - * whether a pixmap is rejected because of its pitch or - * because of its width. - */ - if (!uxa_driver->max_pitch_pixels && !uxa_driver->max_pitch_bytes) - { - uxa_driver->max_pitch_pixels = uxa_driver->max_x; - } - #ifdef RENDER ps = GetPictureScreenIfSet(screen); #endif diff --git a/uxa/uxa.h b/uxa/uxa.h index 22889b7c..f1c1cfa9 100644 --- a/uxa/uxa.h +++ b/uxa/uxa.h @@ -68,26 +68,6 @@ typedef struct _UxaDriver { */ int flags; - /** @{ */ - /** - * max_x controls the X coordinate limitation for rendering from the card. - * The driver should never receive a request for rendering beyond max_x - * in the X direction from the origin of a pixmap. - */ - int max_x; - - /** - * max_y controls the Y coordinate limitation for rendering from the card. - * The driver should never receive a request for rendering beyond max_y - * in the Y direction from the origin of a pixmap. - */ - int max_y; - /** @} */ - - /* private */ - Bool needsSync; - int lastMarker; - /** @name solid * @{ */ @@ -510,36 +490,6 @@ typedef struct _UxaDriver { */ Bool (*pixmap_is_offscreen)(PixmapPtr pPix); - /** - * max_pitch_pixels controls the pitch limitation for rendering from - * the card. - * The driver should never receive a request for rendering a pixmap - * that has a pitch (in pixels) beyond max_pitch_pixels. - * - * Setting this field is optional -- if your hardware doesn't have - * a pitch limitation in pixels, don't set this. If neither this value - * nor max_pitch_bytes is set, then max_pitch_pixels is set to max_x. - * If set, it must not be smaller than max_x. - * - * @sa max_pitch_bytes - */ - int max_pitch_pixels; - - /** - * max_pitch_bytes controls the pitch limitation for rendering from - * the card. - * The driver should never receive a request for rendering a pixmap - * that has a pitch (in bytes) beyond max_pitch_bytes. - * - * Setting this field is optional -- if your hardware doesn't have - * a pitch limitation in bytes, don't set this. - * If set, it must not be smaller than max_x * 4. - * There's no default value for max_pitch_bytes. - * - * @sa max_pitch_pixels - */ - int max_pitch_bytes; - /** @} */ } uxa_driver_t; From 5c9a62a29f62a9ecce37fae98cb01f8217eaba15 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 6 Aug 2008 12:39:03 -0700 Subject: [PATCH 45/45] Revert "Switch to using a buffer object for the vertex buffer" This reverts commit 1abf4d3a7a203ff5d6e5ceda29573e7fd69ddf8e. Conflicts: src/i965_render.c - flushing was removed, keep it that way --- src/i965_render.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/src/i965_render.c b/src/i965_render.c index 62d0035f..391e0633 100644 --- a/src/i965_render.c +++ b/src/i965_render.c @@ -37,7 +37,6 @@ #include "xf86.h" #include "i830.h" #include "i915_reg.h" -#include "i915_drm.h" /* bring in brw structs */ #include "brw_defines.h" @@ -61,7 +60,7 @@ do { \ #endif #define MAX_VERTEX_PER_COMPOSITE 24 -#define VERTEX_BUFFER_SIZE (16 * MAX_VERTEX_PER_COMPOSITE) +#define MAX_VERTEX_BUFFERS 256 struct blendinfo { Bool dst_alpha; @@ -503,14 +502,14 @@ typedef struct _gen4_state { [BRW_BLENDFACTOR_COUNT]; struct brw_cc_viewport cc_viewport; PAD64 (brw_cc_viewport, 0); + + float vb[MAX_VERTEX_PER_COMPOSITE * MAX_VERTEX_BUFFERS]; } gen4_state_t; /** Private data for gen4 render accel implementation. */ struct gen4_render_state { gen4_state_t *card_state; uint32_t card_state_offset; - dri_bo *vb_bo; - int vb_bo_busy; int binding_table_index; int surface_state_index; @@ -1271,11 +1270,12 @@ i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, { ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; I830Ptr pI830 = I830PTR(pScrn); + gen4_state_t *card_state = pI830->gen4_render_state->card_state; struct gen4_render_state *render_state = pI830->gen4_render_state; Bool has_mask; Bool is_affine_src, is_affine_mask, is_affine; float src_x[3], src_y[3], src_w[3], mask_x[3], mask_y[3], mask_w[3]; - float *vb; + float *vb = card_state->vb; int i; is_affine_src = i830_transform_is_affine (pI830->transform[0]); @@ -1352,25 +1352,11 @@ i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, } } - /* Arrange for a buffer object with sufficient space for our - * vertices, and that isn't "busy", that is, it is not already - * referenced by a batch that has been flushed. */ - if (! render_state->vb_bo || render_state->vb_bo_busy || - render_state->vb_offset + MAX_VERTEX_PER_COMPOSITE > VERTEX_BUFFER_SIZE) - { - if (render_state->vb_bo) - dri_bo_unreference (render_state->vb_bo); - - render_state->vb_bo = dri_bo_alloc (pI830->bufmgr, "vb", - VERTEX_BUFFER_SIZE * sizeof (float), - 4096); + if (render_state->vb_offset + MAX_VERTEX_PER_COMPOSITE >= ARRAY_SIZE(card_state->vb)) { + i830WaitSync(pScrn); render_state->vb_offset = 0; } - /* Map the vertex buffer object so we can write to it. */ - dri_bo_map (render_state->vb_bo, 1); - vb = render_state->vb_bo->virtual; - i = render_state->vb_offset; /* rect (x2,y2) */ vb[i++] = (float)(dstX + w); @@ -1413,9 +1399,7 @@ i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, if (!is_affine) vb[i++] = mask_w[0]; } - assert (i <= VERTEX_BUFFER_SIZE); - - dri_bo_unmap (render_state->vb_bo); + assert (i * 4 <= sizeof(card_state->vb)); BEGIN_BATCH(12); OUT_BATCH(MI_FLUSH); @@ -1424,7 +1408,7 @@ i965_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, OUT_BATCH((0 << VB0_BUFFER_INDEX_SHIFT) | VB0_VERTEXDATA | (render_state->vertex_size << VB0_BUFFER_PITCH_SHIFT)); - OUT_RELOC(render_state->vb_bo, I915_GEM_DOMAIN_VERTEX, 0, + OUT_BATCH(render_state->card_state_offset + offsetof(gen4_state_t, vb) + render_state->vb_offset * 4); OUT_BATCH(3); OUT_BATCH(0); // ignore for VERTEXDATA, but still there