From f30d53e0498a558100a1b9d9651ff375a7b3c7b4 Mon Sep 17 00:00:00 2001 From: Nicolai Haehnle Date: Tue, 28 Sep 2004 10:59:23 +0000 Subject: Initial revision --- src/mesa/drivers/dri/r300/radeon_ioctl.c | 348 +++++++++++++++++++++++++++++++ 1 file changed, 348 insertions(+) create mode 100644 src/mesa/drivers/dri/r300/radeon_ioctl.c (limited to 'src/mesa/drivers/dri/r300/radeon_ioctl.c') diff --git a/src/mesa/drivers/dri/r300/radeon_ioctl.c b/src/mesa/drivers/dri/r300/radeon_ioctl.c new file mode 100644 index 0000000000..0caf44569d --- /dev/null +++ b/src/mesa/drivers/dri/r300/radeon_ioctl.c @@ -0,0 +1,348 @@ +/* +Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. + +The Weather Channel (TM) funded Tungsten Graphics to develop the +initial release of the Radeon 8500 driver under the XFree86 license. +This notice must be preserved. + +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 COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell + */ + +#include +#include + +#include "glheader.h" +#include "imports.h" +#include "macros.h" +#include "context.h" +#include "swrast/swrast.h" + +#include "r200_context.h" +#include "r200_state.h" +#include "radeon_ioctl.h" +#include "r200_ioctl.h" +#include "r300_ioctl.h" +#include "r200_tcl.h" +#include "r200_sanity.h" +#include "radeon_reg.h" + +#include "vblank.h" + +static void radeonWaitForIdle(radeonContextPtr radeon); + +/* ================================================================ + * SwapBuffers with client-side throttling + */ + +static uint32_t radeonGetLastFrame(radeonContextPtr radeon) +{ + drm_radeon_getparam_t gp; + int ret; + uint32_t frame; + + gp.param = RADEON_PARAM_LAST_FRAME; + gp.value = (int *)&frame; + ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_GETPARAM, + &gp, sizeof(gp)); + if (ret) { + fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, + ret); + exit(1); + } + + return frame; +} + +static void radeonEmitIrqLocked(radeonContextPtr radeon) +{ + drm_radeon_irq_emit_t ie; + int ret; + + ie.irq_seq = &radeon->iw.irq_seq; + ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_IRQ_EMIT, + &ie, sizeof(ie)); + if (ret) { + fprintf(stderr, "%s: drmRadeonIrqEmit: %d\n", __FUNCTION__, + ret); + exit(1); + } +} + +static void radeonWaitIrq(radeonContextPtr radeon) +{ + int ret; + + do { + ret = drmCommandWrite(radeon->dri.fd, DRM_RADEON_IRQ_WAIT, + &radeon->iw, sizeof(radeon->iw)); + } while (ret && (errno == EINTR || errno == EAGAIN)); + + if (ret) { + fprintf(stderr, "%s: drmRadeonIrqWait: %d\n", __FUNCTION__, + ret); + exit(1); + } +} + +static void radeonWaitForFrameCompletion(radeonContextPtr radeon) +{ + drm_radeon_sarea_t *sarea = radeon->sarea; + + if (radeon->do_irqs) { + if (radeonGetLastFrame(radeon) < sarea->last_frame) { + if (!radeon->irqsEmitted) { + while (radeonGetLastFrame(radeon) < + sarea->last_frame) ; + } else { + UNLOCK_HARDWARE(radeon); + radeonWaitIrq(radeon); + LOCK_HARDWARE(radeon); + } + radeon->irqsEmitted = 10; + } + + if (radeon->irqsEmitted) { + radeonEmitIrqLocked(radeon); + radeon->irqsEmitted--; + } + } else { + while (radeonGetLastFrame(radeon) < sarea->last_frame) { + UNLOCK_HARDWARE(radeon); + if (radeon->do_usleeps) + DO_USLEEP(1); + LOCK_HARDWARE(radeon); + } + } +} + +/* Copy the back color buffer to the front color buffer. + */ +void radeonCopyBuffer(const __DRIdrawablePrivate * dPriv) +{ + radeonContextPtr radeon; + GLint nbox, i, ret; + GLboolean missed_target; + int64_t ust; + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate; + + if (RADEON_DEBUG & DEBUG_IOCTL) { + fprintf(stderr, "\n%s( %p )\n\n", __FUNCTION__, + (void *)radeon->glCtx); + } + + if (IS_FAMILY_R200(radeon)) + R200_FIREVERTICES((r200ContextPtr)radeon); + + LOCK_HARDWARE(radeon); + + /* Throttle the frame rate -- only allow one pending swap buffers + * request at a time. + */ + radeonWaitForFrameCompletion(radeon); + UNLOCK_HARDWARE(radeon); + driWaitForVBlank(dPriv, &radeon->vbl_seq, radeon->vblank_flags, + &missed_target); + LOCK_HARDWARE(radeon); + + nbox = dPriv->numClipRects; /* must be in locked region */ + + for (i = 0; i < nbox;) { + GLint nr = MIN2(i + RADEON_NR_SAREA_CLIPRECTS, nbox); + drm_clip_rect_t *box = dPriv->pClipRects; + drm_clip_rect_t *b = radeon->sarea->boxes; + GLint n = 0; + + for (; i < nr; i++) { + *b++ = box[i]; + n++; + } + radeon->sarea->nbox = n; + + ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_SWAP); + + if (ret) { + fprintf(stderr, "DRM_R200_SWAP_BUFFERS: return = %d\n", + ret); + UNLOCK_HARDWARE(radeon); + exit(1); + } + } + + UNLOCK_HARDWARE(radeon); + + if (IS_FAMILY_R200(radeon)) + ((r200ContextPtr)radeon)->hw.all_dirty = GL_TRUE; + + radeon->swap_count++; + (*radeon->get_ust) (&ust); + if (missed_target) { + radeon->swap_missed_count++; + radeon->swap_missed_ust = ust - radeon->swap_ust; + } + + radeon->swap_ust = ust; + + sched_yield(); +} + +void radeonPageFlip(const __DRIdrawablePrivate * dPriv) +{ + radeonContextPtr radeon; + GLint ret; + GLboolean missed_target; + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate; + + if (RADEON_DEBUG & DEBUG_IOCTL) { + fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__, + radeon->sarea->pfCurrentPage); + } + + if (IS_FAMILY_R200(radeon)) + R200_FIREVERTICES((r200ContextPtr)radeon); + LOCK_HARDWARE(radeon); + + if (!dPriv->numClipRects) { + UNLOCK_HARDWARE(radeon); + usleep(10000); /* throttle invisible client 10ms */ + return; + } + + /* Need to do this for the perf box placement: + */ + { + drm_clip_rect_t *box = dPriv->pClipRects; + drm_clip_rect_t *b = radeon->sarea->boxes; + b[0] = box[0]; + radeon->sarea->nbox = 1; + } + + /* Throttle the frame rate -- only allow a few pending swap buffers + * request at a time. + */ + radeonWaitForFrameCompletion(radeon); + UNLOCK_HARDWARE(radeon); + driWaitForVBlank(dPriv, &radeon->vbl_seq, radeon->vblank_flags, + &missed_target); + if (missed_target) { + radeon->swap_missed_count++; + (void)(*radeon->get_ust) (&radeon->swap_missed_ust); + } + LOCK_HARDWARE(radeon); + + ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_FLIP); + + UNLOCK_HARDWARE(radeon); + + if (ret) { + fprintf(stderr, "DRM_RADEON_FLIP: return = %d\n", ret); + exit(1); + } + + radeon->swap_count++; + (void)(*radeon->get_ust) (&radeon->swap_ust); + + if (radeon->sarea->pfCurrentPage == 1) { + radeon->state.color.drawOffset = radeon->radeonScreen->frontOffset; + radeon->state.color.drawPitch = radeon->radeonScreen->frontPitch; + } else { + radeon->state.color.drawOffset = radeon->radeonScreen->backOffset; + radeon->state.color.drawPitch = radeon->radeonScreen->backPitch; + } + + if (IS_FAMILY_R200(radeon)) { + r200ContextPtr r200 = (r200ContextPtr)radeon; + + R200_STATECHANGE(r200, ctx); + r200->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = radeon->state.color.drawOffset + + radeon->radeonScreen->fbLocation; + r200->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = radeon->state.color.drawPitch; + } +} + +void radeonWaitForIdleLocked(radeonContextPtr radeon) +{ + int ret; + int i = 0; + + do { + ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_CP_IDLE); + if (ret) + DO_USLEEP(1); + } while (ret && ++i < 100); + + if (ret < 0) { + UNLOCK_HARDWARE(radeon); + fprintf(stderr, "Error: R200 timed out... exiting\n"); + exit(-1); + } +} + +static void radeonWaitForIdle(radeonContextPtr radeon) +{ + LOCK_HARDWARE(radeon); + radeonWaitForIdleLocked(radeon); + UNLOCK_HARDWARE(radeon); +} + +void radeonFlush(GLcontext * ctx) +{ + radeonContextPtr radeon = RADEON_CONTEXT(ctx); + + if (IS_FAMILY_R300(radeon)) + r300Flush(ctx); + else + r200Flush(ctx); +} + + +/* Make sure all commands have been sent to the hardware and have + * completed processing. + */ +void radeonFinish(GLcontext * ctx) +{ + radeonContextPtr radeon = RADEON_CONTEXT(ctx); + + radeonFlush(ctx); + + if (radeon->do_irqs) { + LOCK_HARDWARE(radeon); + radeonEmitIrqLocked(radeon); + UNLOCK_HARDWARE(radeon); + radeonWaitIrq(radeon); + } else + radeonWaitForIdle(radeon); +} -- cgit v1.2.3