diff --git a/include/QF/zone.h b/include/QF/zone.h index 8cbcd74fe..24989ca5a 100644 --- a/include/QF/zone.h +++ b/include/QF/zone.h @@ -118,9 +118,15 @@ void *Hunk_TempAlloc (int size); void Hunk_Check (void); +struct cache_user_s; +typedef void * (*cache_allocator_t) (struct cache_user_s *c, int size, const char *name); +typedef void (*cache_loader_t) (struct cache_user_s *cache, cache_allocator_t allocator); + typedef struct cache_user_s { void *data; + char *filename; + cache_loader_t loader; } cache_user_t; void Cache_Flush (void); @@ -137,6 +143,11 @@ void *Cache_Alloc (cache_user_t *c, int size, const char *name); void Cache_Report (void); +void Cache_Add (cache_user_t *c, const char *filename, cache_loader_t loader); +void Cache_Remove (cache_user_t *c); +void *Cache_Get (cache_user_t *c); +void Cache_Release (cache_user_t *c); + /* Modes, pick one */ #define QA_NOFAIL 1 #define QA_LATEFAIL 2 @@ -147,12 +158,13 @@ void Cache_Report (void); /* Flags, OR them with the mode */ #define QA_ZEROED 4 -extern size_t (*Qalloc_callback) (size_t size); +extern size_t (*QA_alloc_callback) (size_t size); -void *Qalloc (void *ptr, size_t size, unsigned modes); -void *Qmalloc (size_t size); -void *Qcalloc (size_t nmemb, size_t size); -void *Qrealloc (void *ptr, size_t size); -void Qfree (void *ptr); +void *QA_alloc (void *ptr, size_t size, unsigned modes); +void *QA_malloc (size_t size); +void *QA_calloc (size_t nmemb, size_t size); +void *QA_realloc (void *ptr, size_t size); +void QA_free (void *ptr); +char *QA_strdup (const char *s); #endif // __zone_h diff --git a/libs/audio/renderer/snd_dma.c b/libs/audio/renderer/snd_dma.c index 6cf31dc33..89a330ac5 100644 --- a/libs/audio/renderer/snd_dma.c +++ b/libs/audio/renderer/snd_dma.c @@ -59,9 +59,9 @@ void SND_StopAllSoundsC (void); void SND_Update_ (void); sfx_t *SND_PrecacheSound (const char *name); -sfxcache_t *SND_LoadSound (sfx_t *s); void SND_ClearBuffer (void); void SND_PaintChannels (int endtime); +void SND_CallbackLoad (struct cache_user_s *cache, cache_allocator_t allocator); void SND_Init_Cvars (); @@ -331,6 +331,7 @@ SND_FindName (const char *name) sfx = &known_sfx[i]; strcpy (sfx->name, name); + Cache_Add (&sfx->cache, name, SND_CallbackLoad); num_sfx++; @@ -360,8 +361,10 @@ SND_PrecacheSound (const char *name) sfx = SND_FindName (name); // cache it in - if (precache->int_val) - SND_LoadSound (sfx); + if (precache->int_val) { + Cache_Get (&sfx->cache); + Cache_Release (&sfx->cache); + } return sfx; } @@ -417,7 +420,6 @@ SND_Spatialize (channel_t *ch) int phase; // in samples vec_t lscale, rscale, scale; vec3_t source_vec; - sfx_t *snd; // anything coming from the view entity will always be full volume if (ch->entnum == *plugin_info_snd_render_data.viewentity) { @@ -428,7 +430,6 @@ SND_Spatialize (channel_t *ch) } // calculate stereo seperation and distance attenuation - snd = ch->sfx; VectorSubtract (ch->origin, listener_origin, source_vec); dist = VectorNormalize (source_vec) * ch->dist_mult; @@ -499,7 +500,7 @@ SND_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, return; // not audible at all // new channel - sc = SND_LoadSound (sfx); + sc = Cache_Get (&sfx->cache); if (!sc) { target_chan->sfx = NULL; return; // couldn't load the sound's data @@ -508,6 +509,7 @@ SND_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, target_chan->sfx = sfx; target_chan->pos = 0.0; target_chan->end = paintedtime + sc->length; + Cache_Release (&sfx->cache); // if an identical sound has also been started this frame, offset the pos // a bit to keep it from just making the first one louder @@ -613,12 +615,13 @@ SND_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) ss = &channels[total_channels]; total_channels++; - sc = SND_LoadSound (sfx); + sc = Cache_Get (&sfx->cache); if (!sc) return; if (sc->loopstart == -1) { Con_Printf ("Sound %s not looped\n", sfx->name); + Cache_Release (&sfx->cache); return; } @@ -627,6 +630,7 @@ SND_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) ss->master_vol = vol; ss->dist_mult = (attenuation / 64) / sound_nominal_clip_dist; ss->end = paintedtime + sc->length; + Cache_Release (&sfx->cache); SND_Spatialize (ss); ss->oldphase = ss->phase; @@ -891,10 +895,20 @@ SND_SoundList (void) sfx_t *sfx; sfxcache_t *sc; int size, total; + int load; + + if (Cmd_Argc() >= 2 && !strcmp (Cmd_Argv (1), "known")) + load = 1; + else + load = 0; total = 0; for (sfx = known_sfx, i = 0; i < num_sfx; i++, sfx++) { - sc = Cache_Check (&sfx->cache); + if (load) + sc = Cache_Get (&sfx->cache); + else + sc = Cache_Check (&sfx->cache); + if (!sc) continue; size = sc->length * sc->width * (sc->stereo + 1); @@ -904,6 +918,9 @@ SND_SoundList (void) else Con_Printf (" "); Con_Printf ("(%2db) %6i : %s\n", sc->width * 8, size, sfx->name); + + if (load) + Cache_Release (&sfx->cache); } Con_Printf ("Total resident: %i\n", total); } diff --git a/libs/audio/renderer/snd_mem.c b/libs/audio/renderer/snd_mem.c index 8095d4d42..6e9f40894 100644 --- a/libs/audio/renderer/snd_mem.c +++ b/libs/audio/renderer/snd_mem.c @@ -46,25 +46,21 @@ int cache_full_cycle; byte *SND_Alloc (int size); -wavinfo_t SND_GetWavinfo (char *name, byte * wav, int wavlength); +wavinfo_t SND_GetWavinfo (const char *name, byte * wav, int wavlength); +sfxcache_t *SND_LoadSound (cache_user_t *cache, const char *name, cache_allocator_t allocator); void -SND_ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte * data) +SND_ResampleSfx (sfxcache_t *sc, int inrate, int inwidth, byte * data) { int outcount; int srcsample; float stepscale; int i; int sample, samplefrac, fracstep; - sfxcache_t *sc; short *is, *os; unsigned char *ib, *ob; - sc = Cache_Check (&sfx->cache); - if (!sc) - return; - is = (short *) data; os = (short *) sc->data; ib = data; @@ -161,24 +157,19 @@ SND_ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte * data) //============================================================================= sfxcache_t * -SND_LoadSound (sfx_t *s) +SND_LoadSound (cache_user_t *cache, const char *name, cache_allocator_t allocator) { - char namebuffer[256]; - byte *data; - wavinfo_t info; - int len; - float stepscale; + char namebuffer[256]; + byte *data; + wavinfo_t info; + int len; + float stepscale; sfxcache_t *sc; - byte stackbuf[1 * 1024]; // avoid dirtying the cache heap - - // see if still in memory - sc = Cache_Check (&s->cache); - if (sc) - return sc; + byte stackbuf[1 * 1024]; // avoid dirtying the cache heap // load it in strcpy (namebuffer, "sound/"); - strncat (namebuffer, s->name, sizeof (namebuffer) - strlen (namebuffer)); + strncat (namebuffer, name, sizeof (namebuffer) - strlen (namebuffer)); data = COM_LoadStackFile (namebuffer, stackbuf, sizeof (stackbuf)); @@ -187,9 +178,9 @@ SND_LoadSound (sfx_t *s) return NULL; } - info = SND_GetWavinfo (s->name, data, com_filesize); + info = SND_GetWavinfo (name, data, com_filesize); if (info.channels != 1) { - Con_Printf ("%s is a stereo sample\n", s->name); + Con_Printf ("%s is a stereo sample\n", name); return NULL; } @@ -202,7 +193,7 @@ SND_LoadSound (sfx_t *s) len = len * 2 * info.channels; } - sc = Cache_Alloc (&s->cache, len + sizeof (sfxcache_t), s->name); + sc = allocator (cache, len + sizeof (sfxcache_t), name); if (!sc) return NULL; @@ -213,11 +204,18 @@ SND_LoadSound (sfx_t *s) sc->width = info.width; sc->stereo = info.channels; - SND_ResampleSfx (s, sc->speed, sc->width, data + info.dataofs); + SND_ResampleSfx (sc, sc->speed, sc->width, data + info.dataofs); return sc; } +void +SND_CallbackLoad (struct cache_user_s *cache, cache_allocator_t allocator) +{ + if (!SND_LoadSound (cache, cache->filename, allocator)) + Sys_Error ("SND_CallbackLoad: load failed!\n"); +} + /* WAV loading */ byte *data_p; @@ -300,7 +298,7 @@ SND_DumpChunks (void) } wavinfo_t -SND_GetWavinfo (char *name, byte * wav, int wavlength) +SND_GetWavinfo (const char *name, byte * wav, int wavlength) { wavinfo_t info; int i; diff --git a/libs/audio/renderer/snd_mix.c b/libs/audio/renderer/snd_mix.c index e592f6aa5..2b9751ee7 100644 --- a/libs/audio/renderer/snd_mix.c +++ b/libs/audio/renderer/snd_mix.c @@ -57,8 +57,6 @@ int *snd_p, snd_linear_count, snd_vol; short *snd_out; void SND_WriteLinearBlastStereo16 (void); -sfxcache_t *SND_LoadSound (sfx_t *s); - #ifndef USE_INTEL_ASM void @@ -239,7 +237,7 @@ SND_PaintChannels (int endtime) continue; if (!ch->leftvol && !ch->rightvol) continue; - sc = SND_LoadSound (ch->sfx); + sc = Cache_Get (&ch->sfx->cache); if (!sc) continue; @@ -265,12 +263,15 @@ SND_PaintChannels (int endtime) ch->pos = sc->loopstart; ch->end = ltime + sc->length - ch->pos; } else { // channel just stopped + Cache_Release (&ch->sfx->cache); ch->sfx = NULL; break; } } } + if (ch->sfx) + Cache_Release (&ch->sfx->cache); } // transfer out according to DMA format diff --git a/libs/util/zone.c b/libs/util/zone.c index 6808e0ec0..a16f2f4f5 100644 --- a/libs/util/zone.c +++ b/libs/util/zone.c @@ -541,6 +541,7 @@ typedef struct cache_system_s { cache_system_t *Cache_TryAlloc (int size, qboolean nobottom); void Cache_RealFree (cache_user_t *c); void *Cache_RealCheck (cache_user_t *c); +void *Cache_RealAlloc (cache_user_t *c, int size, const char *name); cache_system_t cache_head; int cache_writelock; @@ -884,13 +885,20 @@ Cache_RealCheck (cache_user_t *c) return c->data; } -void * +void * Cache_Alloc (cache_user_t *c, int size, const char *name) { - cache_system_t *cs; void *mem; - CACHE_WRITE_LOCK; + mem = Cache_RealAlloc (c, size, name); + CACHE_WRITE_UNLOCK; + return mem; +} + +void * +Cache_RealAlloc (cache_user_t *c, int size, const char *name) +{ + cache_system_t *cs; if (c->data) Sys_Error ("Cache_Alloc: already allocated"); @@ -914,9 +922,7 @@ Cache_Alloc (cache_user_t *c, int size, const char *name) Sys_Error ("Cache_Alloc: out of memory"); } - mem = Cache_RealCheck (c); - CACHE_WRITE_UNLOCK; - return mem; + return Cache_RealCheck (c); } void @@ -956,25 +962,100 @@ Cache_Profile (void) CACHE_WRITE_UNLOCK; } -/* - Qalloc and friends -*/ +void +Cache_Add (cache_user_t *c, const char *filename, cache_loader_t loader) +{ + CACHE_WRITE_LOCK; -size_t (*Qalloc_callback) (size_t size); + if (c->data || c->filename || c->loader) + Sys_Error ("Cache_Add: cache item already exists!\n"); + + c->filename = strdup (filename); + if (!c->filename) + Sys_Error ("Cache_Add: strdup failed!\n"); + c->loader = loader; + +// c->loader (c, Cache_RealAlloc); // for debugging + + CACHE_WRITE_UNLOCK; +} + +void +Cache_Remove (cache_user_t *c) +{ + CACHE_WRITE_LOCK; + + if (!c->filename || !c->loader) + Sys_Error ("Cache_Remove: already removed!\n"); + + if (Cache_RealCheck (c)) + Cache_RealFree (c); + + free (c->filename); + c->filename = 0; + c->loader = 0; + + CACHE_WRITE_UNLOCK; +} void * -Qalloc (void *ptr, size_t size, unsigned modes) +Cache_Get (cache_user_t *c) +{ + void *mem; + CACHE_WRITE_LOCK; + + mem = Cache_RealCheck (c); + if (!mem) { + c->loader (c, Cache_RealAlloc); + mem = Cache_RealCheck (c); + } + + if (!mem) + Sys_Error ("Cache_Get: couldn't get cache!\n"); + + (((cache_system_t *)c->data) - 1)->readlock++; + + CACHE_WRITE_UNLOCK; + return mem; +} + +void +Cache_Release (cache_user_t *c) +{ + int *readlock; + CACHE_WRITE_LOCK; + readlock = &(((cache_system_t *)c->data) - 1)->readlock; + + if (!*readlock) + Sys_Error ("Cache_Release: already released!\n"); + + (*readlock)--; + +// if (!*readlock) +// Cache_RealFree (c); // for debugging + CACHE_WRITE_UNLOCK; +} + + +/* + QA_alloc and friends +*/ + +size_t (*QA_alloc_callback) (size_t size); + +void * +QA_alloc (void *ptr, size_t size, unsigned modes) { void *mem; if (modes & ~(_QA_MODEMASK | QA_ZEROED)) - Sys_Error ("Qalloc: bad modes field: %u\n", modes); + Sys_Error ("QA_alloc: bad modes field: %u\n", modes); if (size) { do { if (ptr) { if (modes & QA_ZEROED) - Sys_Error ("Qalloc: Zeroing reallocated memory not yet supported\n"); + Sys_Error ("QA_alloc: Zeroing reallocated memory not yet supported\n"); else mem = realloc (ptr, size); } else { @@ -984,49 +1065,49 @@ Qalloc (void *ptr, size_t size, unsigned modes) mem = malloc (size); } } while ((modes & _QA_MODEMASK) != QA_EARLYFAIL && !mem - && Qalloc_callback && Qalloc_callback (size)); + && QA_alloc_callback && QA_alloc_callback (size)); if (!mem && (modes & _QA_MODEMASK) == QA_NOFAIL) - Sys_Error ("Qalloc: could not allocate %d bytes!\n", size); + Sys_Error ("QA_alloc: could not allocate %d bytes!\n", size); return mem; } else { if (!ptr) - Sys_Error ("Qalloc: can't free a NULL pointers!\n"); + Sys_Error ("QA_alloc: can't free a NULL pointers!\n"); free (ptr); return 0; } } void * -Qmalloc (size_t size) +QA_malloc (size_t size) { - return Qalloc (0, size, QA_NOFAIL); + return QA_alloc (0, size, QA_NOFAIL); } void * -Qcalloc (size_t nmemb, size_t size) +QA_calloc (size_t nmemb, size_t size) { - return Qalloc (0, nmemb * size, QA_NOFAIL | QA_ZEROED); + return QA_alloc (0, nmemb * size, QA_NOFAIL | QA_ZEROED); } void * -Qrealloc (void *ptr, size_t size) +QA_realloc (void *ptr, size_t size) { - return Qalloc (ptr, size, QA_NOFAIL); + return QA_alloc (ptr, size, QA_NOFAIL); } void -Qfree (void *ptr) +QA_free (void *ptr) { - Qalloc (ptr, 0, QA_NOFAIL); + QA_alloc (ptr, 0, QA_NOFAIL); } char * -Qstrdup (const char *s) +QA_strdup (const char *s) { char *mem; - mem = Qmalloc (strlen (s) + 1); + mem = QA_malloc (strlen (s) + 1); strcpy (mem, s); return mem; }