diff options
author | Eric Anholt <anholt@FreeBSD.org> | 2004-09-22 06:27:02 +0000 |
---|---|---|
committer | Eric Anholt <anholt@FreeBSD.org> | 2004-09-22 06:27:02 +0000 |
commit | 0c8f8d3dc9d60ed34eeca7f3606651420a81753c (patch) | |
tree | 3876839944c4194d4eac39863e96b64c4cfd7683 /src/mesa/drivers/dri/r200/r200_ioctl.c | |
parent | 029ee9c680cd097b82d3d301b3854d57993d4464 (diff) |
The previous code would emit a full set of state during the first EmitState on
a new cmdbuf, to ensure that state wasn't lost across UNLOCK/LOCK pairs (in the
case of context switching). This was rather inefficient. Instead, after
flushing a cmdbuf, mark the state as needing to be saved on UNLOCK. Then, at
the beginning of flushing a cmdbuf, if we actually have lost the context, go
back and emit a new cmdbuf with the full set of state, before continuing with
the cmdbuf flush. Also, remove the dirty/clean atom lists, since atoms are
emitted in a fixed order these days, and go with a simpler single list.
Provides a 14% improvement in ipers performance in my tests, along with other
apps.
Diffstat (limited to 'src/mesa/drivers/dri/r200/r200_ioctl.c')
-rw-r--r-- | src/mesa/drivers/dri/r200/r200_ioctl.c | 86 |
1 files changed, 63 insertions, 23 deletions
diff --git a/src/mesa/drivers/dri/r200/r200_ioctl.c b/src/mesa/drivers/dri/r200/r200_ioctl.c index fb462e0850..955afb0d5f 100644 --- a/src/mesa/drivers/dri/r200/r200_ioctl.c +++ b/src/mesa/drivers/dri/r200/r200_ioctl.c @@ -58,12 +58,71 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. static void r200WaitForIdle( r200ContextPtr rmesa ); +void r200SaveHwState( r200ContextPtr rmesa ) +{ + struct r200_state_atom *atom; + + foreach( atom, &rmesa->hw.atomlist ) + memcpy(atom->savedcmd, atom->cmd, atom->cmd_size * 4); +} + +static void r200SwapHwState( r200ContextPtr rmesa ) +{ + int *temp; + struct r200_state_atom *atom; + + foreach( atom, &rmesa->hw.atomlist ) { + temp = atom->cmd; + atom->cmd = atom->savedcmd; + atom->savedcmd = temp; + } +} + +/* At this point we were in FlushCmdBufLocked but we had lost our context, so + * we need to unwire our current cmdbuf and hook a new one in, emit that, then + * wire the old cmdbuf back in so that FlushCmdBufLocked can continue and the + * buffer can depend on the state not being lost across lock/unlock. + */ +static void r200BackUpAndEmitLostStateLocked( r200ContextPtr rmesa ) +{ + GLuint nr_released_bufs; + struct r200_store store; + struct r200_hw_state temp_state; + static int count = 0; + + rmesa->lost_context = GL_FALSE; + + nr_released_bufs = rmesa->dma.nr_released_bufs; + store = rmesa->store; + rmesa->store.statenr = 0; + rmesa->store.primnr = 0; + rmesa->store.cmd_used = 0; + rmesa->store.elts_start = 0; + rmesa->hw.all_dirty = GL_TRUE; + r200SwapHwState( rmesa ); + /* In this case it's okay to EmitState while locked because we won't exhaust + * our (empty) cmdbuf. + */ + r200EmitState( rmesa ); + r200FlushCmdBufLocked( rmesa, __FUNCTION__ ); + + r200SwapHwState( rmesa ); + /* We've just cleared out the dirty flags, so we don't remember what + * actually needed to be emitted for the next state emit. + */ + rmesa->hw.all_dirty = GL_TRUE; + rmesa->dma.nr_released_bufs = nr_released_bufs; + rmesa->store = store; +} int r200FlushCmdBufLocked( r200ContextPtr rmesa, const char * caller ) { int ret, i; drm_radeon_cmd_buffer_t cmd; + if (rmesa->lost_context) + r200BackUpAndEmitLostStateLocked( rmesa ); + if (R200_DEBUG & DEBUG_IOCTL) { fprintf(stderr, "%s from %s\n", __FUNCTION__, caller); @@ -132,18 +191,7 @@ int r200FlushCmdBufLocked( r200ContextPtr rmesa, const char * caller ) rmesa->store.statenr = 0; rmesa->store.cmd_used = 0; rmesa->dma.nr_released_bufs = 0; - /* Set lost_context so that the first state emit on the new buffer is a full - * one. This is because the context might get lost while preparing the next - * buffer, and when we lock and find out, we don't have the information to - * recreate the state. This function should always be called before the new - * buffer is begun, so it's sufficient to just set lost_context here. - * - * The alternative to this would be to copy out the state on unlock - * (approximately) and if we did lose the context, dispatch a cmdbuf to reset - * the state to that old copy before continuing with the accumulated command - * buffer. - */ - rmesa->lost_context = 1; + rmesa->save_on_next_unlock = 1; return ret; } @@ -464,7 +512,7 @@ void r200CopyBuffer( const __DRIdrawablePrivate *dPriv ) } UNLOCK_HARDWARE( rmesa ); - rmesa->lost_context = 1; + rmesa->hw.all_dirty = GL_TRUE; rmesa->swap_count++; (*rmesa->get_ust)( & ust ); @@ -613,13 +661,6 @@ static void r200Clear( GLcontext *ctx, GLbitfield mask, GLboolean all, cx += dPriv->x; cy = dPriv->y + dPriv->h - cy - ch; - /* We have to emit state along with the clear, since the kernel relies on - * some of it. The EmitState that was above R200_FIREVERTICES was an - * attempt to do that, except that another context may come in and cause us - * to lose our context while we're unlocked. - */ - r200EmitState( rmesa ); - LOCK_HARDWARE( rmesa ); /* Throttle the number of clear ioctls we do. @@ -722,7 +763,7 @@ static void r200Clear( GLcontext *ctx, GLbitfield mask, GLboolean all, } UNLOCK_HARDWARE( rmesa ); - rmesa->lost_context = 1; + rmesa->hw.all_dirty = GL_TRUE; } @@ -763,8 +804,7 @@ void r200Flush( GLcontext *ctx ) if (rmesa->dma.flush) rmesa->dma.flush( rmesa ); - if (!is_empty_list(&rmesa->hw.dirty)) - r200EmitState( rmesa ); + r200EmitState( rmesa ); if (rmesa->store.cmd_used) r200FlushCmdBuf( rmesa, __FUNCTION__ ); |