Skip to content

Commit 532826b

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 6112667 commit 532826b

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);
@@ -834,6 +835,10 @@ struct stb_vorbis
834835
#ifdef STB_VORBIS_SDL
835836
SDL_RWops *rwops;
836837
uint32 rwops_start;
838+
uint32 rwops_virtual_pos;
839+
uint32 rwops_buffer_pos;
840+
uint32 rwops_buffer_fill;
841+
uint8 rwops_buffer[RWOPS_BUFFER_SIZE];
837842
int close_on_free;
838843
#endif
839844

@@ -1398,9 +1403,13 @@ static int STBV_CDECL point_compare(const void *p, const void *q)
13981403
static uint8 get8(vorb *z)
13991404
{
14001405
#ifdef STB_VORBIS_SDL
1401-
uint8 c;
1402-
if (SDL_RWread(z->rwops, &c, 1, 1) != 1) { z->eof = TRUE; return 0; }
1403-
return c;
1406+
if (z->rwops_buffer_pos >= z->rwops_buffer_fill) {
1407+
z->rwops_buffer_fill = SDL_RWread(z->rwops, z->rwops_buffer, 1, RWOPS_BUFFER_SIZE);
1408+
z->rwops_buffer_pos = 0;
1409+
if (z->rwops_buffer_fill == 0) { z->eof = TRUE; return 0; }
1410+
}
1411+
z->rwops_virtual_pos++;
1412+
return z->rwops_buffer[z->rwops_buffer_pos++];
14041413

14051414
#else
14061415
if (USE_MEMORY(z)) {
@@ -1431,9 +1440,28 @@ static uint32 get32(vorb *f)
14311440
static int getn(vorb *z, uint8 *data, int n)
14321441
{
14331442
#ifdef STB_VORBIS_SDL
1434-
if (SDL_RWread(z->rwops, data, n, 1) == 1) return 1;
1435-
z->eof = 1;
1436-
return 0;
1443+
while (n > 0) {
1444+
int chunk;
1445+
1446+
if (z->rwops_buffer_pos >= z->rwops_buffer_fill) {
1447+
z->rwops_buffer_fill = SDL_RWread(z->rwops, z->rwops_buffer, 1, RWOPS_BUFFER_SIZE);
1448+
z->rwops_buffer_pos = 0;
1449+
if (z->rwops_buffer_fill == 0) {
1450+
z->eof = 1;
1451+
return 0;
1452+
}
1453+
}
1454+
1455+
chunk = z->rwops_buffer_fill - z->rwops_buffer_pos;
1456+
if (chunk > n) chunk = n;
1457+
1458+
memcpy(data, z->rwops_buffer + z->rwops_buffer_pos, chunk);
1459+
z->rwops_buffer_pos += chunk;
1460+
z->rwops_virtual_pos += chunk;
1461+
data += chunk;
1462+
n -= chunk;
1463+
}
1464+
return 1;
14371465

14381466
#else
14391467
if (USE_MEMORY(z)) {
@@ -1454,11 +1482,12 @@ static int getn(vorb *z, uint8 *data, int n)
14541482
#endif
14551483
}
14561484

1485+
static int set_file_offset(stb_vorbis *f, unsigned int loc);
1486+
14571487
static void skip(vorb *z, int n)
14581488
{
14591489
#ifdef STB_VORBIS_SDL
1460-
SDL_RWseek(z->rwops, n, RW_SEEK_CUR);
1461-
1490+
set_file_offset(z, z->rwops_virtual_pos + n);
14621491
#else
14631492
if (USE_MEMORY(z)) {
14641493
z->stream += n;
@@ -1483,17 +1512,31 @@ static int set_file_offset(stb_vorbis *f, unsigned int loc)
14831512
f->eof = 0;
14841513

14851514
#ifdef STB_VORBIS_SDL
1486-
if (loc + f->rwops_start < loc || loc >= 0x80000000) {
1487-
loc = 0x7fffffff;
1515+
{ unsigned int rwops_pos;
1516+
uint32 buffer_start = f->rwops_virtual_pos - f->rwops_buffer_pos;
1517+
uint32 buffer_end = buffer_start + f->rwops_buffer_fill;
1518+
f->rwops_virtual_pos = loc;
1519+
1520+
// Move within buffer if possible
1521+
if (loc >= buffer_start && loc < buffer_end)
1522+
{
1523+
f->rwops_buffer_pos = loc - buffer_start;
1524+
return 1;
1525+
}
1526+
1527+
rwops_pos = loc + f->rwops_start;
1528+
if (rwops_pos < loc || loc >= 0x80000000) {
1529+
rwops_pos = 0x7fffffff;
14881530
f->eof = 1;
1489-
} else {
1490-
loc += f->rwops_start;
14911531
}
1492-
if (SDL_RWseek(f->rwops, loc, RW_SEEK_SET) != -1)
1532+
1533+
f->rwops_buffer_pos = f->rwops_buffer_fill = 0; // Invalidate buffer
1534+
if (SDL_RWseek(f->rwops, rwops_pos, RW_SEEK_SET) != -1)
14931535
return 1;
14941536
f->eof = 1;
14951537
SDL_RWseek(f->rwops, f->rwops_start, RW_SEEK_END);
14961538
return 0;
1539+
}
14971540

14981541
#else
14991542
if (USE_MEMORY(f)) {
@@ -4438,6 +4481,10 @@ static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z)
44384481
#ifdef STB_VORBIS_SDL
44394482
p->close_on_free = FALSE;
44404483
p->rwops = NULL;
4484+
p->rwops_start = 0;
4485+
p->rwops_virtual_pos = 0;
4486+
p->rwops_buffer_pos = 0;
4487+
p->rwops_buffer_fill = 0;
44414488
#endif
44424489
#ifndef STB_VORBIS_NO_STDIO
44434490
p->close_on_free = FALSE;
@@ -4709,7 +4756,7 @@ unsigned int stb_vorbis_get_file_offset(stb_vorbis *f)
47094756
if (f->push_mode) return 0;
47104757
#endif
47114758
#ifdef STB_VORBIS_SDL
4712-
return (unsigned int) (SDL_RWtell(f->rwops) - f->rwops_start);
4759+
return f->rwops_virtual_pos;
47134760
#else
47144761
if (USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start);
47154762
#endif

0 commit comments

Comments
 (0)