audio: precalculate if we can use simple copies instead of the full mixer.
This just saves a bunch of conditionals (and an atomic get!) per iteration of the audio thread.main
parent
36b0f11414
commit
23f60203a3
|
@ -137,6 +137,20 @@ static int GetDefaultSampleFramesFromFreq(const int freq)
|
|||
}
|
||||
}
|
||||
|
||||
// device should be locked when calling this.
|
||||
static SDL_bool AudioDeviceCanUseSimpleCopy(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_assert(device != NULL);
|
||||
return (
|
||||
device->logical_devices && // there's a logical device
|
||||
!device->logical_devices->next && // there's only _ONE_ logical device
|
||||
!device->logical_devices->postmix && // there isn't a postmix callback
|
||||
!SDL_AtomicGet(&device->logical_devices->paused) && // it isn't paused
|
||||
device->logical_devices->bound_streams && // there's a bound stream
|
||||
!device->logical_devices->bound_streams->next_binding // there's only _ONE_ bound stream.
|
||||
) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// device management and hotplug...
|
||||
|
||||
|
@ -198,6 +212,8 @@ static void DestroyLogicalAudioDevice(SDL_LogicalAudioDevice *logdev)
|
|||
SDL_UnlockMutex(stream->lock);
|
||||
}
|
||||
|
||||
logdev->physical_device->simple_copy = AudioDeviceCanUseSimpleCopy(logdev->physical_device);
|
||||
|
||||
SDL_free(logdev);
|
||||
}
|
||||
|
||||
|
@ -752,19 +768,12 @@ SDL_bool SDL_OutputAudioThreadIterate(SDL_AudioDevice *device)
|
|||
retval = SDL_FALSE;
|
||||
} else {
|
||||
SDL_assert(buffer_size <= device->buffer_size); // you can ask for less, but not more.
|
||||
SDL_assert(AudioDeviceCanUseSimpleCopy(device) == device->simple_copy); // make sure this hasn't gotten out of sync.
|
||||
|
||||
// can we do a basic copy without silencing/mixing the buffer? This is an extremely likely scenario, so we special-case it.
|
||||
const SDL_bool simple_copy = device->logical_devices && // there's a logical device
|
||||
!device->logical_devices->next && // there's only _ONE_ logical device
|
||||
!device->logical_devices->postmix && // there isn't a postmix callback
|
||||
!SDL_AtomicGet(&device->logical_devices->paused) && // it isn't paused
|
||||
device->logical_devices->bound_streams && // there's a bound stream
|
||||
!device->logical_devices->bound_streams->next_binding; // there's only _ONE_ bound stream.
|
||||
|
||||
if (simple_copy) {
|
||||
if (device->simple_copy) {
|
||||
SDL_LogicalAudioDevice *logdev = device->logical_devices;
|
||||
SDL_AudioStream *stream = logdev->bound_streams;
|
||||
|
||||
const int br = GetAudioStreamDataInFormat(stream, device_buffer, buffer_size, &device->spec);
|
||||
if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
|
||||
retval = SDL_FALSE;
|
||||
|
@ -1423,6 +1432,7 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp
|
|||
device->logical_devices->prev = logdev;
|
||||
}
|
||||
device->logical_devices = logdev;
|
||||
device->simple_copy = AudioDeviceCanUseSimpleCopy(device);
|
||||
}
|
||||
SDL_UnlockMutex(device->lock);
|
||||
}
|
||||
|
@ -1437,6 +1447,7 @@ static int SetLogicalAudioDevicePauseState(SDL_AudioDeviceID devid, int value)
|
|||
return -1; // ObtainLogicalAudioDevice will have set an error.
|
||||
}
|
||||
SDL_AtomicSet(&logdev->paused, value);
|
||||
logdev->physical_device->simple_copy = AudioDeviceCanUseSimpleCopy(logdev->physical_device);
|
||||
SDL_UnlockMutex(logdev->physical_device->lock);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1482,6 +1493,8 @@ int SDL_SetAudioPostmixCallback(SDL_AudioDeviceID devid, SDL_AudioPostmixCallbac
|
|||
logdev->postmix_userdata = userdata;
|
||||
}
|
||||
|
||||
device->simple_copy = AudioDeviceCanUseSimpleCopy(device);
|
||||
|
||||
SDL_UnlockMutex(device->lock);
|
||||
}
|
||||
return retval;
|
||||
|
@ -1565,6 +1578,8 @@ int SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream **streams, int
|
|||
}
|
||||
}
|
||||
|
||||
device->simple_copy = AudioDeviceCanUseSimpleCopy(device);
|
||||
|
||||
SDL_UnlockMutex(device->lock);
|
||||
|
||||
return retval;
|
||||
|
@ -1635,6 +1650,7 @@ void SDL_UnbindAudioStreams(SDL_AudioStream **streams, int num_streams)
|
|||
stream->bound_device = NULL;
|
||||
SDL_UnlockMutex(stream->lock);
|
||||
if (logdev) {
|
||||
logdev->physical_device->simple_copy = AudioDeviceCanUseSimpleCopy(logdev->physical_device);
|
||||
SDL_UnlockMutex(logdev->physical_device->lock);
|
||||
}
|
||||
}
|
||||
|
@ -1674,10 +1690,12 @@ SDL_AudioStream *SDL_OpenAudioDeviceStream(SDL_AudioDeviceID devid, const SDL_Au
|
|||
|
||||
SDL_AudioDevice *physdevice = logdev->physical_device;
|
||||
SDL_assert(physdevice != NULL);
|
||||
SDL_UnlockMutex(physdevice->lock); // we don't need to hold the lock for any of this.
|
||||
const SDL_bool iscapture = physdevice->iscapture;
|
||||
|
||||
SDL_AtomicSet(&logdev->paused, 1); // start the device paused, to match SDL2.
|
||||
physdevice->simple_copy = AudioDeviceCanUseSimpleCopy(physdevice);
|
||||
|
||||
SDL_UnlockMutex(physdevice->lock); // we don't need to hold the lock for any of this.
|
||||
const SDL_bool iscapture = physdevice->iscapture;
|
||||
|
||||
SDL_AudioStream *stream = NULL;
|
||||
if (iscapture) {
|
||||
|
@ -1831,6 +1849,9 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
|
|||
new_default_device->logical_devices = logdev;
|
||||
}
|
||||
|
||||
current_default_device->simple_copy = AudioDeviceCanUseSimpleCopy(current_default_device);
|
||||
new_default_device->simple_copy = AudioDeviceCanUseSimpleCopy(new_default_device);
|
||||
|
||||
if (current_default_device->logical_devices == NULL) { // nothing left on the current physical device, close it.
|
||||
// !!! FIXME: we _need_ to release this lock, but doing so can cause a race condition if someone opens a device while we're closing it.
|
||||
SDL_UnlockMutex(current_default_device->lock); // can't hold the lock or the audio thread will deadlock while we WaitThread it.
|
||||
|
|
|
@ -267,6 +267,9 @@ struct SDL_AudioDevice
|
|||
// SDL_TRUE if this is a capture device instead of an output device
|
||||
SDL_bool iscapture;
|
||||
|
||||
// SDL_TRUE if audio thread can skip silence/mix/convert stages and just do a basic memcpy.
|
||||
SDL_bool simple_copy;
|
||||
|
||||
// Scratch buffers used for mixing.
|
||||
Uint8 *work_buffer;
|
||||
Uint8 *mix_buffer;
|
||||
|
|
Loading…
Reference in New Issue