From 6c45d6668ba73cbe131ef21fb53b8320ddeae622 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Mar 2012 10:33:06 -0700 Subject: [PATCH] Cache OpenAL buffers for easy reuse --- apps/openmw/mwsound/openal_output.cpp | 118 ++++++++++++++++---------- apps/openmw/mwsound/openal_output.hpp | 14 +++ 2 files changed, 87 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 468c1565d7..a0884fb40f 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -313,35 +313,8 @@ public: virtual void stop(); virtual bool isPlaying(); virtual void update(const float *pos); - - static ALuint LoadBuffer(DecoderPtr decoder); }; -ALuint OpenAL_Sound::LoadBuffer(DecoderPtr decoder) -{ - int srate; - ChannelConfig chans; - SampleType type; - ALenum format; - - decoder->getInfo(&srate, &chans, &type); - format = getALFormat(chans, type); - - std::vector data(32768); - size_t got, total = 0; - while((got=decoder->read(&data[total], data.size()-total)) > 0) - { - total += got; - data.resize(total*2); - } - data.resize(total); - - ALuint buf=0; - alGenBuffers(1, &buf); - alBufferData(buf, format, &data[0], total, srate); - return buf; -} - OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf) : mOutput(output), mSource(src), mBuffer(buf) { @@ -352,8 +325,7 @@ OpenAL_Sound::~OpenAL_Sound() alSourcei(mSource, AL_BUFFER, 0); mOutput.mFreeSources.push_back(mSource); - alDeleteBuffers(1, &mBuffer); - alGetError(); + mOutput.bufferFinished(mBuffer); } void OpenAL_Sound::stop() @@ -431,6 +403,15 @@ void OpenAL_Output::deinit() alDeleteSources(mFreeSources.size(), mFreeSources.data()); mFreeSources.clear(); } + + mBufferRefs.clear(); + mUnusedBuffers.clear(); + while(!mBufferCache.empty()) + { + alDeleteBuffers(1, &mBufferCache.begin()->second); + mBufferCache.erase(mBufferCache.begin()); + } + alcMakeContextCurrent(0); if(mContext) alcDestroyContext(mContext); @@ -441,6 +422,63 @@ void OpenAL_Output::deinit() } +ALuint OpenAL_Output::getBuffer(const std::string &fname) +{ + ALuint buf = 0; + + NameMap::iterator iditer = mBufferCache.find(fname); + if(iditer != mBufferCache.end()) + { + buf = iditer->second; + if(mBufferRefs[buf]++ == 0) + { + IDDq::iterator iter = std::find(mUnusedBuffers.begin(), + mUnusedBuffers.end(), buf); + if(iter != mUnusedBuffers.end()) + mUnusedBuffers.erase(iter); + } + + return buf; + } + throwALerror(); + + int srate; + ChannelConfig chans; + SampleType type; + ALenum format; + + DecoderPtr decoder = mManager.getDecoder(); + decoder->open(fname); + decoder->getInfo(&srate, &chans, &type); + format = getALFormat(chans, type); + + std::vector data(32768); + size_t got, total = 0; + while((got=decoder->read(&data[total], data.size()-total)) > 0) + { + total += got; + data.resize(total*2); + } + data.resize(total); + decoder->close(); + + alGenBuffers(1, &buf); + throwALerror(); + + alBufferData(buf, format, &data[0], total, srate); + mBufferCache[fname] = buf; + mBufferRefs[buf] = 1; + + return buf; +} + +void OpenAL_Output::bufferFinished(ALuint buf) +{ + if(mBufferRefs.at(buf)-- == 1) + mUnusedBuffers.push_back(buf); +} + + Sound* OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, bool loop) { throwALerror(); @@ -455,19 +493,14 @@ Sound* OpenAL_Output::playSound(const std::string &fname, float volume, float pi try { - DecoderPtr decoder = mManager.getDecoder(); - decoder->open(fname); - buf = OpenAL_Sound::LoadBuffer(decoder); - throwALerror(); - decoder->close(); - + buf = getBuffer(fname); sound.reset(new OpenAL_Sound(*this, src, buf)); } catch(std::exception &e) { mFreeSources.push_back(src); - if(alIsBuffer(buf)) - alDeleteBuffers(1, &buf); + if(buf && alIsBuffer(buf)) + bufferFinished(buf); alGetError(); throw; } @@ -509,19 +542,14 @@ Sound* OpenAL_Output::playSound3D(const std::string &fname, const float *pos, fl try { - DecoderPtr decoder = mManager.getDecoder(); - decoder->open(fname); - buf = OpenAL_Sound::LoadBuffer(decoder); - throwALerror(); - decoder->close(); - + buf = getBuffer(fname); sound.reset(new OpenAL_Sound(*this, src, buf)); } catch(std::exception &e) { mFreeSources.push_back(src); - if(alIsBuffer(buf)) - alDeleteBuffers(1, &buf); + if(buf && alIsBuffer(buf)) + bufferFinished(buf); alGetError(); throw; } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index dddd1d6dc6..62ec39abaf 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include "alc.h" #include "al.h" @@ -22,6 +24,18 @@ namespace MWSound typedef std::vector IDVec; IDVec mFreeSources; + typedef std::map NameMap; + NameMap mBufferCache; + + typedef std::map IDRefMap; + IDRefMap mBufferRefs; + + typedef std::deque IDDq; + IDDq mUnusedBuffers; + + ALuint getBuffer(const std::string &fname); + void bufferFinished(ALuint buffer); + virtual void init(const std::string &devname=""); virtual void deinit();