diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-08-25 12:56:43 +0100 |
---|---|---|
committer | Owain G. Ainsworth <oga@openbsd.org> | 2010-09-12 04:52:11 +0100 |
commit | 56f3afcc7b7b11b7eeabe197176a74892449221d (patch) | |
tree | 630c02bdcb8958e9f7b09e66603429342a561f4d /src/intel_uxa.c | |
parent | de486ee8e4295d5d827692b26c5c12b7a26c9d01 (diff) |
Enable a shadow buffer and disable GPU acceleration.
An attempt to workaround the incoherency in gen2 chipsets, we avoid
using dynamic reallocation as much as possible.
The first step is to disable allocation of pixmaps using GEM and simply
create them in system memory without a backing buffer object. This
forces all rendering to use S/W fallbacks.
The second step is to allocate a shadow front buffer and assign that to
the Screen pixmap. This ensure that the front buffer remains in the GTT
and pinned for scanout. The shadow buffer will be rendered to in the
normal fashion via the Screen pixmap, and be marked dirty. In the block
handler, the dirty shadow buffer is then blitted (using the GPU) over
the front buffer. This should completely avoid having to move pages
around in the GTT and avoid incurring the wrath of those early chipsets.
Secondly, performance should be reasonable as we avoid the ping-pong
caused by the small aperture and weak GPU forcing software fallbacks.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Owain G. Ainsworth <oga@openbsd.org>
(cherry-picked from commit 2b96c18165d713cd6781dbf217ec33e11cc961bc)
Also pulled in the following commit:
commit ae160d7fbfc79e78dad8702efcc55d9c0c25ff67
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date: Fri Sep 10 13:19:12 2010 +0100
shadow: Simply modify the Screen pixmap header
This is a slightly less risky strategy than having to remember to update
all pointers to the old Screen pixmap.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/intel_uxa.c')
-rw-r--r-- | src/intel_uxa.c | 216 |
1 files changed, 202 insertions, 14 deletions
diff --git a/src/intel_uxa.c b/src/intel_uxa.c index 4f7ab3f9..aed5d548 100644 --- a/src/intel_uxa.c +++ b/src/intel_uxa.c @@ -675,9 +675,6 @@ static void intel_uxa_finish_access(PixmapPtr pixmap) struct intel_pixmap *priv = intel_get_pixmap_private(pixmap); dri_bo *bo = priv->bo; - if (bo == intel->front_buffer) - intel->need_sync = TRUE; - if (priv->tiling || bo->size <= intel->max_gtt_map_size) drm_intel_gem_bo_unmap_gtt(bo); else @@ -879,14 +876,196 @@ static Bool intel_uxa_get_image(PixmapPtr pixmap, scratch->drawable.pScreen->DestroyPixmap(scratch); return ret; +} + +static dri_bo * +intel_shadow_create_bo(intel_screen_private *intel, + int16_t x1, int16_t y1, + int16_t x2, int16_t y2, + int *pitch) +{ + int w = x2 - x1, h = y2 - y1; + int size = h * w * intel->cpp; + dri_bo *bo; + + bo = drm_intel_bo_alloc(intel->bufmgr, "shadow", size, 0); + if (bo && drm_intel_gem_bo_map_gtt(bo) == 0) { + char *dst = bo->virtual; + char *src = intel->shadow_buffer; + int src_pitch = intel->shadow_stride; + int row_length = w * intel->cpp; + int num_rows = h; + src += y1 * src_pitch + x1 * intel->cpp; + do { + memcpy (dst, src, row_length); + src += src_pitch; + dst += row_length; + } while (--num_rows); + drm_intel_gem_bo_unmap_gtt(bo); + } + + *pitch = w * intel->cpp; + return bo; +} + +static void +intel_shadow_blt(intel_screen_private *intel) +{ + ScrnInfoPtr scrn = intel->scrn; + unsigned int dst_pitch; + uint32_t blt, br13; + RegionPtr region; + BoxPtr box; + int n; + + dst_pitch = intel->front_pitch; + + blt = XY_SRC_COPY_BLT_CMD; + if (intel->cpp == 4) + blt |= (XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + + if (IS_I965G(intel)) { + if (intel->front_tiling) { + dst_pitch >>= 2; + blt |= XY_SRC_COPY_BLT_DST_TILED; + } + } + + br13 = ROP_S << 16 | dst_pitch; + switch (intel->cpp) { + default: + case 4: br13 |= 1 << 25; /* RGB8888 */ + case 2: br13 |= 1 << 24; /* RGB565 */ + case 1: break; + } + + region = DamageRegion(intel->shadow_damage); + box = REGION_RECTS(region); + n = REGION_NUM_RECTS(region); + while (n--) { + int pitch; + dri_bo *bo; + int offset; + + if (IS_I8XX(intel)) { + bo = intel->shadow_buffer; + offset = box->x1 | box->y1 << 16; + pitch = intel->shadow_stride; + } else { + bo = intel_shadow_create_bo(intel, + box->x1, box->y1, + box->x2, box->y2, + &pitch); + if (bo == NULL) + return; + + offset = 0; + } + + BEGIN_BATCH(8); + OUT_BATCH(blt); + OUT_BATCH(br13); + OUT_BATCH(box->y1 << 16 | box->x1); + OUT_BATCH(box->y2 << 16 | box->x2); + OUT_RELOC_FENCED(intel->front_buffer, + I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER, + 0); + OUT_BATCH(offset); + OUT_BATCH(pitch); + OUT_RELOC(bo, I915_GEM_DOMAIN_RENDER, 0, 0); + + ADVANCE_BATCH(); + + if (bo != intel->shadow_buffer) + drm_intel_bo_unreference(bo); + box++; + } +} + +static void intel_shadow_create(struct intel_screen_private *intel) +{ + ScrnInfoPtr scrn = intel->scrn; + ScreenPtr screen = scrn->pScreen; + PixmapPtr pixmap; + int stride; + + pixmap = screen->GetScreenPixmap(screen); + if (IS_I8XX(intel)) { + dri_bo *bo; + int size; + + /* Reduce the incoherency worries for gen2 + * by only allocating a static shadow, at about 2-3x + * performance cost for forcing rendering to uncached memory. + */ + if (intel->shadow_buffer) { + drm_intel_gem_bo_unmap_gtt(intel->shadow_buffer); + drm_intel_bo_unreference(intel->shadow_buffer); + intel->shadow_buffer = NULL; + } + + stride = ALIGN(scrn->virtualX * intel->cpp, 4); + size = stride * scrn->virtualY; + bo = drm_intel_bo_alloc(intel->bufmgr, + "shadow", size, + 0); + if (bo && drm_intel_gem_bo_map_gtt(bo) == 0) { + screen->ModifyPixmapHeader(pixmap, + scrn->virtualX, + scrn->virtualY, + -1, -1, + stride, + bo->virtual); + intel->shadow_buffer = bo; + } + } else { + void *buffer; + + stride = intel->cpp*scrn->virtualX; + buffer = malloc(stride * scrn->virtualY); + + if (buffer && screen->ModifyPixmapHeader(pixmap, + scrn->virtualX, + scrn->virtualY, + -1, -1, + stride, + buffer)) { + if (intel->shadow_buffer) + free(intel->shadow_buffer); + + intel->shadow_buffer = buffer; + } else + stride = intel->shadow_stride; + } + if (!intel->shadow_damage) { + intel->shadow_damage = DamageCreate(NULL, NULL, + DamageReportNone, + TRUE, + screen, + intel); + DamageRegister(&pixmap->drawable, intel->shadow_damage); + DamageSetReportAfterOp(intel->shadow_damage, TRUE); + } + + scrn->displayWidth = stride / intel->cpp; + intel->shadow_stride = stride; } void intel_uxa_block_handler(intel_screen_private *intel) { - if (intel->need_sync) { - dri_bo_wait_rendering(intel->front_buffer); - intel->need_sync = FALSE; + if (intel->shadow_damage && + pixman_region_not_empty(DamageRegion(intel->shadow_damage))) { + intel_shadow_blt(intel); + /* Emit a flush of the rendering cache, or on the 965 + * and beyond rendering results may not hit the + * framebuffer until significantly later. + */ + intel_batch_submit(intel->scrn, TRUE); + + DamageEmpty(intel->shadow_damage); } } @@ -1034,17 +1213,27 @@ static Bool intel_uxa_destroy_pixmap(PixmapPtr pixmap) return TRUE; } - void intel_uxa_create_screen_resources(ScreenPtr screen) { ScrnInfoPtr scrn = xf86Screens[screen->myNum]; intel_screen_private *intel = intel_get_screen_private(scrn); - dri_bo *bo = intel->front_buffer; - if (bo != NULL) { - PixmapPtr pixmap = screen->GetScreenPixmap(screen); - intel_set_pixmap_bo(pixmap, bo); - intel_get_pixmap_private(pixmap)->busy = 1; + if (intel->use_shadow) { + intel_shadow_create(intel); + } else { + dri_bo *bo = intel->front_buffer; + if (bo != NULL) { + PixmapPtr pixmap = screen->GetScreenPixmap(screen); + intel_set_pixmap_bo(pixmap, bo); + intel_get_pixmap_private(pixmap)->busy = 1; + screen->ModifyPixmapHeader(pixmap, + scrn->virtualX, + scrn->virtualY, + -1, -1, + intel->front_pitch, + NULL); + } + scrn->displayWidth = intel->front_pitch / intel->cpp; } } @@ -1120,8 +1309,6 @@ Bool intel_uxa_init(ScreenPtr screen) memset(intel->uxa_driver, 0, sizeof(*intel->uxa_driver)); - intel->force_fallback = FALSE; - intel->bufferOffset = 0; intel->uxa_driver->uxa_major = 1; intel->uxa_driver->uxa_minor = 0; @@ -1195,6 +1382,7 @@ Bool intel_uxa_init(ScreenPtr screen) } uxa_set_fallback_debug(screen, intel->fallback_debug); + uxa_set_force_fallback(screen, intel->force_fallback); return TRUE; } |