summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <bjorn@lindeijer.nl>2025-02-28 08:37:52 +0100
committerThorbjørn Lindeijer <bjorn@lindeijer.nl>2025-02-28 08:41:27 +0100
commitddd86b80a2090d40e61126d81c69fad6a0545a14 (patch)
tree629b98a222d8a7bceeb7966021347fdf83d076e0 /src
parent81a2f0829a9a0a0d524028fbff42273387078613 (diff)
downloadmana-ddd86b80a2090d40e61126d81c69fad6a0545a14.tar.gz
mana-ddd86b80a2090d40e61126d81c69fad6a0545a14.tar.bz2
mana-ddd86b80a2090d40e61126d81c69fad6a0545a14.tar.xz
mana-ddd86b80a2090d40e61126d81c69fad6a0545a14.zip
Replaced buffered SDL_RWops wrapper with PHYSFS_setBuffer
This removes the buffered SDL_RWops functionality that was just added in 51b0c3239265ddee2d1bf445f873299cc8193ab9. We just call PHYSFS_setBuffer instead. Using the PhysicsFS buffer is a little bit slower, likely because it operates at a lower level, but it is fast enough for our purposes. Uncompressed music files loaded from ZIP files can start playing in about 1-2 ms. I've also landed a fix for the problem in SDL_mixer, which works even better in any case: https://github.com/libsdl-org/SDL_mixer/pull/671
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/utils/bufferedrwops.c184
-rw-r--r--src/utils/bufferedrwops.h30
-rw-r--r--src/utils/filesystem.h22
4 files changed, 13 insertions, 225 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f47cbf5b..b7cfe091 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -368,8 +368,6 @@ set(SRCS
resources/wallpaper.h
utils/base64.cpp
utils/base64.h
- utils/bufferedrwops.c
- utils/bufferedrwops.h
utils/copynpaste.cpp
utils/copynpaste.h
utils/dtor.h
diff --git a/src/utils/bufferedrwops.c b/src/utils/bufferedrwops.c
deleted file mode 100644
index e12f8b5b..00000000
--- a/src/utils/bufferedrwops.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Buffered SDL_RWops implementation
- * Copyright (C) 2025 Thorbjørn Lindeijer
- *
- * Written as part of a conversation between a human and an AI assistant
- * on GitHub Copilot Chat.
- *
- * This code is released into the public domain. You may use it freely
- * for any purpose, including commercial applications.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include "bufferedrwops.h"
-
-#include <string.h>
-
-#define BUFFER_SIZE 2048
-
-typedef struct BufferedRWops {
- SDL_RWops* source; // The underlying RWops we're wrapping
- size_t bufferPos; // Current position within buffer
- size_t bufferFill; // How much valid data is in buffer
- Sint64 virtualPos; // Current virtual stream position
- Uint8 buffer[BUFFER_SIZE]; // Our read-ahead buffer
-} BufferedRWops;
-
-static Sint64 SDLCALL buffered_size(SDL_RWops* context) {
- BufferedRWops* br = (BufferedRWops*)context->hidden.unknown.data1;
- return SDL_RWsize(br->source);
-}
-
-static Sint64 SDLCALL buffered_seek(SDL_RWops* context, Sint64 offset, int whence) {
- BufferedRWops* br = (BufferedRWops*)context->hidden.unknown.data1;
- Sint64 newPos;
-
- // Calculate new position
- switch (whence) {
- case RW_SEEK_SET:
- newPos = offset;
- break;
- case RW_SEEK_CUR:
- newPos = br->virtualPos + offset;
- break;
- case RW_SEEK_END: {
- Sint64 size = SDL_RWsize(br->source);
- if (size < 0) return -1;
- newPos = size + offset;
- break;
- }
- default:
- SDL_SetError("Invalid whence value");
- return -1;
- }
-
- if (newPos < 0) {
- SDL_SetError("Attempt to seek before start of file");
- return -1;
- }
-
- // Check if new position is within our buffer
- Sint64 bufferStart = br->virtualPos - br->bufferPos;
- Sint64 bufferEnd = bufferStart + br->bufferFill;
-
- if (newPos >= bufferStart && newPos < bufferEnd) {
- // Position is within buffer - just update buffer position
- br->bufferPos = (size_t)(newPos - bufferStart);
- } else {
- // Position is outside buffer - need to seek in source
- if (SDL_RWseek(br->source, newPos, RW_SEEK_SET) < 0) {
- return -1;
- }
- br->bufferPos = 0;
- br->bufferFill = 0;
- }
-
- br->virtualPos = newPos;
- return newPos;
-}
-
-static size_t SDLCALL buffered_read(SDL_RWops* context, void* dst, size_t size, size_t maxnum) {
- BufferedRWops* br = (BufferedRWops*)context->hidden.unknown.data1;
- size_t total = size * maxnum;
- size_t copied = 0;
-
- // Handle single byte reads separately since it is a common case when
- // SDL_mixer uses stb_vorbis.
- if (total == 1 && br->bufferPos < br->bufferFill) {
- *(Uint8*)dst = br->buffer[br->bufferPos];
- ++br->bufferPos;
- ++br->virtualPos;
- return 1;
- }
-
- while (copied < total) {
- size_t remaining = total - copied;
-
- // If buffer is empty or exhausted, try to fill it
- if (br->bufferPos >= br->bufferFill) {
- // If we want to read more than the buffer size, bypass the buffer
- if (remaining >= BUFFER_SIZE) {
- size_t read = SDL_RWread(br->source, dst + copied, 1, remaining);
- copied += read;
- br->virtualPos += read;
- break; // Nothing more to read
- }
-
- br->bufferPos = 0;
- br->bufferFill = SDL_RWread(br->source, br->buffer, 1, BUFFER_SIZE);
-
- if (br->bufferFill == 0)
- break; // EOF or error
- }
-
- // Copy what we can from the buffer
- size_t available = br->bufferFill - br->bufferPos;
- size_t toCopy = remaining < available ? remaining : available;
-
- memcpy(dst + copied, br->buffer + br->bufferPos, toCopy);
- br->bufferPos += toCopy;
- copied += toCopy;
- br->virtualPos += toCopy;
- }
-
- return copied / size;
-}
-
-static size_t SDLCALL buffered_write(SDL_RWops* context, const void* ptr, size_t size, size_t num) {
- SDL_SetError("Write operations not supported on buffered read-only RWops");
- return 0;
-}
-
-static int SDLCALL buffered_close(SDL_RWops* context) {
- if (context) {
- BufferedRWops* br = (BufferedRWops*)context->hidden.unknown.data1;
- if (br) {
- if (br->source) {
- SDL_RWclose(br->source);
- }
- SDL_free(br);
- }
- SDL_FreeRW(context);
- }
- return 0;
-}
-
-SDL_RWops* createBufferedRWops(SDL_RWops* source) {
- if (!source) {
- SDL_SetError("NULL source RWops");
- return NULL;
- }
-
- BufferedRWops* br = (BufferedRWops*)SDL_malloc(sizeof(BufferedRWops));
- if (!br) {
- SDL_SetError("Out of memory");
- return NULL;
- }
-
- br->source = source;
- br->bufferPos = 0;
- br->bufferFill = 0;
- br->virtualPos = 0;
-
- SDL_RWops* rw = SDL_AllocRW();
- if (!rw) {
- SDL_free(br);
- return NULL;
- }
-
- rw->size = buffered_size;
- rw->seek = buffered_seek;
- rw->read = buffered_read;
- rw->write = buffered_write;
- rw->close = buffered_close;
- rw->hidden.unknown.data1 = br;
-
- return rw;
-}
diff --git a/src/utils/bufferedrwops.h b/src/utils/bufferedrwops.h
deleted file mode 100644
index bba29467..00000000
--- a/src/utils/bufferedrwops.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Buffered SDL_RWops implementation
- * Copyright (C) 2025 Thorbjørn Lindeijer
- *
- * Written as part of a conversation between a human and an AI assistant
- * on GitHub Copilot Chat.
- *
- * This code is released into the public domain. You may use it freely
- * for any purpose, including commercial applications.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include "SDL.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-SDL_RWops* createBufferedRWops(SDL_RWops* source);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/src/utils/filesystem.h b/src/utils/filesystem.h
index 0363cd22..3474e7c4 100644
--- a/src/utils/filesystem.h
+++ b/src/utils/filesystem.h
@@ -23,7 +23,6 @@
// Suppress deprecation warnings for PHYSFS_getUserDir
#define PHYSFS_DEPRECATED
-#include "utils/bufferedrwops.h"
#include "utils/physfsrwops.h"
#include <optional>
@@ -267,18 +266,23 @@ inline SDL_RWops *openRWops(const std::string &path)
/**
* Creates a buffered SDL_RWops.
*
- * Used to workaround a performance issue when SDL_mixer is using stb_vorbis.
- * The overhead of calling PHYSFS_readBytes each time is too high because
- * stb_vorbis requests the file one byte at a time.
+ * Used to workaround a performance issue when SDL_mixer is using stb_vorbis,
+ * in which case the file is read one byte at a time.
*
* See https://github.com/libsdl-org/SDL_mixer/issues/670
*/
-inline SDL_RWops *openBufferedRWops(const std::string &path)
+inline SDL_RWops *openBufferedRWops(const std::string &path,
+ PHYSFS_uint64 bufferSize = 2048)
{
- auto rw = PHYSFSRWOPS_openRead(path.c_str());
- if (auto buffered = createBufferedRWops(rw))
- return buffered;
- return rw;
+ if (auto file = PHYSFS_openRead(path.c_str()))
+ {
+ PHYSFS_setBuffer(file, bufferSize);
+ if (auto rw = PHYSFSRWOPS_makeRWops(file))
+ return rw;
+ else
+ PHYSFS_close(file);
+ }
+ return nullptr;
}
inline void *loadFile(const std::string &path, size_t &datasize)