summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2008-08-06 12:40:47 -0700
committerJesse Barnes <jbarnes@virtuousgeek.org>2008-08-06 12:40:47 -0700
commitf9504eff31eb3c9c6c6b33dced9875866ff8307e (patch)
treedcc861375a18d76d30e512ecfa3f4381ae5fd6f9
parentf91134795b545c8baebf218975b261c76a0e5873 (diff)
parent5c9a62a29f62a9ecce37fae98cb01f8217eaba15 (diff)
Merge branch 'drm-gem'
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac15
-rw-r--r--src/Makefile.am12
-rw-r--r--src/i810_reg.h11
-rw-r--r--src/i830.h76
-rw-r--r--src/i830_accel.c132
-rw-r--r--src/i830_batchbuffer.c167
-rw-r--r--src/i830_batchbuffer.h148
-rw-r--r--src/i830_debug.c15
-rw-r--r--src/i830_dri.c128
-rw-r--r--src/i830_dri.h1
-rw-r--r--src/i830_driver.c344
-rw-r--r--src/i830_exa.c336
-rw-r--r--src/i830_memory.c192
-rw-r--r--src/i830_render.c21
-rw-r--r--src/i830_ring.h5
-rw-r--r--src/i830_video.c4
-rw-r--r--src/i915_3d.h10
-rw-r--r--src/i915_render.c16
-rw-r--r--src/i915_video.c2
-rw-r--r--src/i965_render.c20
-rw-r--r--src/reg_dumper/.gitignore1
-rw-r--r--src/reg_dumper/Makefile.am8
-rw-r--r--src/reg_dumper/idle.c8
-rw-r--r--src/reg_dumper/reg_dumper.h1
-rw-r--r--src/reg_dumper/statuspage.c81
-rw-r--r--src/reg_dumper/util.c86
-rw-r--r--src/xvmc/Makefile.am5
-rw-r--r--uxa/Makefile.am20
-rw-r--r--uxa/uxa-accel.c1032
-rw-r--r--uxa/uxa-glyphs.c880
-rw-r--r--uxa/uxa-priv.h443
-rw-r--r--uxa/uxa-render.c1015
-rw-r--r--uxa/uxa-unaccel.c370
-rw-r--r--uxa/uxa.c510
-rw-r--r--uxa/uxa.h528
36 files changed, 6192 insertions, 453 deletions
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 276fc1fb..b24a1541 100644
--- a/configure.ac
+++ b/configure.ac
@@ -196,9 +196,10 @@ 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.4.0],[DRI_MM=yes], [DRI_MM=no])
@@ -208,17 +209,6 @@ if test "$DRI" = yes; then
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 <inttypes.h>
-#include <i915_drm.h>
-])
- CFLAGS="$save_CFLAGS"
fi
AM_CONDITIONAL(VIDEO_DEBUG, test x$VIDEO_DEBUG = xyes)
@@ -261,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 382c0aa5..dd92c8d9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,13 +30,14 @@ 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@ \
- @XMODES_CFLAGS@ -DI830_XV -DI830_USE_XAA -DI830_USE_EXA
+AM_CFLAGS = @WARN_CFLAGS@ @XORG_CFLAGS@ @DRM_CFLAGS@ @DRI_CFLAGS@ \
+ @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
@@ -93,6 +94,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 \
@@ -154,7 +157,6 @@ INTEL_G4I = \
exa_wm.g4i \
exa_wm_affine.g4i \
exa_wm_projective.g4i
-
INTEL_G4B = \
packed_yuv_sf.g4b \
@@ -176,7 +178,7 @@ INTEL_G4B = \
exa_wm_write.g4b \
exa_wm_yuv_rgb.g4b \
exa_wm_xy.g4b
-
+
EXTRA_DIST = \
$(XMODE_SRCS) \
$(INTEL_G4A) \
diff --git a/src/i810_reg.h b/src/i810_reg.h
index 515e73d1..4b9ce9bd 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -405,7 +405,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:
*/
@@ -490,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 */
@@ -2417,6 +2419,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 6a5de6bc..e2b4885e 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"
@@ -81,6 +78,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "damage.h"
#endif
#endif
+#include "dri_bufmgr.h"
+#include "intel_bufmgr.h"
+#include "i915_drm.h"
#ifdef I830_USE_EXA
#include "exa.h"
@@ -88,6 +88,14 @@ Bool I830EXAInit(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
@@ -95,7 +103,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"
@@ -194,10 +201,10 @@ struct _i830_memory {
i830_memory *prev;
/** @} */
-#ifdef XF86DRI_MM
- drmBO bo;
+ dri_bo *bo;
+ uint32_t alignment;
+ uint32_t gem_name;
Bool lifetime_fixed_offset;
-#endif
};
typedef struct {
@@ -355,6 +362,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;
@@ -398,6 +413,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;
@@ -408,6 +425,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;
@@ -445,6 +473,8 @@ typedef struct _I830Rec {
#endif
#endif
+ Bool need_mi_flush;
+
Bool NeedRingBufferLow;
Bool allowPageFlip;
Bool TripleBuffer;
@@ -481,8 +511,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;
@@ -503,8 +532,19 @@ typedef struct _I830Rec {
#ifdef I830_USE_EXA
ExaDriverPtr EXADriverPtr;
+#endif
+#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;
#endif
+ int accel_pixmap_pitch_alignment;
+ int accel_pixmap_offset_alignment;
+ int accel_max_x;
+ int accel_max_y;
I830WriteIndexedByteFunc writeControl;
I830ReadIndexedByteFunc readControl;
@@ -676,6 +716,12 @@ 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"
+
/* I830 specific functions */
extern int I830WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis);
extern void I830SetPIOAccess(I830Ptr pI830);
@@ -747,8 +793,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,
@@ -783,6 +827,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);
@@ -885,7 +930,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;
}
@@ -903,13 +948,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..a3018187 100644
--- a/src/i830_accel.c
+++ b/src/i830_accel.c
@@ -54,21 +54,25 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include <errno.h>
+
#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)
{
+#if defined(I830_USE_EXA) || defined(I830_USE_UXA)
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;
@@ -77,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
@@ -147,6 +149,9 @@ I830WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis)
#ifdef I830_USE_EXA
pI830->EXADriverPtr = NULL;
#endif
+#ifdef I830_USE_UXA
+ pI830->uxa_driver = NULL;
+#endif
FatalError("lockup\n");
}
@@ -168,12 +173,11 @@ 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");
- if (pI830->noAccel)
+ if (pI830->accel == ACCEL_NONE)
return;
#ifdef XF86DRI
@@ -186,24 +190,40 @@ I830Sync(ScrnInfoPtr pScrn)
if (pI830->entityPrivate && !pI830->entityPrivate->RingRunning) return;
- if (IS_I965G(pI830))
- flags = 0;
-
- /* 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();
+ I830EmitFlush(pScrn);
+
+ intel_batch_flush(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);
}
- i830_wait_ring_idle(pScrn);
-
- pI830->LpRing->space = pI830->LpRing->mem->size - 8;
pI830->nextColorExpandBuf = 0;
}
@@ -259,15 +279,73 @@ 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)
+ /* 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:
+ 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_batchbuffer.c b/src/i830_batchbuffer.c
new file mode 100644
index 00000000..07ea0825
--- /dev/null
+++ b/src/i830_batchbuffer.c
@@ -0,0 +1,167 @@
+/* -*- 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 <eric@anholt.net>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "xf86.h"
+#include "i830.h"
+#include "i830_ring.h"
+#include "i915_drm.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;
+
+ if (pI830->memory_manager) {
+ struct drm_i915_gem_execbuffer *exec;
+ int ret;
+
+ exec = dri_process_relocs(pI830->batch_bo);
+
+ 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;
+
+ 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 {
+ 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 {
+ 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);
+
+ /* 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_batchbuffer.h b/src/i830_batchbuffer.h
new file mode 100644
index 00000000..4c1198d6
--- /dev/null
+++ b/src/i830_batchbuffer.h
@@ -0,0 +1,148 @@
+/**************************************************************************
+
+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;
+}
+
+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 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);
+#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;
+}
+
+#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, reads, write, delta) \
+ intel_batch_emit_reloc_pixmap(pI830, pPixmap, reads, write, delta)
+
+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_debug.c b/src/i830_debug.c
index a7f16835..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;
@@ -1471,13 +1473,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;
}
@@ -1501,8 +1502,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;
@@ -1547,7 +1548,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
@@ -1584,7 +1585,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",
diff --git a/src/i830_dri.c b/src/i830_dri.c
index d38fef1f..d40ada56 100644
--- a/src/i830_dri.c
+++ b/src/i830_dri.c
@@ -65,6 +65,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <stdio.h>
#include <string.h>
#include <assert.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <errno.h>
#include "xf86.h"
#include "xf86_OSproc.h"
@@ -83,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);
@@ -172,22 +158,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,
@@ -594,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
@@ -796,17 +791,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);
@@ -957,6 +955,7 @@ I830DRICloseScreen(ScreenPtr pScreen)
xfree(pI830->pVisualConfigs);
if (pI830->pVisualConfigsPriv)
xfree(pI830->pVisualConfigsPriv);
+ pI830->directRenderingEnabled = FALSE;
}
static Bool
@@ -1071,9 +1070,8 @@ I830DRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
if (!pScrn->vtSema)
return;
pI830->LockHeld = 1;
- i830_refresh_ring(pScrn);
-
- I830EmitFlush(pScrn);
+ if (!pI830->memory_manager)
+ i830_refresh_ring(pScrn);
#ifdef DAMAGE
if (!pI830->pDamage && pI830->allowPageFlip) {
@@ -1128,8 +1126,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) {
@@ -1515,6 +1511,27 @@ I830DRIClipNotify(ScreenPtr pScreen, WindowPtr *ppWin, int num)
}
#endif /* DRI_SUPPORTS_CLIP_NOTIFY */
+static int
+i830_name_buffer (ScrnInfoPtr pScrn, i830_memory *mem)
+{
+ if (mem && mem->bo)
+ {
+ if (!mem->gem_name)
+ {
+ 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;
+ }
+ }
+ return mem->gem_name;
+ }
+ return -1;
+}
+
/**
* Update the SAREA fields with current buffer information.
*
@@ -1546,20 +1563,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
- 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.
@@ -1755,7 +1762,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_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 79a43591..8ea05af0 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -209,9 +209,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifdef XF86DRI
#include "dri.h"
#include <sys/ioctl.h>
-#ifdef XF86DRI_MM
-#include "xf86mm.h"
-#endif
+#include "i915_drm.h"
#endif
#ifdef I830_USE_EXA
@@ -292,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,
@@ -308,7 +304,7 @@ typedef enum {
OPTION_LVDS24BITMODE,
OPTION_FBC,
OPTION_TILING,
-#ifdef XF86DRI_MM
+#ifdef XF86DRI
OPTION_INTELTEXPOOL,
#endif
OPTION_LVDSFIXEDMODE,
@@ -320,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},
@@ -336,7 +330,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},
@@ -855,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 +
@@ -882,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;
}
@@ -1340,6 +1338,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.
@@ -1556,7 +1563,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;
}
/*
@@ -1570,29 +1577,38 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
* All this *could* go away if we removed XAA support from this driver,
* for example. :)
*/
- if (!pI830->noAccel) {
+ if (pI830->accel == ACCEL_UNINIT) {
+ pI830->accel = ACCEL_NONE;
+#ifdef I830_USE_XAA
+ pI830->accel = ACCEL_XAA;
+#endif
+#ifdef I830_USE_UXA
+ pI830->accel = ACCEL_UXA;
+#endif
#ifdef I830_USE_EXA
- pI830->useEXA = TRUE;
-#else
- pI830->useEXA = FALSE;
+ pI830->accel = ACCEL_EXA;
#endif
-#if defined(I830_USE_XAA) && defined(I830_USE_EXA)
+#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;
@@ -1603,7 +1619,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;
@@ -1618,7 +1634,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
from = X_PROBED;
-#ifdef XF86DRI_MM
+#ifdef XF86DRI
if (!IS_I965G(pI830)) {
Bool tmp;
@@ -1780,7 +1796,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 */
@@ -1794,18 +1810,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;
@@ -1823,8 +1840,12 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
return FALSE;
}
xf86LoaderReqSymLists(I830exaSymbols, NULL);
+ break;
}
#endif
+ default:
+ break;
+ }
if (!pI830->SWCursor) {
if (!xf86LoadSubModule(pScrn, "ramdac")) {
PreInitCleanup(pScrn);
@@ -1884,11 +1905,11 @@ 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);
- I830Sync(pScrn);
+ i830_wait_ring_idle(pScrn);
}
OUTREG(LP_RING + RING_LEN, 0);
@@ -1906,7 +1927,7 @@ i830_start_ring(ScrnInfoPtr pScrn)
DPRINTF(PFX, "SetRingRegs\n");
- if (pI830->noAccel)
+ if (pI830->accel == ACCEL_NONE)
return;
if (!I830IsPrimary(pScrn)) return;
@@ -2447,7 +2468,7 @@ IntelEmitInvarientState(ScrnInfoPtr pScrn)
I830Ptr pI830 = I830PTR(pScrn);
uint32_t ctx_addr;
- if (pI830->noAccel)
+ if (pI830->accel == ACCEL_NONE)
return;
#ifdef XF86DRI
@@ -2502,15 +2523,31 @@ 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->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->accel != ACCEL_NONE && (pI830->need_mi_flush || pI830->batch_used))
+ I830EmitFlush(pScrn);
+
+ /* Flush the batch, so that any rendering is executed in a timely
+ * 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
+ drmCommandNone(pI830->drmSubFD, DRM_I915_GEM_THROTTLE);
+#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
@@ -2718,6 +2755,70 @@ 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;
+}
+
+void
+i830_init_bufmgr(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ if (pI830->bufmgr) return;
+
+ 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);
+ 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,
+ 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)
{
@@ -2935,12 +3036,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;
@@ -2950,18 +3051,18 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
pI830->XvEnabled = FALSE;
#endif
- if (!pI830->noAccel) {
- if (pI830->LpRing->mem->size == 0) {
+ 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;
@@ -2983,7 +3084,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;
@@ -3047,6 +3148,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");
@@ -3055,7 +3158,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,
@@ -3103,7 +3206,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");
@@ -3290,9 +3393,19 @@ I830LeaveVT(int scrnIndex, int flags)
xf86_hide_cursors (pScrn);
+ I830Sync(pScrn);
+
RestoreHWState(pScrn);
- i830_stop_ring(pScrn, TRUE);
+ /* 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);
+
+ if (!pI830->memory_manager)
+ i830_stop_ring(pScrn, TRUE);
if (pI830->debug_modes) {
i830CompareRegsToSnapshot(pScrn, "After LeaveVT");
@@ -3302,18 +3415,20 @@ 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) {
- if (pI830->memory_manager != NULL && pScrn->vtSema) {
- drmMMLock(pI830->drmSubFD, DRM_BO_MEM_TT, 1, 0);
- }
+#ifdef XF86DRI
+ 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 */
+#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)
@@ -3342,16 +3457,18 @@ 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
+#ifdef XF86DRI
+ 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 */
+#endif /* XF86DRI */
if (I830IsPrimary(pScrn))
if (!i830_bind_all_memory(pScrn))
@@ -3362,7 +3479,9 @@ I830EnterVT(int scrnIndex, int flags)
/* Update the screen pixmap in case the buffer moved */
i830_update_front_offset(pScrn);
- if (pI830->useEXA && IS_I965G(pI830))
+ intel_batch_init(pScrn);
+
+ if ((pI830->accel == ACCEL_EXA || pI830->accel == ACCEL_UXA) && IS_I965G(pI830))
gen4_render_state_init(pScrn);
if (i830_check_error_state(pScrn)) {
@@ -3370,8 +3489,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);
@@ -3402,7 +3524,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);
@@ -3429,7 +3551,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++;
@@ -3482,16 +3605,11 @@ 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 */
-
}
+ dri_bufmgr_destroy(pI830->bufmgr);
+ pI830->bufmgr = NULL;
+
if (pI830->devicesTimer)
TimerCancel(pI830->devicesTimer);
pI830->devicesTimer = NULL;
@@ -3513,12 +3631,19 @@ 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);
i830_allocator_fini(pScrn);
@@ -3747,19 +3872,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 && pI830->need_sync) {
+ pI830->need_sync = FALSE;
+ I830Sync(pScrn);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
}
void
@@ -3767,16 +3907,30 @@ 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)
+ pI830->need_sync = TRUE;
+ break;
#endif
+ default:
+ break;
+ }
}
void
diff --git a/src/i830_exa.c b/src/i830_exa.c
index 2c807c51..20417410 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...) \
@@ -121,6 +122,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)
{
@@ -162,7 +178,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,12 +188,9 @@ I830EXAPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg)
i830_exa_check_pitch_2d(pPixmap);
- offset = exaGetPixmapOffset(pPixmap);
- pitch = exaGetPixmapPitch(pPixmap);
+ pitch = i830_pixmap_pitch(pPixmap);
- if (offset % pI830->EXADriverPtr->pixmapOffsetAlign != 0)
- I830FALLBACK("pixmap offset not aligned");
- 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,11 +215,10 @@ 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);
+ pitch = i830_pixmap_pitch(pPixmap);
{
BEGIN_BATCH(6);
@@ -227,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_BATCH(offset);
+ OUT_RELOC_PIXMAP(pPixmap, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
OUT_BATCH(pI830->BR[16]);
ADVANCE_BATCH();
}
@@ -236,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
}
/**
@@ -285,15 +302,13 @@ 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);
+ dst_pitch = i830_pixmap_pitch(pDstPixmap);
+ src_pitch = i830_pixmap_pitch(pI830->pSrcPixmap);
{
BEGIN_BATCH(8);
@@ -322,10 +337,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, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
OUT_BATCH((src_y1 << 16) | (src_x1 & 0xffff));
OUT_BATCH(src_pitch);
- OUT_BATCH(src_off);
+ OUT_RELOC_PIXMAP(pI830->pSrcPixmap, I915_GEM_DOMAIN_RENDER, 0, 0);
ADVANCE_BATCH();
}
@@ -334,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) \
@@ -436,7 +477,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));
@@ -472,55 +513,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;
@@ -564,7 +560,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;
}
}
@@ -574,6 +570,206 @@ I830EXAInit(ScreenPtr pScreen)
return TRUE;
}
+static DevPrivateKey uxa_pixmap_key = &uxa_pixmap_key;
+
+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, uxa_access_t access)
+{
+ 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);
+
+ 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;
+ }
+ 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)
+{
+ 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 Bool
+i830_uxa_pixmap_is_offscreen(PixmapPtr pixmap)
+{
+ return i830_uxa_get_pixmap_bo (pixmap) != 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;
+ }
+
+ screen->ModifyPixmapHeader (pixmap, w, h, 0, 0, stride, NULL);
+
+ 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_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);
+ i830_uxa_set_pixmap_bo (pixmap, bo);
+ }
+}
+
+Bool
+i830_uxa_init (ScreenPtr pScreen)
+{
+ ScrnInfoPtr scrn = xf86Screens[pScreen->myNum];
+ I830Ptr i830 = I830PTR(scrn);
+
+ 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(i830->uxa_driver, 0, sizeof(*i830->uxa_driver));
+
+ i830->bufferOffset = 0;
+ i830->uxa_driver->uxa_major = 1;
+ i830->uxa_driver->uxa_minor = 0;
+
+ /* Solid fill */
+ i830->uxa_driver->prepare_solid = I830EXAPrepareSolid;
+ i830->uxa_driver->solid = I830EXASolid;
+ i830->uxa_driver->done_solid = I830EXADoneSolid;
+
+ /* Copy */
+ i830->uxa_driver->prepare_copy = I830EXAPrepareCopy;
+ i830->uxa_driver->copy = I830EXACopy;
+ i830->uxa_driver->done_copy = I830EXADoneCopy;
+
+ /* Composite */
+ if (!IS_I9XX(i830)) {
+ 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->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->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;
+ }
+
+ 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,
+ "UXA initialization failed\n");
+ xfree(i830->uxa_driver);
+ i830->accel = ACCEL_NONE;
+ return FALSE;
+ }
+
+ pScreen->CreatePixmap = i830_uxa_create_pixmap;
+ pScreen->DestroyPixmap = i830_uxa_destroy_pixmap;
+
+ I830SelectBuffer(scrn, I830_SELECT_FRONT);
+
+ return TRUE;
+}
+
#ifdef XF86DRI
#ifndef ExaOffscreenMarkUsed
diff --git a/src/i830_memory.c b/src/i830_memory.c
index 0a2faebb..ff5def69 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 <string.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/ioctl.h>
#include "xf86.h"
#include "xf86_OSproc.h"
#include "i830.h"
#include "i810_reg.h"
+#ifdef XF86DRI
+#include "i915_drm.h"
+#endif
#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
@@ -161,28 +165,18 @@ i830_bind_memory(ScrnInfoPtr pScrn, i830_memory *mem)
if (mem == NULL || mem->bound)
return TRUE;
-#ifdef XF86DRI_MM
- if (mem->bo.size != 0) {
- I830Ptr pI830 = I830PTR(pScrn);
- 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);
- if (ret != 0)
+#ifdef XF86DRI
+ 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 = mem->bo.offset;
- mem->end = mem->bo.offset + mem->size;
+ mem->offset = mem->bo->offset;
+ mem->end = mem->offset + mem->size;
}
#endif
@@ -216,16 +210,9 @@ i830_unbind_memory(ScrnInfoPtr pScrn, i830_memory *mem)
if (mem->tiling != TILE_NONE)
i830_clear_tiling(pScrn, mem->fence_nr);
-#ifdef XF86DRI_MM
- if (mem->bo.size != 0) {
- I830Ptr pI830 = I830PTR(pScrn);
- int ret;
-
- ret = drmBOSetStatus(pI830->drmSubFD, &mem->bo,
- 0, DRM_BO_FLAG_NO_EVICT,
- 0, 0, 0);
-
- if (ret == 0) {
+#ifdef XF86DRI
+ 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;
@@ -254,11 +241,10 @@ i830_free_memory(ScrnInfoPtr pScrn, i830_memory *mem)
/* Free any AGP memory. */
i830_unbind_memory(pScrn, mem);
-#ifdef XF86DRI_MM
- if (mem->bo.size != 0) {
+#ifdef XF86DRI
+ if (mem->bo != NULL) {
I830Ptr pI830 = I830PTR(pScrn);
-
- drmBOUnreference(pI830->drmSubFD, &mem->bo);
+ dri_bo_unreference (mem->bo);
if (pI830->bo_list == mem) {
pI830->bo_list = mem->next;
if (mem->next)
@@ -315,12 +301,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.
@@ -346,6 +330,7 @@ i830_reset_allocations(ScrnInfoPtr pScrn)
pI830->textures = NULL;
#endif
pI830->LpRing->mem = NULL;
+ pI830->fake_bufmgr_mem = NULL;
}
void
@@ -370,7 +355,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.
*/
@@ -379,8 +364,10 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size)
{
I830Ptr pI830 = I830PTR(pScrn);
i830_memory *start, *end;
-#ifdef XF86DRI_MM
+#ifdef XF86DRI
int dri_major, dri_minor, dri_patch;
+ struct drm_i915_getparam gp;
+ int has_gem;
#endif
start = xcalloc(1, sizeof(*start));
@@ -418,15 +405,22 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size)
pI830->memory_list = start;
-#ifdef XF86DRI_MM
+#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;
@@ -437,7 +431,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);
}
@@ -456,13 +450,9 @@ 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;
- /* 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",
@@ -470,19 +460,22 @@ 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");
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");
@@ -490,7 +483,7 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size)
pI830->memory_manager = NULL;
}
}
-#endif /* XF86DRI_MM */
+#endif /* XF86DRI */
return TRUE;
}
@@ -503,14 +496,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) {
- 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;
}
-#endif /* XF86DRI_MM */
/* Free the start/end markers */
free(pI830->memory_list->next);
@@ -628,6 +619,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;
@@ -719,15 +711,13 @@ i830_allocate_agp_memory(ScrnInfoPtr pScrn, i830_memory *mem, int flags)
return TRUE;
}
-#ifdef XF86DRI_MM
+#ifdef XF86DRI
static i830_memory *
i830_allocate_memory_bo(ScrnInfoPtr pScrn, const char *name,
unsigned long size, unsigned long align, int flags)
{
I830Ptr pI830 = I830PTR(pScrn);
i830_memory *mem;
- unsigned long mask;
- int ret;
assert((flags & NEED_PHYSICAL_ADDR) == 0);
@@ -745,37 +735,27 @@ 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.
- */
+ mem->bo = dri_bo_alloc (pI830->bufmgr, name, size, align);
- 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);
- if (ret) {
+ if (!mem->bo) {
xfree(mem->name);
xfree(mem);
return NULL;
}
+
/* Give buffer obviously wrong offset/end until it's pinned. */
mem->offset = -1;
mem->end = -1;
mem->size = size;
mem->allocated_size = size;
+ mem->alignment = align;
if (flags & NEED_LIFETIME_FIXED)
mem->lifetime_fixed_offset = TRUE;
/* Bind it if we currently control the VT */
if (pScrn->vtSema) {
if (!i830_bind_memory(pScrn, mem)) {
- drmBOUnreference(pI830->drmSubFD, &mem->bo);
+ dri_bo_unreference (mem->bo);
xfree(mem->name);
xfree(mem);
return NULL;
@@ -791,7 +771,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.
*
@@ -817,7 +797,7 @@ i830_allocate_memory(ScrnInfoPtr pScrn, const char *name,
{
i830_memory *mem;
-#ifdef XF86DRI_MM
+#ifdef XF86DRI
I830Ptr pI830 = I830PTR(pScrn);
if (pI830->memory_manager && !(flags & NEED_PHYSICAL_ADDR) &&
@@ -825,7 +805,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)
@@ -902,6 +882,30 @@ i830_allocate_memory_tiled(ScrnInfoPtr pScrn, const char *name,
mem->pitch = pitch;
mem->fence_nr = -1;
+#ifdef XF86DRI
+ if (mem->bo != 0) {
+ uint32_t tiling_mode = I915_TILING_NONE;
+ int ret;
+
+ if (tile_format == TILE_XMAJOR)
+ tiling_mode = I915_TILING_X;
+ else
+ tiling_mode = I915_TILING_Y;
+
+ 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,
+ ret == 0 ? "rejected by kernel" : strerror(errno));
+ i830_free_memory(pScrn, mem);
+ return i830_allocate_memory(pScrn, name, size, alignment,
+ flags);
+ return FALSE;
+ }
+ }
+#endif
+
return mem;
}
@@ -955,7 +959,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);
@@ -985,7 +988,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
@@ -993,7 +995,7 @@ i830_allocate_ringbuffer(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
- if (pI830->noAccel || 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
@@ -1138,7 +1140,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) {
@@ -1169,7 +1171,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;
@@ -1184,7 +1186,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;
@@ -1372,8 +1374,18 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn)
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 */
- 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 =
@@ -1411,7 +1423,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).
@@ -1439,10 +1451,10 @@ 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 TTM anyway.
+ * end up being supported with GEM anyway.
*/
pI830->xaa_scratch =
i830_allocate_memory(pScrn, "xaa scratch", MAX_SCRATCH_BUFFER_SIZE,
@@ -1619,8 +1631,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,
@@ -1682,7 +1696,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;
}
@@ -1952,12 +1966,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);
@@ -1982,7 +1994,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.
@@ -1990,7 +2001,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/i830_render.c b/src/i830_render.c
index 3a959e82..c1ce856a 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, 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);
@@ -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, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
OUT_BATCH(MI_NOOP);
OUT_BATCH(_3DSTATE_DST_BUF_VARS_CMD);
@@ -735,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/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/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/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);
diff --git a/src/i915_render.c b/src/i915_render.c
index 4a02cf54..970c42ad 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, I915_GEM_DOMAIN_SAMPLER, 0, 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, I915_GEM_DOMAIN_SAMPLER, 0, 0);
OUT_BATCH(pI830->mapstate[1]);
OUT_BATCH(pI830->mapstate[2]);
- OUT_BATCH(pI830->mapstate[3]);
+ OUT_RELOC_PIXMAP(pMask, I915_GEM_DOMAIN_SAMPLER, 0, 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, 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 d2da94bb..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_BATCH(BUF_3D_ADDR(intel_get_pixmap_offset(pPixmap)));
+ OUT_RELOC_PIXMAP(pPixmap, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
ADVANCE_BATCH();
if (!planar) {
diff --git a/src/i965_render.c b/src/i965_render.c
index 8360be4a..391e0633 100644
--- a/src/i965_render.c
+++ b/src/i965_render.c
@@ -1431,26 +1431,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();
- }
-
- /* Mark sync so we can wait for it before setting up the VB on the next
- * rectangle.
- */
- i830MarkSync(pScrn);
}
/**
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
diff --git a/src/reg_dumper/Makefile.am b/src/reg_dumper/Makefile.am
index d49a59b1..11275814 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 intel_hotplug
+noinst_PROGRAMS = intel_reg_dumper intel_idle intel_stepping intel_statuspage intel_hotplug
intel_reg_dumper_SOURCES = \
main.c \
@@ -21,10 +21,16 @@ intel_hotplug_SOURCES = \
intel_stepping_SOURCES = \
stepping.c
+intel_statuspage_SOURCES = \
+ statuspage.c \
+ reg_dumper.h \
+ util.c
+
intel_hotplug_LDADD = $(PCIACCESS_LIBS)
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/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)
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 <eric@anholt.net>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <pciaccess.h>
+#include <err.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#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 <eric@anholt.net>
+ *
+ */
+
+/** @file util.c
+ *
+ * Utility functions for the various tools in the reg_dumper directory.
+ */
+
+#include <err.h>
+#include <pciaccess.h>
+
+#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;
+}
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
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..b25a8faa
--- /dev/null
+++ b/uxa/uxa-accel.c
@@ -0,0 +1,1032 @@
+/*
+ * 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 <eric@anholt.net>
+ * Michel Dänzer <michel@tungstengraphics.com>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+#include "uxa-priv.h"
+#include <X11/fonts/fontstruct.h>
+#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->prepare_solid) (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->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)
+{
+ 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->put_image)
+ 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->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.
+ */
+ if (!ok) {
+ FbStip *dst;
+ FbStride dst_stride;
+ int dstBpp;
+ int dstXoff, dstYoff;
+
+ if (!access_prepared) {
+ uxa_prepare_access(pDrawable, UXA_ACCESS_RW);
+ 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);
+
+ 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_ACCESS_RW);
+ fbCopyArea((DrawablePtr)pPixmap, pDrawable, pGC, sx, sy, sw, sh, dx, dy);
+ uxa_finish_access(pDrawable);
+
+ 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_ACCESS_RW);
+ fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy,
+ data);
+ uxa_finish_access(pDrawable);
+ }
+}
+
+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->done_copy(pDstPixmap);
+ dirsetup = -1;
+ if (!(*uxa_screen->info->prepare_copy)(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->done_copy(pDstPixmap);
+ dirsetup = 1;
+ if (!(*uxa_screen->info->prepare_copy)(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->done_copy(pDstPixmap);
+ dirsetup = 1;
+ if (!(*uxa_screen->info->prepare_copy)(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->done_copy(pDstPixmap);
+ dirsetup = -1;
+ if (!(*uxa_screen->info->prepare_copy)(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->done_copy(pDstPixmap);
+ 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->prepare_copy) (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->done_copy) (pDstPixmap);
+
+ 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_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_finish_access (pDstDrawable);
+}
+
+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);
+ if (!prect)
+ return;
+ 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));
+ if (!prect)
+ return;
+ 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);
+ if (!prect)
+ return;
+ 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->prepare_solid) (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->done_solid) (pPixmap);
+
+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->prepare_solid) (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->done_solid) (pPixmap);
+
+ 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->prepare_copy) (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->done_copy) (pPixmap);
+
+ 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->get_image == 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->get_image(pPix, pDrawable->x + x + xoff,
+ pDrawable->y + y + yoff, w, h, d,
+ PixmapBytePad(w, pDrawable->depth));
+ if (ok)
+ return;
+
+fallback:
+ UXA_FALLBACK(("from %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+
+ uxa_prepare_access (pDrawable, UXA_ACCESS_RO);
+ fbGetImage (pDrawable, x, y, w, h, format, planeMask, d);
+ uxa_finish_access (pDrawable);
+
+ return;
+}
diff --git a/uxa/uxa-glyphs.c b/uxa/uxa-glyphs.c
new file mode 100644
index 00000000..364fcfbc
--- /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 <otaylor@fishsoup.net>
+ * Based on code by: Keith Packard
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#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->put_image || 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->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;
+}
+
+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..c50ab3af
--- /dev/null
+++ b/uxa/uxa-priv.h
@@ -0,0 +1,443 @@
+/*
+ *
+ * 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 <dix-config.h>
+#else
+#include <xorg-server.h>
+#endif
+
+#include "uxa.h"
+
+#include <X11/X.h>
+#define NEED_EVENTS
+#include <X11/Xproto.h>
+#ifdef MITSHM
+#define _XSHM_SERVER_
+#include <X11/extensions/shmstr.h>
+#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 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, uxa_access_t access);
+
+void
+uxa_finish_access(DrawablePtr pDrawable);
+
+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..94e18a55
--- /dev/null
+++ b/uxa/uxa-render.c
@@ -0,0 +1,1015 @@
+/*
+ * 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 <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#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 (&region, 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, &region, dst_off_x, dst_off_y);
+
+ pixel = uxa_get_pixmap_first_pixel (pSrcPix);
+
+ if (!uxa_pixmap_is_offscreen(pDstPix)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 0;
+ }
+
+ if (!uxa_get_rgba_from_pixel(pixel, &red, &green, &blue, &alpha,
+ pSrc->format))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ if (!uxa_get_pixel_from_rgba(&pixel, red, green, blue, alpha,
+ pDst->format))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ if (!(*uxa_screen->info->prepare_solid) (pDstPix, GXcopy, 0xffffffff, pixel))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2);
+ pbox++;
+ }
+
+ (*uxa_screen->info->done_solid) (pDstPix);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ 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;
+
+ if (!uxa_screen->info->prepare_composite)
+ return -1;
+
+ if (uxa_screen->info->check_composite &&
+ !(*uxa_screen->info->check_composite) (op, pSrc, NULL, pDst))
+ {
+ return -1;
+ }
+
+ pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
+ if (!pDstPix)
+ return 0;
+
+ pSrcPix = uxa_get_offscreen_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y);
+ if (!pSrcPix)
+ return 0;
+
+ if (!(*uxa_screen->info->prepare_composite) (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 (&region, pSrc, NULL, pDst,
+ xSrc, ySrc, 0, 0, xDst, yDst,
+ rects->width, rects->height))
+ goto next_rect;
+
+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ 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, &region);
+
+ rects++;
+ }
+ (*uxa_screen->info->done_composite) (pDstPix);
+
+ 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;
+
+ 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->check_composite &&
+ !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst))
+ {
+ return -1;
+ }
+
+ if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
+ xSrc, ySrc, xMask, yMask, xDst, yDst,
+ width, height))
+ return 1;
+
+ 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, &region);
+ return 0;
+ }
+
+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
+ if (!(*uxa_screen->info->prepare_composite) (op, pSrc, pMask, pDst, pSrcPix,
+ pMaskPix, pDstPix))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ 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->done_composite) (pDstPix);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ 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->check_composite &&
+ (!(*uxa_screen->info->check_composite)(PictOpOutReverse, pSrc, pMask,
+ pDst) ||
+ !(*uxa_screen->info->check_composite)(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 (&region, 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(&region), REGION_NUM_RECTS(&region),
+ xSrc - xDst, ySrc - yDst,
+ FALSE, FALSE, 0, NULL);
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ 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->prepare_composite && !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 (&region, 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, &region,
+ (PixmapPtr)pSrc->pDrawable,
+ &patOrg, FB_ALLONES, GXcopy);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+
+ 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->prepare_composite &&
+ !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_ACCESS_RW);
+
+ for (; ntrap; ntrap--, traps++)
+ (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0);
+
+ uxa_finish_access(pDraw);
+ }
+ 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_ACCESS_RW);
+ for (; ntrap; ntrap--, traps++)
+ (*ps->RasterizeTrapezoid) (pPicture, traps,
+ -bounds.x1, -bounds.y1);
+ uxa_finish_access(pPicture->pDrawable);
+
+ 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_ACCESS_RW);
+ (*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
+ uxa_finish_access(pDraw);
+ }
+ 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_ACCESS_RW);
+ (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
+ uxa_finish_access(pPicture->pDrawable);
+
+ 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..01c13224
--- /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_ACCESS_RO);
+ if (pGC->fillStyle == FillTiled)
+ uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_ACCESS_RO);
+}
+
+/**
+ * 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);
+ if (pGC->stipple)
+ uxa_finish_access(&pGC->stipple->drawable);
+}
+
+#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_ACCESS_RW);
+ uxa_prepare_access_gc (pGC);
+ fbFillSpans (pDrawable, pGC, nspans, ppt, pwidth, fSorted);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable);
+}
+
+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_ACCESS_RW);
+ fbSetSpans (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+ uxa_finish_access (pDrawable);
+}
+
+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_ACCESS_RW);
+ fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
+ uxa_finish_access (pDrawable);
+}
+
+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_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_finish_access (pDst);
+
+ 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_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_finish_access (pDst);
+
+ 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_ACCESS_RW);
+ fbPolyPoint (pDrawable, pGC, mode, npt, pptInit);
+ uxa_finish_access (pDrawable);
+}
+
+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_ACCESS_RW);
+ uxa_prepare_access_gc (pGC);
+ fbPolyLine (pDrawable, pGC, mode, npt, ppt);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable);
+ 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_ACCESS_RW);
+ uxa_prepare_access_gc (pGC);
+ fbPolySegment (pDrawable, pGC, nsegInit, pSegInit);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable);
+ 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_ACCESS_RW);
+ uxa_prepare_access_gc (pGC);
+ fbPolyArc (pDrawable, pGC, narcs, pArcs);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable);
+ 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_ACCESS_RW);
+ uxa_prepare_access_gc (pGC);
+ fbPolyFillRect (pDrawable, pGC, nrect, prect);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable);
+}
+
+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_ACCESS_RW);
+ uxa_prepare_access_gc (pGC);
+ fbImageGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable);
+}
+
+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_ACCESS_RW);
+ uxa_prepare_access_gc (pGC);
+ fbPolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable);
+}
+
+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_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_finish_access (pDrawable);
+}
+
+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_ACCESS_RO);
+ fbGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+ uxa_finish_access (pDrawable);
+}
+
+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_ACCESS_RW);
+ if (pSrc->pDrawable != NULL)
+ uxa_prepare_access (pSrc->pDrawable, UXA_ACCESS_RO);
+ if (pMask && pMask->pDrawable != NULL)
+ uxa_prepare_access (pMask->pDrawable, UXA_ACCESS_RO);
+ fbComposite (op,
+ pSrc,
+ pMask,
+ pDst,
+ xSrc,
+ ySrc,
+ xMask,
+ yMask,
+ xDst,
+ yDst,
+ width,
+ height);
+ if (pMask && pMask->pDrawable != NULL)
+ uxa_finish_access (pMask->pDrawable);
+ if (pSrc->pDrawable != NULL)
+ uxa_finish_access (pSrc->pDrawable);
+ uxa_finish_access (pDst->pDrawable);
+}
+
+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_ACCESS_RW);
+ fbAddTraps (pPicture, x_off, y_off, ntrap, traps);
+ uxa_finish_access(pPicture->pDrawable);
+}
+
+/**
+ * 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_ACCESS_RO);
+ 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);
+
+ return pixel;
+}
diff --git a/uxa/uxa.c b/uxa/uxa.c
new file mode 100644
index 00000000..aac3d686
--- /dev/null
+++ b/uxa/uxa.c
@@ -0,0 +1,510 @@
+/*
+ * 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 <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "uxa-priv.h"
+#include <X11/fonts/fontstruct.h>
+#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->pixmap_is_offscreen)
+ return uxa_screen->info->pixmap_is_offscreen(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, uxa_access_t access)
+{
+ 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;
+
+ if (uxa_screen->info->prepare_access)
+ (*uxa_screen->info->prepare_access) (pPixmap, access);
+}
+
+/**
+ * uxa_finish_access() is UXA's wrapper for the driver's finish_access() handler.
+ *
+ * It deals with calling the driver's finish_access() only if necessary.
+ */
+void
+uxa_finish_access(DrawablePtr pDrawable)
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable);
+
+ if (uxa_screen->info->finish_access == NULL)
+ return;
+
+ if (!uxa_pixmap_is_offscreen (pPixmap))
+ return;
+
+ (*uxa_screen->info->finish_access) (pPixmap);
+}
+
+/**
+ * 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/finish_access.
+ */
+#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_ACCESS_RO);
+ pNewTile = fb24_32ReformatTile (pOldTile,
+ pDrawable->bitsPerPixel);
+ uxa_finish_access(&pOldTile->drawable);
+ }
+ 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_ACCESS_RW);
+ fbPadPixmap (pGC->tile.pixmap);
+ uxa_finish_access(&pGC->tile.pixmap->drawable);
+ }
+ /* 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_ACCESS_RO);
+
+ if (pWin->borderIsPixel == FALSE)
+ 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);
+
+ if (pWin->borderIsPixel == FALSE)
+ uxa_finish_access(&pWin->border.pixmap->drawable);
+}
+
+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_ACCESS_RO);
+ ret = fbPixmapToRegion(pPix);
+ uxa_finish_access(&pPix->drawable);
+ 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->prepare_solid) {
+ LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::prepare_solid must be "
+ "non-NULL\n", screen->myNum);
+ return FALSE;
+ }
+
+ if (!uxa_driver->prepare_copy) {
+ LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::prepare_copy must be "
+ "non-NULL\n", screen->myNum);
+ return FALSE;
+ }
+
+#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->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->put_image != NULL) {
+ LogMessage(X_INFO, " put_image\n");
+ }
+ if (uxa_driver->get_image != NULL) {
+ LogMessage(X_INFO, " get_image\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*/
+}
diff --git a/uxa/uxa.h b/uxa/uxa.h
new file mode 100644
index 00000000..f1c1cfa9
--- /dev/null
+++ b/uxa/uxa.h
@@ -0,0 +1,528 @@
+/*
+ * 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
+
+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.
+ */
+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;
+
+ /** @name solid
+ * @{
+ */
+ /**
+ * 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*
+ * 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 prepare_solid() call is required of all drivers, but it may fail for any
+ * reason. Failure results in a fallback to software rendering.
+ */
+ Bool (*prepare_solid) (PixmapPtr pPixmap,
+ int alu,
+ Pixel planemask,
+ Pixel fg);
+
+ /**
+ * solid() performs a solid fill set up in the last prepare_solid() 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 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 prepare_solid() ever succeeds.
+ */
+ void (*solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2);
+
+ /**
+ * done_solid() finishes a set of solid fills.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * 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 prepare_solid().
+ *
+ * This call is required if prepare_solid() ever succeeds.
+ */
+ void (*done_solid) (PixmapPtr pPixmap);
+ /** @} */
+
+ /** @name copy
+ * @{
+ */
+ /**
+ * prepare_copy() 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 prepare_copy() call is required of all drivers, but it may fail for any
+ * reason. Failure results in a fallback to software rendering.
+ */
+ Bool (*prepare_copy) (PixmapPtr pSrcPixmap,
+ PixmapPtr pDstPixmap,
+ int dx,
+ int dy,
+ int alu,
+ Pixel planemask);
+
+ /**
+ * copy() performs a copy set up in the last prepare_copy 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 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 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 prepare_copy ever succeeds.
+ */
+ void (*copy) (PixmapPtr pDstPixmap,
+ int srcX,
+ int srcY,
+ int dstX,
+ int dstY,
+ int width,
+ int height);
+
+ /**
+ * done_copy() finishes a set of copies.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * 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 prepare_copy().
+ *
+ * This call is required if prepare_copy() ever succeeds.
+ */
+ void (*done_copy) (PixmapPtr pDstPixmap);
+ /** @} */
+
+ /** @name composite
+ * @{
+ */
+ /**
+ * check_composite() 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 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 prepare_composite() for more details on likely issues that drivers
+ * will have in accelerating composite operations.
+ *
+ * The check_composite() call is recommended if prepare_composite() is
+ * implemented, but is not required.
+ */
+ Bool (*check_composite) (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture);
+
+ /**
+ * prepare_composite() 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
+ * 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
+ * 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 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 (*prepare_composite) (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ PixmapPtr pSrc,
+ PixmapPtr pMask,
+ PixmapPtr pDst);
+
+ /**
+ * composite() performs a composite operation set up in the last
+ * prepare_composite() 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 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
+ * 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 prepare_composite() ever succeeds.
+ */
+ void (*composite) (PixmapPtr pDst,
+ int srcX,
+ int srcY,
+ int maskX,
+ int maskY,
+ int dstX,
+ int dstY,
+ int width,
+ int height);
+
+ /**
+ * done_composite() finishes a set of composite operations.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * 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 prepare_composite().
+ *
+ * This call is required if prepare_composite() ever succeeds.
+ */
+ void (*done_composite) (PixmapPtr pDst);
+ /** @} */
+
+ /**
+ * put_image() 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * put_image() is not required, but is recommended if composite
+ * acceleration is supported.
+ */
+ Bool (*put_image) (PixmapPtr pDst,
+ int x,
+ int y,
+ int w,
+ int h,
+ char *src,
+ int src_pitch);
+
+ /**
+ * get_image() 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.
+ *
+ * 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 get_image() was asynchronous. This is in
+ * contrast to most other acceleration calls in UXA.
+ *
+ * @return TRUE if the driver successfully downloaded the data. FALSE
+ * indicates that UXA should fall back to doing the download in software.
+ *
+ * get_image() is not required, but is highly recommended.
+ */
+ Bool (*get_image)(PixmapPtr pSrc,
+ int x, int y,
+ int w, int h,
+ char *dst, int dst_pitch);
+
+ /** @{ */
+ /**
+ * 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.
+ *
+ * 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 prepare_access() called on them per operation,
+ * drivers can have a small, statically-allocated space to maintain state
+ * 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).
+ *
+ * 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.
+ * 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 prepare_access() successfully prepared the pixmap for CPU
+ * drawing.
+ * @return FALSE if prepare_access() is unsuccessful and UXA should use
+ * get_image() to migate the pixmap out.
+ */
+ Bool (*prepare_access)(PixmapPtr pPix, uxa_access_t access);
+
+ /**
+ * 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.
+ *
+ * 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 (*finish_access)(PixmapPtr pPix);
+
+ /**
+ * 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 prepare_access()/finish_access() when accessing it
+ * with the CPU.
+ *
+ *
+ */
+ Bool (*pixmap_is_offscreen)(PixmapPtr pPix);
+
+ /** @} */
+} 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);
+
+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 */