summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/r200/r200_ioctl.c
diff options
context:
space:
mode:
authorEric Anholt <anholt@FreeBSD.org>2004-09-22 06:27:02 +0000
committerEric Anholt <anholt@FreeBSD.org>2004-09-22 06:27:02 +0000
commit0c8f8d3dc9d60ed34eeca7f3606651420a81753c (patch)
tree3876839944c4194d4eac39863e96b64c4cfd7683 /src/mesa/drivers/dri/r200/r200_ioctl.c
parent029ee9c680cd097b82d3d301b3854d57993d4464 (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.c86
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__ );