aboutsummaryrefslogtreecommitdiffstats
path: root/al/buffer.cpp
diff options
context:
space:
mode:
authorBoris I. Bendovsky <[email protected]>2022-01-30 14:47:32 +0200
committerGitHub <[email protected]>2022-01-30 04:47:32 -0800
commit19ed994dc30ed84ea7cbbb5152577669fc25caf6 (patch)
treef68933bf8f778806618bd6c0b1bf9ced1b0ccf08 /al/buffer.cpp
parent619249371a40f03cf988d1f5750d643df797c485 (diff)
Add EAX extensions (EAX 2.0-5.0, X-RAM) (#632)
* Add EAX extensions (EAX 2.0-5.0, X-RAM) * Comment out C++17 leftovers * Remove everything related to patching * Update alsoftrc.sample * Rewrite integration * Fix GCC compilation under Linux * Always reset EAX effect properties when loading it into FX slot
Diffstat (limited to 'al/buffer.cpp')
-rw-r--r--al/buffer.cpp292
1 files changed, 292 insertions, 0 deletions
diff --git a/al/buffer.cpp b/al/buffer.cpp
index a473c3f9..a4967223 100644
--- a/al/buffer.cpp
+++ b/al/buffer.cpp
@@ -56,6 +56,11 @@
#include "core/voice.h"
#include "opthelpers.h"
+#if ALSOFT_EAX
+#include "eax_globals.h"
+#include "eax_x_ram.h"
+#endif // ALSOFT_EAX
+
namespace {
@@ -412,6 +417,15 @@ ALbuffer *AllocBuffer(ALCdevice *device)
void FreeBuffer(ALCdevice *device, ALbuffer *buffer)
{
+#if ALSOFT_EAX
+ if (buffer->eax_x_ram_is_hardware)
+ {
+ const auto buffer_size = static_cast<ALsizei>(buffer->OriginalSize);
+ assert((device->eax_x_ram_free_size + buffer_size) <= eax_x_ram_max_size);
+ device->eax_x_ram_free_size += buffer_size;
+ }
+#endif // ALSOFT_EAX
+
const ALuint id{buffer->id - 1};
const size_t lidx{id >> 6};
const ALuint slidx{id & 0x3f};
@@ -485,6 +499,102 @@ const ALchar *NameFromUserFmtType(UserFmtType type)
return "<internal type error>";
}
+#if ALSOFT_EAX
+bool eax_x_ram_validate_buffer(
+ ALCdevice& al_device,
+ ALbuffer& al_buffer)
+{
+ switch (al_buffer.eax_x_ram_mode)
+ {
+ case AL_STORAGE_HARDWARE:
+ if (al_buffer.OriginalSize > static_cast<ALuint>(al_device.eax_x_ram_free_size))
+ {
+ return false;
+ }
+
+ break;
+
+ case AL_STORAGE_AUTOMATIC:
+ case AL_STORAGE_ACCESSIBLE:
+ break;
+
+ default:
+ assert(false && "Unsupported X-RAM mode.");
+ return false;
+ }
+
+ return true;
+}
+
+void eax_x_ram_update_buffer(
+ ALCdevice& al_device,
+ ALbuffer& al_buffer)
+{
+ const auto buffer_size = static_cast<ALsizei>(al_buffer.OriginalSize);
+
+ auto is_hardware = al_buffer.eax_x_ram_is_hardware;
+ auto size_delta = ALsizei{};
+
+ switch (al_buffer.eax_x_ram_mode)
+ {
+ case AL_STORAGE_AUTOMATIC:
+ if (!al_buffer.eax_x_ram_is_dirty)
+ {
+ // First usage.
+
+ if (buffer_size <= al_device.eax_x_ram_free_size)
+ {
+ // Have enough X-RAM memory.
+
+ is_hardware = true;
+ size_delta = -buffer_size;
+ }
+ }
+ else
+ {
+ // Used at least once.
+ // From now on, use only system memory.
+
+ is_hardware = false;
+
+ if (al_buffer.eax_x_ram_is_hardware)
+ {
+ // First allocation was in X-RAM.
+ // Free that block.
+
+ size_delta = buffer_size;
+ }
+ }
+
+ break;
+
+ case AL_STORAGE_HARDWARE:
+ is_hardware = true;
+ size_delta = buffer_size;
+
+ break;
+
+ case AL_STORAGE_ACCESSIBLE:
+ // Always use system memory.
+ is_hardware = false;
+ break;
+
+ default:
+ break;
+ }
+
+ al_buffer.eax_x_ram_is_hardware = is_hardware;
+ al_buffer.eax_x_ram_is_dirty = true;
+
+ assert(
+ (al_device.eax_x_ram_free_size + size_delta) >= eax_x_ram_min_size &&
+ (al_device.eax_x_ram_free_size + size_delta) <= eax_x_ram_max_size
+ );
+
+ al_device.eax_x_ram_free_size += size_delta;
+}
+#endif // ALSOFT_EAX
+
/** Loads the specified data into the buffer, using the specified format. */
void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size,
UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData,
@@ -620,6 +730,13 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size,
ALBuf->mSampleLen = frames;
ALBuf->mLoopStart = 0;
ALBuf->mLoopEnd = ALBuf->mSampleLen;
+
+#if ALSOFT_EAX
+ if (eax_g_is_enabled)
+ {
+ eax_x_ram_update_buffer(*context->mALDevice, *ALBuf);
+ }
+#endif // ALSOFT_EAX
}
/** Prepares the buffer to use the specified callback, using the specified format. */
@@ -889,8 +1006,24 @@ START_API_FUNC
if UNLIKELY(!usrfmt)
context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format);
else
+#if ALSOFT_EAX
+ {
+ if (eax_g_is_enabled)
+ {
+ const auto is_buffer_valid = eax_x_ram_validate_buffer(*device, *albuf);
+
+ if (!is_buffer_valid)
+ {
+ context->setError(AL_OUT_OF_MEMORY, "Out of X-RAM memory.");
+ return;
+ }
+ }
+#endif // ALSOFT_EAX
LoadData(context.get(), albuf, freq, static_cast<ALuint>(size), usrfmt->channels,
usrfmt->type, static_cast<const al::byte*>(data), flags);
+#if ALSOFT_EAX
+ }
+#endif // ALSOFT_EAX
}
}
END_API_FUNC
@@ -1642,3 +1775,162 @@ BufferSubList::~BufferSubList()
al_free(Buffers);
Buffers = nullptr;
}
+
+
+#if ALSOFT_EAX
+ALboolean AL_APIENTRY EAXSetBufferMode(
+ ALsizei n,
+ const ALuint* buffers,
+ ALint value)
+START_API_FUNC
+{
+#define EAX_PREFIX "[EAXSetBufferMode] "
+
+ if (n == 0)
+ {
+ return ALC_TRUE;
+ }
+
+ if (n < 0)
+ {
+ ERR(EAX_PREFIX "Buffer count %d out of range.\n", n);
+ return ALC_FALSE;
+ }
+
+ if (!buffers)
+ {
+ ERR(EAX_PREFIX "%s\n", "Null AL buffers.");
+ return ALC_FALSE;
+ }
+
+ switch (value)
+ {
+ case AL_STORAGE_AUTOMATIC:
+ case AL_STORAGE_HARDWARE:
+ case AL_STORAGE_ACCESSIBLE:
+ break;
+
+ default:
+ ERR(EAX_PREFIX "Unsupported X-RAM mode %d.\n", value);
+ return ALC_FALSE;
+ }
+
+ const auto context = ContextRef{GetContextRef()};
+
+ if (!context)
+ {
+ ERR(EAX_PREFIX "%s\n", "No current context.");
+ return ALC_FALSE;
+ }
+
+ if (!eax_g_is_enabled)
+ {
+ ERR(EAX_PREFIX "%s\n", "EAX not enabled.");
+ return ALC_FALSE;
+ }
+
+ auto device = context->mALDevice.get();
+ std::lock_guard<std::mutex> device_lock{device->BufferLock};
+
+ // Validate the buffers.
+ //
+ for (auto i = 0; i < n; ++i)
+ {
+ const auto buffer = buffers[i];
+
+ if (buffer == AL_NONE)
+ {
+ continue;
+ }
+
+ const auto al_buffer = LookupBuffer(device, buffer);
+
+ if (!al_buffer)
+ {
+ ERR(EAX_PREFIX "Invalid buffer ID %u.\n", buffer);
+ return ALC_FALSE;
+ }
+
+ if (al_buffer->eax_x_ram_is_dirty)
+ {
+ ERR(EAX_PREFIX "Buffer %u has audio data.\n", buffer);
+ return ALC_FALSE;
+ }
+ }
+
+ // Update the mode.
+ //
+ for (auto i = 0; i < n; ++i)
+ {
+ const auto buffer = buffers[i];
+
+ if (buffer == AL_NONE)
+ {
+ continue;
+ }
+
+ const auto al_buffer = LookupBuffer(device, buffer);
+ assert(al_buffer);
+ assert(!al_buffer->eax_x_ram_is_dirty);
+
+ al_buffer->eax_x_ram_mode = value;
+ }
+
+ return AL_TRUE;
+
+#undef EAX_PREFIX
+}
+END_API_FUNC
+
+ALenum AL_APIENTRY EAXGetBufferMode(
+ ALuint buffer,
+ ALint* pReserved)
+START_API_FUNC
+{
+#define EAX_PREFIX "[EAXGetBufferMode] "
+
+ if (buffer == AL_NONE)
+ {
+ ERR(EAX_PREFIX "%s\n", "Null AL buffer.");
+ return AL_NONE;
+ }
+
+ if (pReserved)
+ {
+ ERR(EAX_PREFIX "%s\n", "Non-null reserved parameter.");
+ return AL_NONE;
+ }
+
+ const auto context = ContextRef{GetContextRef()};
+
+ if (!context)
+ {
+ ERR(EAX_PREFIX "%s\n", "No current context.");
+ return AL_NONE;
+ }
+
+ if (!eax_g_is_enabled)
+ {
+ ERR(EAX_PREFIX "%s\n", "EAX not enabled.");
+ return AL_NONE;
+ }
+
+ auto device = context->mALDevice.get();
+ std::lock_guard<std::mutex> device_lock{device->BufferLock};
+
+ const auto al_buffer = LookupBuffer(device, buffer);
+
+ if (!al_buffer)
+ {
+ ERR(EAX_PREFIX "Invalid buffer ID %u.\n", buffer);
+ return AL_NONE;
+ }
+
+ return al_buffer->eax_x_ram_mode;
+
+#undef EAX_PREFIX
+}
+END_API_FUNC
+
+
+#endif // ALSOFT_EAX