Maarten Lankhorst : dsound: Add SndQueueMin to have less lock contention in mixer.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Aug 1 05:16:44 CDT 2007


Module: wine
Branch: master
Commit: 575f34e5489660dc4e43ad17ba52daeb6d75beaa
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=575f34e5489660dc4e43ad17ba52daeb6d75beaa

Author: Maarten Lankhorst <m.b.lankhorst at gmail.com>
Date:   Mon Jul 30 16:12:29 2007 +0200

dsound: Add SndQueueMin to have less lock contention in mixer.

---

 dlls/dsound/dsound_main.c    |    7 +++++++
 dlls/dsound/dsound_private.h |    1 +
 dlls/dsound/mixer.c          |   22 +++++++++++++++-------
 3 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c
index 497fa15..2feb935 100644
--- a/dlls/dsound/dsound_main.c
+++ b/dlls/dsound/dsound_main.c
@@ -55,6 +55,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
 #define DS_HEL_BUFLEN 0x8000 /* HEL: The buffer length of the emulated buffer */
 #define DS_SND_QUEUE_MAX 10 /* max number of fragments to prebuffer, each fragment is approximately 10 ms long */
+#define DS_SND_QUEUE_MIN 6 /* If the minimum of prebuffered fragments go below this, forcibly take all locks to prevent underruns */
 
 DirectSoundDevice*	DSOUND_renderer[MAXWAVEDRIVERS];
 GUID                    DSOUND_renderer_guids[MAXWAVEDRIVERS];
@@ -90,6 +91,7 @@ HRESULT mmErr(UINT err)
 int ds_emuldriver = 0;
 int ds_hel_buflen = DS_HEL_BUFLEN;
 int ds_snd_queue_max = DS_SND_QUEUE_MAX;
+int ds_snd_queue_min = DS_SND_QUEUE_MIN;
 int ds_hw_accel = DS_HW_ACCEL_FULL;
 int ds_default_playback = 0;
 int ds_default_capture = 0;
@@ -152,6 +154,9 @@ void setup_dsound_options(void)
     if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH ))
         ds_snd_queue_max = atoi(buffer);
 
+    if (!get_config_key( hkey, appkey, "SndQueueMin", buffer, MAX_PATH ))
+        ds_snd_queue_min = atoi(buffer);
+
     if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) {
 	if (strcmp(buffer, "Full") == 0)
 	    ds_hw_accel = DS_HW_ACCEL_FULL;
@@ -184,6 +189,8 @@ void setup_dsound_options(void)
        WARN("ds_hel_buflen = %d (default=%d)\n",ds_hel_buflen ,DS_HEL_BUFLEN);
     if (ds_snd_queue_max != DS_SND_QUEUE_MAX)
        WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX);
+    if (ds_snd_queue_min != DS_SND_QUEUE_MIN)
+       WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min ,DS_SND_QUEUE_MIN);
     if (ds_hw_accel != DS_HW_ACCEL_FULL)
 	WARN("ds_hw_accel = %s (default=Full)\n",
 	    ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" :
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 91ac107..61ff4a0 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -32,6 +32,7 @@
 extern int ds_emuldriver;
 extern int ds_hel_buflen;
 extern int ds_snd_queue_max;
+extern int ds_snd_queue_min;
 extern int ds_hw_accel;
 extern int ds_default_playback;
 extern int ds_default_capture;
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 6390584..c9ede68 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -667,10 +667,10 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi
  * For a DirectSoundDevice, go through all the currently playing buffers and
  * mix them in to the device buffer.
  *
- * playpos = the current play position in the primary buffer
  * writepos = the current safe-to-write position in the primary buffer
  * mixlen = the maximum amount to mix into the primary buffer
  *          (beyond the current writepos)
+ * mustlock = Do we have to fight for lock because we otherwise risk an underrun?
  * recover = true if the sound device may have been reset and the write
  *           position in the device buffer changed
  * all_stopped = reports back if all buffers have stopped
@@ -678,12 +678,12 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi
  * Returns:  the length beyond the writepos that was mixed to.
  */
 
-static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos,
-                                 DWORD mixlen, BOOL recover, BOOL *all_stopped)
+static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos, DWORD mixlen, BOOL mustlock, BOOL recover, BOOL *all_stopped)
 {
 	INT i, len;
 	DWORD minlen = 0;
 	IDirectSoundBufferImpl	*dsb;
+	BOOL gotall = TRUE;
 
 	/* unless we find a running buffer, all have stopped */
 	*all_stopped = TRUE;
@@ -696,8 +696,11 @@ static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos
 
 		if (dsb->buflen && dsb->state && !dsb->hwbuf) {
 			TRACE("Checking %p, mixlen=%d\n", dsb, mixlen);
-			RtlAcquireResourceShared(&dsb->lock, TRUE);
-
+			if (!RtlAcquireResourceShared(&dsb->lock, mustlock))
+			{
+				gotall = FALSE;
+				continue;
+			}
 			/* if buffer is stopping it is stopped now */
 			if (dsb->state == STATE_STOPPING) {
 				dsb->state = STATE_STOPPED;
@@ -733,7 +736,7 @@ static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos
 	}
 
 	TRACE("Mixed at least %d from all buffers\n", minlen);
-
+	if (!gotall) return 0;
 	return minlen;
 }
 
@@ -816,6 +819,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
 		DWORD playpos, writepos, writelead, maxq, frag, prebuff_max, prebuff_left, size1, size2;
 		LPVOID buf1, buf2;
 		BOOL lock = (device->hwbuf && !(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK));
+		BOOL mustlock = FALSE;
 		int nfiller;
 
 		/* the sound of silence */
@@ -890,11 +894,15 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
 			device->mixpos = writepos;
 		}
 
+		/* Do we risk an 'underrun' if we don't advance pointer? */
+		if (writelead/device->fraglen <= ds_snd_queue_min || recover)
+			mustlock = TRUE;
+
 		if (lock)
 			IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, writepos, maxq, 0);
 
 		/* do the mixing */
-		frag = DSOUND_MixToPrimary(device, writepos, maxq, recover, &all_stopped);
+		frag = DSOUND_MixToPrimary(device, writepos, maxq, mustlock, recover, &all_stopped);
 
 		/* update the mix position, taking wrap-around into acount */
 		device->mixpos = writepos + frag;




More information about the wine-cvs mailing list