Catch errors in AL gen sources/buffers, workaround Apple OpenAL implementation leaking

This commit is contained in:
Joshua Granick
2018-04-03 17:05:11 -07:00
parent c34e11bb57
commit c9b28de490
3 changed files with 270 additions and 67 deletions

View File

@@ -1,6 +1,8 @@
#if defined (IPHONE) || defined (TVOS) || (defined (HX_MACOS) && !defined (LIME_OPENALSOFT))
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#define LIME_OPENAL_DELETION_DELAY 600
#include <time.h>
#else
#include "AL/al.h"
#include "AL/alc.h"
@@ -14,12 +16,20 @@
#include <system/CFFIPointer.h>
#include <system/Mutex.h>
#include <utils/ArrayBufferView.h>
#include <list>
#include <map>
namespace lime {
#ifdef LIME_OPENAL_DELETION_DELAY
std::list<ALuint> alDeletedBuffer;
std::list<time_t> alDeletedBufferTime;
std::list<ALuint> alDeletedSource;
std::list<time_t> alDeletedSourceTime;
#endif
std::map<ALuint, value> alObjects;
std::map<void*, value> alcObjects;
Mutex al_gc_mutex;
@@ -84,6 +94,28 @@ namespace lime {
}
void lime_al_atexit () {
ALCcontext* alcContext = alcGetCurrentContext ();
if (alcContext) {
ALCdevice* alcDevice = alcGetContextsDevice (alcContext);
alcMakeContextCurrent (0);
alcDestroyContext (alcContext);
if (alcDevice) {
alcCloseDevice (alcDevice);
}
}
}
void lime_al_auxf (value aux, int param, float value) {
#ifdef LIME_OPENALSOFT
@@ -255,23 +287,58 @@ namespace lime {
void lime_al_cleanup () {
ALCcontext* alcContext = alcGetCurrentContext ();
#ifdef LIME_OPENAL_DELETION_DELAY
time_t currentTime = time (0);
ALuint deletedData;
time_t deletedTime;
if (alcContext) {
std::list<ALuint>::const_iterator itSource = alDeletedSource.begin ();
std::list<time_t>::const_iterator itSourceTime = alDeletedSourceTime.begin ();
while (itSource != alDeletedSource.end ()) {
ALCdevice* alcDevice = alcGetContextsDevice (alcContext);
deletedTime = *itSourceTime;
alcMakeContextCurrent (0);
alcDestroyContext (alcContext);
if (alcDevice) {
if (difftime (currentTime, deletedTime) * 1000 > LIME_OPENAL_DELETION_DELAY) {
alcCloseDevice (alcDevice);
ALuint deletedData = *itSource;
alDeleteSources (1, &deletedData);
itSource = alDeletedSource.erase (itSource);
itSourceTime = alDeletedSourceTime.erase (itSourceTime);
} else {
++itSource;
++itSourceTime;
}
}
std::list<ALuint>::iterator itBuffer = alDeletedBuffer.begin ();
std::list<time_t>::iterator itBufferTime = alDeletedBufferTime.begin ();
while (itBuffer != alDeletedBuffer.end ()) {
deletedTime = *itBufferTime;
if (difftime (currentTime, deletedTime) * 1000 > LIME_OPENAL_DELETION_DELAY) {
ALuint deletedData = *itBuffer;
alDeleteBuffers (1, &deletedData);
itBuffer = alDeletedBuffer.erase (itBuffer);
itBufferTime = alDeletedBufferTime.erase (itBufferTime);
} else {
++itBuffer;
++itBufferTime;
}
}
#endif
}
@@ -300,7 +367,12 @@ namespace lime {
al_gc_mutex.Lock ();
ALuint data = (ALuint)(uintptr_t)val_data (buffer);
val_gc (buffer, 0);
#ifdef LIME_OPENAL_DELETION_DELAY
alDeletedBuffer.push_back (data);
alDeletedBufferTime.push_back (time (0));
#else
alDeleteBuffers ((ALuint)1, &data);
#endif
alObjects.erase (data);
al_gc_mutex.Unlock ();
@@ -314,10 +386,28 @@ namespace lime {
if (!val_is_null (buffers)) {
int size = val_array_size (buffers);
ALuint* data = new ALuint[size];
value buffer;
al_gc_mutex.Lock ();
#ifdef LIME_OPENAL_DELETION_DELAY
ALuint data;
for (int i = 0; i < size; ++i) {
buffer = val_array_i (buffers, i);
data = (ALuint)(uintptr_t)val_data (buffer);
alDeletedBuffer.push_back (data);
alDeletedBufferTime.push_back (time (0));
val_gc (buffer, 0);
alObjects.erase (data);
}
#else
ALuint* data = new ALuint[size];
for (int i = 0; i < size; ++i) {
buffer = val_array_i (buffers, i);
@@ -326,10 +416,13 @@ namespace lime {
alObjects.erase (data[i]);
}
al_gc_mutex.Unlock ();
alDeleteBuffers (n, data);
delete[] data;
#endif
al_gc_mutex.Unlock ();
}
@@ -371,8 +464,16 @@ namespace lime {
if (!val_is_null (source)) {
ALuint data = (ALuint)(uintptr_t)val_data (source);
alDeleteSources (1, &data);
val_gc (source, 0);
#ifdef LIME_OPENAL_DELETION_DELAY
al_gc_mutex.Lock ();
alSourcei (data, AL_BUFFER, 0);
alDeletedSource.push_back (data);
alDeletedSourceTime.push_back (time (0));
al_gc_mutex.Unlock ();
#else
alDeleteSources (1, &data);
#endif
}
@@ -384,9 +485,29 @@ namespace lime {
if (!val_is_null (sources)) {
int size = val_array_size (sources);
ALuint* data = new ALuint[size];
value source;
#ifdef LIME_OPENAL_DELETION_DELAY
al_gc_mutex.Lock ();
ALuint data;
for (int i = 0; i < size; ++i) {
source = val_array_i (sources, i);
data = (ALuint)(uintptr_t)val_data (source);
alSourcei (data, AL_BUFFER, 0);
alDeletedSource.push_back (data);
alDeletedSourceTime.push_back (time (0));
val_gc (source, 0);
}
al_gc_mutex.Unlock ();
#else
ALuint* data = new ALuint[size];
for (int i = 0; i < size; ++i) {
source = val_array_i (sources, i);
@@ -397,6 +518,7 @@ namespace lime {
alDeleteSources (n, data);
delete[] data;
#endif
}
@@ -547,96 +669,154 @@ namespace lime {
value lime_al_gen_buffer () {
al_gc_mutex.Lock ();
ALuint buffer;
alGetError ();
ALuint buffer = 0;
alGenBuffers ((ALuint)1, &buffer);
value ptr = CFFIPointer ((void*)(uintptr_t)buffer, gc_al_buffer);
alObjects[buffer] = ptr;
al_gc_mutex.Unlock ();
return ptr;
if (alGetError () == AL_NO_ERROR) {
al_gc_mutex.Lock ();
value ptr = CFFIPointer ((void*)(uintptr_t)buffer, gc_al_buffer);
alObjects[buffer] = ptr;
al_gc_mutex.Unlock ();
return ptr;
} else {
return alloc_null ();
}
}
value lime_al_gen_buffers (int n) {
alGetError ();
ALuint* buffers = new ALuint[n];
alGenBuffers (n, buffers);
value result = alloc_array (n);
ALuint buffer;
value ptr;
al_gc_mutex.Lock ();
for (int i = 0; i < n; i++) {
if (alGetError () == AL_NO_ERROR) {
buffer = buffers[i];
ptr = CFFIPointer ((void*)(uintptr_t)buffer, gc_al_buffer);
alObjects[buffer] = ptr;
value result = alloc_array (n);
val_array_set_i (result, i, ptr);
ALuint buffer;
value ptr;
al_gc_mutex.Lock ();
for (int i = 0; i < n; i++) {
buffer = buffers[i];
ptr = CFFIPointer ((void*)(uintptr_t)buffer, gc_al_buffer);
alObjects[buffer] = ptr;
val_array_set_i (result, i, ptr);
}
al_gc_mutex.Unlock ();
delete[] buffers;
return result;
} else {
delete[] buffers;
return alloc_null ();
}
al_gc_mutex.Unlock ();
delete[] buffers;
return result;
}
value lime_al_gen_effect () {
alGetError ();
#ifdef LIME_OPENALSOFT
ALuint effect;
alGenEffects ((ALuint)1, &effect);
return CFFIPointer ((void*)(uintptr_t)effect, gc_al_effect);
#else
return alloc_null ();
if (alGetError () == AL_NO_ERROR) {
return CFFIPointer ((void*)(uintptr_t)effect, gc_al_effect);
}
#endif
return alloc_null ();
}
value lime_al_gen_filter () {
alGetError ();
#ifdef LIME_OPENALSOFT
ALuint filter;
alGenFilters ((ALuint)1, &filter);
return CFFIPointer ((void*)(uintptr_t)filter, gc_al_filter);
#else
return alloc_null ();
if (alGetError () == AL_NO_ERROR) {
return CFFIPointer ((void*)(uintptr_t)filter, gc_al_filter);
}
#endif
return alloc_null ();
}
value lime_al_gen_source () {
alGetError ();
ALuint source;
alGenSources ((ALuint)1, &source);
return CFFIPointer ((void*)(uintptr_t)source, gc_al_source);
if (alGetError () == AL_NO_ERROR) {
return CFFIPointer ((void*)(uintptr_t)source, gc_al_source);
} else {
return alloc_null ();
}
}
value lime_al_gen_sources (int n) {
alGetError ();
ALuint* sources = new ALuint[n];
alGenSources (n, sources);
value result = alloc_array (n);
for (int i = 0; i < n; i++) {
if (alGetError () == AL_NO_ERROR) {
val_array_set_i (result, i, CFFIPointer ((void*)(uintptr_t)sources[i], gc_al_source));
value result = alloc_array (n);
for (int i = 0; i < n; i++) {
val_array_set_i (result, i, CFFIPointer ((void*)(uintptr_t)sources[i], gc_al_source));
}
delete[] sources;
return result;
} else {
delete[] sources;
return alloc_null ();
}
delete[] sources;
return result;
}
@@ -1480,29 +1660,33 @@ namespace lime {
void lime_al_sourcei (value source, int param, value val) {
ALuint id = (ALuint)(uintptr_t)val_data (source);
ALuint data;
ALuint data = 0;
#ifdef LIME_OPENALSOFT
if (param == AL_BUFFER || param == AL_DIRECT_FILTER) {
if (!val_is_null (val)) {
data = (ALuint)(uintptr_t)val_data (val);
} else {
data = val_int (val);
#ifdef LIME_OPENALSOFT
if (param == AL_BUFFER || param == AL_DIRECT_FILTER) {
data = (ALuint)(uintptr_t)val_data (val);
} else {
data = val_int (val);
}
#else
if (param == AL_BUFFER) {
data = (ALuint)(uintptr_t)val_data (val);
} else {
data = val_int (val);
}
#endif
}
#else
if (param == AL_BUFFER) {
data = (ALuint)(uintptr_t)val_data (val);
} else {
data = val_int (val);
}
#endif
alSourcei (id, param, data);
@@ -1693,7 +1877,7 @@ namespace lime {
value lime_alc_open_device (HxString devicename) {
ALCdevice* alcDevice = alcOpenDevice (devicename.__s);
atexit (lime_al_cleanup);
atexit (lime_al_atexit);
value ptr = CFFIPointer (alcDevice, gc_alc_object);
alcObjects[alcDevice] = ptr;
@@ -1751,6 +1935,7 @@ namespace lime {
DEFINE_PRIME3v (lime_al_bufferfv);
DEFINE_PRIME3v (lime_al_bufferi);
DEFINE_PRIME3v (lime_al_bufferiv);
DEFINE_PRIME0v (lime_al_cleanup);
DEFINE_PRIME1v (lime_al_delete_auxiliary_effect_slot);
DEFINE_PRIME1v (lime_al_delete_buffer);
DEFINE_PRIME2v (lime_al_delete_buffers);