summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2014-10-12 09:03:08 -0700
committerChris Robinson <[email protected]>2014-10-12 09:17:13 -0700
commit4320a1483b22eff1cc49b13570054064b321473b (patch)
tree8c41a696d5859db726837016297860817ec3e562
parenta77387b5490e8f40c682118c2a1c192cddc06939 (diff)
Make alcSuspendContext and alcProcessContext batch updates
This behavior better matches Creative's hardware drivers and Rapture3D's OpenAL driver. A compatibility environment variable is provided to restore the old no-op behavior for any app that behaves badly from this change (set __ALSOFT_SUSPEND_CONTEXT to "ignore"). If too many apps have a problem with this, the default behavior may need to be changed to ignore, with the env var providing an option to defer/batch instead.
-rw-r--r--Alc/ALc.c139
-rw-r--r--OpenAL32/Include/alMain.h3
-rw-r--r--OpenAL32/alState.c74
-rw-r--r--env-vars.txt10
4 files changed, 150 insertions, 76 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c
index 04c3f398..781e0729 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -748,6 +748,11 @@ static alonce_flag alc_config_once = AL_ONCE_FLAG_INIT;
/* Default effect that applies to sources that don't have an effect on send 0 */
static ALeffect DefaultEffect;
+/* Flag to specify if alcSuspendContext/alcProcessContext should defer/process
+ * updates.
+ */
+static ALCboolean SuspendDefers = ALC_TRUE;
+
/************************************************
* ALC information
@@ -908,6 +913,18 @@ static void alc_initconfig(void)
}
ReadALConfig();
+ str = getenv("__ALSOFT_SUSPEND_CONTEXT");
+ if(str && *str)
+ {
+ if(strcasecmp(str, "ignore") == 0)
+ {
+ SuspendDefers = ALC_FALSE;
+ TRACE("Selected context suspend behavior, \"ignore\"\n");
+ }
+ else
+ ERR("Unhandled context suspend behavior setting: \"%s\"\n", str);
+ }
+
capfilter = 0;
#if defined(HAVE_SSE4_1)
capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE4_1;
@@ -1538,6 +1555,98 @@ void SetDefaultChannelOrder(ALCdevice *device)
extern inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan);
+/* ALCcontext_DeferUpdates
+ *
+ * Defers/suspends updates for the given context's listener and sources. This
+ * does *NOT* stop mixing, but rather prevents certain property changes from
+ * taking effect.
+ */
+void ALCcontext_DeferUpdates(ALCcontext *context)
+{
+ ALCdevice *device = context->Device;
+ FPUCtl oldMode;
+
+ SetMixerFPUMode(&oldMode);
+
+ V0(device->Backend,lock)();
+ if(!ExchangeInt(&context->DeferUpdates, AL_TRUE))
+ {
+ ALboolean UpdateSources;
+ ALvoice *voice, *voice_end;
+ ALeffectslot **slot, **slot_end;
+ /* Make sure all pending updates are performed */
+ UpdateSources = ATOMIC_EXCHANGE(ALenum, &context->UpdateSources, AL_FALSE);
+
+ voice = context->Voices;
+ voice_end = voice + context->VoiceCount;
+ while(voice != voice_end)
+ {
+ ALsource *source = voice->Source;
+ if(!source) goto next;
+
+ if(source->state != AL_PLAYING && source->state != AL_PAUSED)
+ {
+ voice->Source = NULL;
+ continue;
+ }
+
+ if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) || UpdateSources)
+ voice->Update(voice, source, context);
+ next:
+ voice++;
+ }
+
+ slot = VECTOR_ITER_BEGIN(context->ActiveAuxSlots);
+ slot_end = VECTOR_ITER_END(context->ActiveAuxSlots);
+ while(slot != slot_end)
+ {
+ if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
+ V((*slot)->EffectState,update)(context->Device, *slot);
+ slot++;
+ }
+ }
+ V0(device->Backend,unlock)();
+
+ RestoreFPUMode(&oldMode);
+}
+
+/* ALCcontext_ProcessUpdates
+ *
+ * Resumes update processing after being deferred.
+ */
+void ALCcontext_ProcessUpdates(ALCcontext *context)
+{
+ ALCdevice *device = context->Device;
+
+ V0(device->Backend,lock)();
+ if(ExchangeInt(&context->DeferUpdates, AL_FALSE))
+ {
+ ALsizei pos;
+
+ LockUIntMapRead(&context->SourceMap);
+ for(pos = 0;pos < context->SourceMap.size;pos++)
+ {
+ ALsource *Source = context->SourceMap.array[pos].value;
+ ALenum new_state;
+
+ if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
+ Source->Offset >= 0.0)
+ {
+ ReadLock(&Source->queue_lock);
+ ApplyOffset(Source);
+ ReadUnlock(&Source->queue_lock);
+ }
+
+ new_state = ExchangeInt(&Source->new_state, AL_NONE);
+ if(new_state)
+ SetSourceState(Source, context, new_state);
+ }
+ UnlockUIntMapRead(&context->SourceMap);
+ }
+ V0(device->Backend,unlock)();
+}
+
+
/* alcSetError
*
* Stores the latest ALC device error
@@ -2307,18 +2416,40 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
/* alcSuspendContext
*
- * Not functional
+ * Suspends updates for the given context
*/
-ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *UNUSED(context))
+ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *context)
{
+ if(!SuspendDefers)
+ return;
+
+ context = VerifyContext(context);
+ if(!context)
+ alcSetError(NULL, ALC_INVALID_CONTEXT);
+ else
+ {
+ ALCcontext_DeferUpdates(context);
+ ALCcontext_DecRef(context);
+ }
}
/* alcProcessContext
*
- * Not functional
+ * Resumes processing updates for the given context
*/
-ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *UNUSED(context))
+ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *context)
{
+ if(!SuspendDefers)
+ return;
+
+ context = VerifyContext(context);
+ if(!context)
+ alcSetError(NULL, ALC_INVALID_CONTEXT);
+ else
+ {
+ ALCcontext_ProcessUpdates(context);
+ ALCcontext_DecRef(context);
+ }
}
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index 8cbac90e..191c35b7 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -777,6 +777,9 @@ void ALCdevice_Lock(ALCdevice *device);
void ALCdevice_Unlock(ALCdevice *device);
ALint64 ALCdevice_GetLatency(ALCdevice *device);
+void ALCcontext_DeferUpdates(ALCcontext *context);
+void ALCcontext_ProcessUpdates(ALCcontext *context);
+
inline void LockContext(ALCcontext *context)
{ ALCdevice_Lock(context->Device); }
diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c
index b4f17b9d..180a8c04 100644
--- a/OpenAL32/alState.c
+++ b/OpenAL32/alState.c
@@ -712,52 +712,7 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
context = GetContextRef();
if(!context) return;
- if(!context->DeferUpdates)
- {
- ALboolean UpdateSources;
- ALvoice *voice, *voice_end;
- ALeffectslot **slot, **slot_end;
- FPUCtl oldMode;
-
- SetMixerFPUMode(&oldMode);
-
- LockContext(context);
- context->DeferUpdates = AL_TRUE;
-
- /* Make sure all pending updates are performed */
- UpdateSources = ATOMIC_EXCHANGE(ALenum, &context->UpdateSources, AL_FALSE);
-
- voice = context->Voices;
- voice_end = voice + context->VoiceCount;
- while(voice != voice_end)
- {
- ALsource *source = voice->Source;
- if(!source) goto next;
-
- if(source->state != AL_PLAYING && source->state != AL_PAUSED)
- {
- voice->Source = NULL;
- continue;
- }
-
- if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) || UpdateSources)
- voice->Update(voice, source, context);
- next:
- voice++;
- }
-
- slot = VECTOR_ITER_BEGIN(context->ActiveAuxSlots);
- slot_end = VECTOR_ITER_END(context->ActiveAuxSlots);
- while(slot != slot_end)
- {
- if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
- V((*slot)->EffectState,update)(context->Device, *slot);
- slot++;
- }
-
- UnlockContext(context);
- RestoreFPUMode(&oldMode);
- }
+ ALCcontext_DeferUpdates(context);
ALCcontext_DecRef(context);
}
@@ -769,32 +724,7 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
context = GetContextRef();
if(!context) return;
- LockContext(context);
- if(ExchangeInt(&context->DeferUpdates, AL_FALSE))
- {
- ALsizei pos;
-
- LockUIntMapRead(&context->SourceMap);
- for(pos = 0;pos < context->SourceMap.size;pos++)
- {
- ALsource *Source = context->SourceMap.array[pos].value;
- ALenum new_state;
-
- if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
- Source->Offset >= 0.0)
- {
- ReadLock(&Source->queue_lock);
- ApplyOffset(Source);
- ReadUnlock(&Source->queue_lock);
- }
-
- new_state = ExchangeInt(&Source->new_state, AL_NONE);
- if(new_state)
- SetSourceState(Source, context, new_state);
- }
- UnlockUIntMapRead(&context->SourceMap);
- }
- UnlockContext(context);
+ ALCcontext_ProcessUpdates(context);
ALCcontext_DecRef(context);
}
diff --git a/env-vars.txt b/env-vars.txt
index 47dce032..487067d5 100644
--- a/env-vars.txt
+++ b/env-vars.txt
@@ -69,3 +69,13 @@ sound (i.e., sounds that are supposed to be behind you sound like they're in
front, and vice-versa). Setting this to "true" or "1" will negate the localized
Z coordinate to attempt to fix output for apps that have incorrect front/back
panning.
+
+__ALSOFT_SUSPEND_CONTEXT
+Due to the OpenAL spec not being very clear about them, behavior of the
+alcSuspendContext and alcProcessContext methods has varied, and because of
+that, previous versions of OpenAL Soft had them no-op. Creative's hardware
+drivers and the Rapture3D driver, however, use these methods to batch changes
+and protect against partial updates, which some applications make use of. In an
+attempt to standardize on that behavior, OpenAL Soft has changed those methods
+accordingly. Setting this to "ignore" restores the previous no-op behavior for
+applications that interact poorly with the new behavior.