Module: wine Branch: master Commit: 575f34e5489660dc4e43ad17ba52daeb6d75beaa URL: http://source.winehq.org/git/wine.git/?a=commit;h=575f34e5489660dc4e43ad17ba...
Author: Maarten Lankhorst m.b.lankhorst@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;