Skip to content

Commit da1704a

Browse files
bjornsezero
authored andcommitted
stb_vorbis: Use a buffer to cache SDL_RWops reads
Requesting the data one byte at a time can be prohibitively expensive, especially when the SDL_RWops isn't backed by constant memory but routed through PhysicsFS for example. This change introduces a 2kb buffer, which feels small enough to not add too much overhead and is the same size as used by libvorbisfile. In my measurements, using a larger buffer no longer made a significant difference when starting to play an OGG file. Testing with an uncompressed OGG file read from zip file, timing the call to Mix_LoadMUS_RW: * No buffer: ~ 47 ms * 10 bytes: ~ 5.2 ms * 100 bytes: ~ 1.1 ms * 1 kb: ~ 0.62 ms * 2 kb: ~ 0.6 ms * 8 kb: ~ 0.58 ms When using the libvorbisfile backend it takes about 0.2 ms.
1 parent 393684a commit da1704a

File tree

1 file changed

+61
-14
lines changed

1 file changed

+61
-14
lines changed

src/codecs/stb_vorbis/stb_vorbis.h

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_cl
308308
#ifdef STB_VORBIS_SDL
309309
extern stb_vorbis * stb_vorbis_open_rwops_section(SDL_RWops *rwops, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length);
310310
extern stb_vorbis * stb_vorbis_open_rwops(SDL_RWops *rwops, int close_on_free, int *error, const stb_vorbis_alloc *alloc);
311+
#define RWOPS_BUFFER_SIZE 2048
311312
#endif
312313

313314
extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
@@ -836,6 +837,10 @@ struct stb_vorbis
836837
#ifdef STB_VORBIS_SDL
837838
SDL_RWops *rwops;
838839
uint32 rwops_start;
840+
uint32 rwops_virtual_pos;
841+
uint32 rwops_buffer_pos;
842+
uint32 rwops_buffer_fill;
843+
uint8 rwops_buffer[RWOPS_BUFFER_SIZE];
839844
int close_on_free;
840845
#endif
841846

@@ -1400,9 +1405,13 @@ static int STBV_CDECL point_compare(const void *p, const void *q)
14001405
static uint8 get8(vorb *z)
14011406
{
14021407
#ifdef STB_VORBIS_SDL
1403-
uint8 c;
1404-
if (SDL_RWread(z->rwops, &c, 1, 1) != 1) { z->eof = TRUE; return 0; }
1405-
return c;
1408+
if (z->rwops_buffer_pos >= z->rwops_buffer_fill) {
1409+
z->rwops_buffer_fill = SDL_RWread(z->rwops, z->rwops_buffer, 1, RWOPS_BUFFER_SIZE);
1410+
z->rwops_buffer_pos = 0;
1411+
if (z->rwops_buffer_fill == 0) { z->eof = TRUE; return 0; }
1412+
}
1413+
z->rwops_virtual_pos++;
1414+
return z->rwops_buffer[z->rwops_buffer_pos++];
14061415

14071416
#else
14081417
if (USE_MEMORY(z)) {
@@ -1433,9 +1442,28 @@ static uint32 get32(vorb *f)
14331442
static int getn(vorb *z, uint8 *data, int n)
14341443
{
14351444
#ifdef STB_VORBIS_SDL
1436-
if (SDL_RWread(z->rwops, data, n, 1) == 1) return 1;
1437-
z->eof = 1;
1438-
return 0;
1445+
while (n > 0) {
1446+
int chunk;
1447+
1448+
if (z->rwops_buffer_pos >= z->rwops_buffer_fill) {
1449+
z->rwops_buffer_fill = SDL_RWread(z->rwops, z->rwops_buffer, 1, RWOPS_BUFFER_SIZE);
1450+
z->rwops_buffer_pos = 0;
1451+
if (z->rwops_buffer_fill == 0) {
1452+
z->eof = 1;
1453+
return 0;
1454+
}
1455+
}
1456+
1457+
chunk = z->rwops_buffer_fill - z->rwops_buffer_pos;
1458+
if (chunk > n) chunk = n;
1459+
1460+
memcpy(data, z->rwops_buffer + z->rwops_buffer_pos, chunk);
1461+
z->rwops_buffer_pos += chunk;
1462+
z->rwops_virtual_pos += chunk;
1463+
data += chunk;
1464+
n -= chunk;
1465+
}
1466+
return 1;
14391467

14401468
#else
14411469
if (USE_MEMORY(z)) {
@@ -1456,11 +1484,12 @@ static int getn(vorb *z, uint8 *data, int n)
14561484
#endif
14571485
}
14581486

1487+
static int set_file_offset(stb_vorbis *f, unsigned int loc);
1488+
14591489
static void skip(vorb *z, int n)
14601490
{
14611491
#ifdef STB_VORBIS_SDL
1462-
SDL_RWseek(z->rwops, n, RW_SEEK_CUR);
1463-
1492+
set_file_offset(z, z->rwops_virtual_pos + n);
14641493
#else
14651494
if (USE_MEMORY(z)) {
14661495
z->stream += n;
@@ -1485,17 +1514,31 @@ static int set_file_offset(stb_vorbis *f, unsigned int loc)
14851514
f->eof = 0;
14861515

14871516
#ifdef STB_VORBIS_SDL
1488-
if (loc + f->rwops_start < loc || loc >= 0x80000000) {
1489-
loc = 0x7fffffff;
1517+
{ unsigned int rwops_pos;
1518+
uint32 buffer_start = f->rwops_virtual_pos - f->rwops_buffer_pos;
1519+
uint32 buffer_end = buffer_start + f->rwops_buffer_fill;
1520+
f->rwops_virtual_pos = loc;
1521+
1522+
// Move within buffer if possible
1523+
if (loc >= buffer_start && loc < buffer_end)
1524+
{
1525+
f->rwops_buffer_pos = loc - buffer_start;
1526+
return 1;
1527+
}
1528+
1529+
rwops_pos = loc + f->rwops_start;
1530+
if (rwops_pos < loc || loc >= 0x80000000) {
1531+
rwops_pos = 0x7fffffff;
14901532
f->eof = 1;
1491-
} else {
1492-
loc += f->rwops_start;
14931533
}
1494-
if (SDL_RWseek(f->rwops, loc, RW_SEEK_SET) != -1)
1534+
1535+
f->rwops_buffer_pos = f->rwops_buffer_fill = 0; // Invalidate buffer
1536+
if (SDL_RWseek(f->rwops, rwops_pos, RW_SEEK_SET) != -1)
14951537
return 1;
14961538
f->eof = 1;
14971539
SDL_RWseek(f->rwops, f->rwops_start, RW_SEEK_END);
14981540
return 0;
1541+
}
14991542

15001543
#else
15011544
if (USE_MEMORY(f)) {
@@ -4440,6 +4483,10 @@ static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z)
44404483
#ifdef STB_VORBIS_SDL
44414484
p->close_on_free = FALSE;
44424485
p->rwops = NULL;
4486+
p->rwops_start = 0;
4487+
p->rwops_virtual_pos = 0;
4488+
p->rwops_buffer_pos = 0;
4489+
p->rwops_buffer_fill = 0;
44434490
#endif
44444491
#ifndef STB_VORBIS_NO_STDIO
44454492
p->close_on_free = FALSE;
@@ -4711,7 +4758,7 @@ unsigned int stb_vorbis_get_file_offset(stb_vorbis *f)
47114758
if (f->push_mode) return 0;
47124759
#endif
47134760
#ifdef STB_VORBIS_SDL
4714-
return (unsigned int) (SDL_RWtell(f->rwops) - f->rwops_start);
4761+
return f->rwops_virtual_pos;
47154762
#else
47164763
if (USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start);
47174764
#endif

0 commit comments

Comments
 (0)