diff options
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) @@ -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 (®ion, pSrc, NULL, pDst, + xSrc, ySrc, 0, 0, xDst, yDst, + width, height)) + return 1; + + uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); + + REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + + pixel = uxa_get_pixmap_first_pixel (pSrcPix); + + if (!uxa_pixmap_is_offscreen(pDstPix)) { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 0; + } + + if (!uxa_get_rgba_from_pixel(pixel, &red, &green, &blue, &alpha, + pSrc->format)) + { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return -1; + } + + if (!uxa_get_pixel_from_rgba(&pixel, red, green, blue, alpha, + pDst->format)) + { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return -1; + } + + if (!(*uxa_screen->info->prepare_solid) (pDstPix, GXcopy, 0xffffffff, pixel)) + { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return -1; + } + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + while (nbox--) + { + (*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2); + pbox++; + } + + (*uxa_screen->info->done_solid) (pDstPix); + + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 1; +} + +static int +uxa_try_driver_composite_rects(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + int nrect, + uxa_composite_rect_t *rects) +{ + uxa_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 (®ion, pSrc, NULL, pDst, + xSrc, ySrc, 0, 0, xDst, yDst, + rects->width, rects->height)) + goto next_rect; + + REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + xSrc = xSrc + src_off_x - xDst - dst_off_x; + ySrc = ySrc + src_off_y - yDst - dst_off_y; + + while (nbox--) + { + (*uxa_screen->info->composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + 0, 0, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + + next_rect: + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + rects++; + } + (*uxa_screen->info->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 (®ion, 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, ®ion); + return 0; + } + + REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + + if (!(*uxa_screen->info->prepare_composite) (op, pSrc, pMask, pDst, pSrcPix, + pMaskPix, pDstPix)) + { + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return -1; + } + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + xMask = xMask + mask_off_x - xDst - dst_off_x; + yMask = yMask + mask_off_y - yDst - dst_off_y; + + xSrc = xSrc + src_off_x - xDst - dst_off_x; + ySrc = ySrc + src_off_y - yDst - dst_off_y; + + while (nbox--) + { + (*uxa_screen->info->composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + pbox->x1 + xMask, + pbox->y1 + yMask, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + (*uxa_screen->info->done_composite) (pDstPix); + + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + return 1; +} + +/** + * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of + * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component + * alpha and limited 1-tmu cards. + * + * From http://anholt.livejournal.com/32058.html: + * + * The trouble is that component-alpha rendering requires two different sources + * for blending: one for the source value to the blender, which is the + * per-channel multiplication of source and mask, and one for the source alpha + * for multiplying with the destination channels, which is the multiplication + * of the source channels by the mask alpha. So the equation for Over is: + * + * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A + * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R + * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G + * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B + * + * But we can do some simpler operations, right? How about PictOpOutReverse, + * which has a source factor of 0 and dest factor of (1 - source alpha). We + * can get the source alpha value (srca.X = src.A * mask.X) out of the texture + * blenders pretty easily. So we can do a component-alpha OutReverse, which + * gets us: + * + * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A + * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R + * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G + * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B + * + * OK. And if an op doesn't use the source alpha value for the destination + * factor, then we can do the channel multiplication in the texture blenders + * to get the source value, and ignore the source alpha that we wouldn't use. + * We've supported this in the Radeon driver for a long time. An example would + * be PictOpAdd, which does: + * + * dst.A = src.A * mask.A + dst.A + * dst.R = src.R * mask.R + dst.R + * dst.G = src.G * mask.G + dst.G + * dst.B = src.B * mask.B + dst.B + * + * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right + * after it, we get: + * + * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) + * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) + * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) + * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) + */ + +static int +uxa_try_magic_two_pass_composite_helper(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + + assert(op == PictOpOver); + + if (uxa_screen->info->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 (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, + yDst, width, height)) + goto done; + + + uxa_copy_n_to_n (pSrc->pDrawable, pDst->pDrawable, NULL, + REGION_RECTS(®ion), REGION_NUM_RECTS(®ion), + xSrc - xDst, ySrc - yDst, + FALSE, FALSE, 0, NULL); + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + goto done; + } + else if (pSrc->pDrawable != NULL && + pSrc->pDrawable->type == DRAWABLE_PIXMAP && + !pSrc->transform && + pSrc->repeatType == RepeatNormal) + { + DDXPointRec patOrg; + + /* Let's see if the driver can do the repeat in one go */ + if (uxa_screen->info->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 (®ion, pSrc, pMask, pDst, xSrc, + ySrc, xMask, yMask, xDst, yDst, + width, height)) + goto done; + + /* pattern origin is the point in the destination drawable + * corresponding to (0,0) in the source */ + patOrg.x = xDst - xSrc; + patOrg.y = yDst - ySrc; + + ret = uxa_fill_region_tiled(pDst->pDrawable, ®ion, + (PixmapPtr)pSrc->pDrawable, + &patOrg, FB_ALLONES, GXcopy); + + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + if (ret) + goto done; + } + } + } + + /* Remove repeat in mask if useless */ + if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 && + (xMask + width) <= pMask->pDrawable->width && yMask >= 0 && + (yMask + height) <= pMask->pDrawable->height) + pMask->repeat = 0; + + if (uxa_screen->info->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 */ |