diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp index c3e3fe286..392122c58 100644 --- a/indra/llaudio/llaudioengine_fmodex.cpp +++ b/indra/llaudio/llaudioengine_fmodex.cpp @@ -95,6 +95,28 @@ inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) return true; } +void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) +{ + if(type & FMOD_MEMORY_STREAM_DECODE) + { + llinfos << "Decode buffer size: " << size << llendl; + } + else if(type & FMOD_MEMORY_STREAM_FILE) + { + llinfos << "Strean buffer size: " << size << llendl; + } + return new char[size]; +} +void* F_STDCALL decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) +{ + memset(ptr,0,size); + return ptr; +} +void F_STDCALL decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr) +{ + delete[] (char*)ptr; +} + bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) { @@ -108,6 +130,10 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL; + result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE); + if(Check_FMOD_Error(result, "FMOD::Memory_Initialize")) + return false; + result = FMOD::System_Create(&mSystem); if(Check_FMOD_Error(result, "FMOD::System_Create")) return false; diff --git a/indra/llaudio/llstreamingaudio.h b/indra/llaudio/llstreamingaudio.h index 0e81cc530..3fb9ad4e3 100644 --- a/indra/llaudio/llstreamingaudio.h +++ b/indra/llaudio/llstreamingaudio.h @@ -58,6 +58,9 @@ class LLStreamingAudioInterface virtual const LLSD *getMetaData() = 0; virtual bool supportsWaveData() = 0; virtual bool getWaveData(float* arr, S32 count, S32 stride = 1) = 0; + + virtual bool supportsAdjustableBufferSizes(){return false;} + virtual void setBufferSizes(U32 streambuffertime, U32 decodebuffertime){}; }; #endif // LL_STREAMINGAUDIO_H diff --git a/indra/llaudio/llstreamingaudio_fmodex.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp index 6d97bcc49..c57f7d59b 100644 --- a/indra/llaudio/llstreamingaudio_fmodex.cpp +++ b/indra/llaudio/llstreamingaudio_fmodex.cpp @@ -50,7 +50,7 @@ public: const std::string& getURL() { return mInternetStreamURL; } - FMOD_OPENSTATE getOpenState(); + FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered=NULL, bool* starving=NULL, bool* diskbusy=NULL); protected: FMOD::System* mSystem; FMOD::Channel* mStreamChannel; @@ -70,11 +70,13 @@ LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) : mCurrentInternetStreamp(NULL), mFMODInternetStreamChannelp(NULL), mGain(1.0f), - mMetaData(NULL) + mMetaData(NULL), + mStarvedProgress(0), + mStarvedNoProgressFrames(0) { // Number of milliseconds of audio to buffer for the audio card. // Must be larger than the usual Second Life frame stutter time. - const U32 buffer_seconds = 5; //sec + const U32 buffer_seconds = 10; //sec const U32 estimated_bitrate = 128; //kbit/sec mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); @@ -145,7 +147,10 @@ void LLStreamingAudio_FMODEX::update() return; } - FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(); + unsigned int progress; + bool starving; + bool diskbusy; + FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy); if (open_state == FMOD_OPENSTATE_READY) { @@ -158,6 +163,7 @@ void LLStreamingAudio_FMODEX::update() // Reset volume to previously set volume setGain(getGain()); mFMODInternetStreamChannelp->setPaused(false); + mLastStarved.stop(); } } else if(open_state == FMOD_OPENSTATE_ERROR) @@ -168,6 +174,7 @@ void LLStreamingAudio_FMODEX::update() if(mFMODInternetStreamChannelp) { + llinfos << "progress = " << progress << llendl; if(!mMetaData) mMetaData = new LLSD; @@ -237,12 +244,46 @@ void LLStreamingAudio_FMODEX::update() } } } + if(starving) + { + if(!mLastStarved.getStarted()) + { + llinfos << "Stream starvation detected! Muting stream audio until it clears." << llendl; + llinfos << " (diskbusy="<setMute(true); + mStarvedProgress = progress; + mStarvedNoProgressFrames = 0; + } + else if(mStarvedProgress == progress) + { + if(++mStarvedNoProgressFrames >= 10) + { + //we got 10 consecutive updates of 0 progress made on the stream buffer. It probably stalled. + llinfos << "Stream unable to recover from starvation. Halting." << llendl; + stop(); + return; + } + } + else + { + mStarvedNoProgressFrames = 0; + mStarvedProgress = progress; + } + mLastStarved.start(); + } + else if(mLastStarved.getStarted() && mLastStarved.getElapsedTimeF32() > 5.f) + { + mLastStarved.stop(); + mFMODInternetStreamChannelp->setMute(false); + } } } } void LLStreamingAudio_FMODEX::stop() { + mLastStarved.stop(); if(mMetaData) { delete mMetaData; @@ -341,6 +382,11 @@ void LLStreamingAudio_FMODEX::setGain(F32 vol) if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp) return false; + bool muted=false; + mFMODInternetStreamChannelp->getMute(&muted); + if(muted) + return false; + static std::vector local_array(count); //Have to have an extra buffer to mix channels. Bleh. if(count > (S32)local_array.size()) //Expand the array if needed. Try to minimize allocation calls, so don't ever shrink. local_array.resize(count); @@ -442,9 +488,19 @@ bool LLAudioStreamManagerFMODEX::stopStream() } } -FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState() +FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy) { FMOD_OPENSTATE state; - mInternetStream->getOpenState(&state,NULL,NULL,NULL); + mInternetStream->getOpenState(&state,percentbuffered,starving,diskbusy); return state; } + +void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) +{ + mSystem->setStreamBufferSize(streambuffertime/1000*128*128, FMOD_TIMEUNIT_RAWBYTES); + FMOD_ADVANCEDSETTINGS settings; + memset(&settings,0,sizeof(settings)); + settings.cbsize=sizeof(settings); + settings.defaultDecodeBufferSize = decodebuffertime;//ms + mSystem->setAdvancedSettings(&settings); +} \ No newline at end of file diff --git a/indra/llaudio/llstreamingaudio_fmodex.h b/indra/llaudio/llstreamingaudio_fmodex.h index 064b266e6..46c0ea553 100644 --- a/indra/llaudio/llstreamingaudio_fmodex.h +++ b/indra/llaudio/llstreamingaudio_fmodex.h @@ -37,6 +37,7 @@ #include "stdtypes.h" // from llcommon #include "llstreamingaudio.h" +#include "lltimer.h" //Stubs class LLAudioStreamManagerFMODEX; @@ -66,6 +67,8 @@ class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface /*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing. /*virtual*/ bool supportsWaveData(){return true;} /*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1); + /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} + /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); private: FMOD::System *mSystem; @@ -76,6 +79,10 @@ private: std::string mURL; F32 mGain; + LLTimer mLastStarved; + unsigned int mStarvedProgress; + unsigned int mStarvedNoProgressFrames; + LLSD *mMetaData; }; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 92d095b80..cf287f98c 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -435,11 +435,7 @@ LLGLManager::LLGLManager() : mHasPointParameters(FALSE), mHasDrawBuffers(FALSE), mHasTextureRectangle(FALSE), - mHasTextureMultisample(FALSE), mHasTransformFeedback(FALSE), - mMaxSampleMaskWords(0), - mMaxColorTextureSamples(0), - mMaxDepthTextureSamples(0), mMaxIntegerSamples(0), mHasAnisotropic(FALSE), @@ -732,12 +728,10 @@ bool LLGLManager::initGL() stop_glerror(); - if (mHasTextureMultisample) + if (mHasFramebufferMultisample) { - glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &mMaxColorTextureSamples); - glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &mMaxDepthTextureSamples); glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples); - glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords); + glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples); } stop_glerror(); @@ -749,24 +743,12 @@ bool LLGLManager::initGL() } #endif stop_glerror(); - mHasTextureMultisample = FALSE; -#if LL_WINDOWS - if (mIsATI) - { //using multisample textures on ATI results in black screen for some reason - mHasTextureMultisample = FALSE; - } -#endif if (mIsIntel && mGLVersion <= 3.f) { //never try to use framebuffer objects on older intel drivers (crashy) mHasFramebufferObject = FALSE; } - if (mHasFramebufferObject) - { - glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples); - } - stop_glerror(); setToDebugGPU(); @@ -847,14 +829,6 @@ std::string LLGLManager::getRawGLString() return gl_string; } -U32 LLGLManager::getNumFBOFSAASamples(U32 samples) -{ - samples = llmin(samples, (U32) mMaxColorTextureSamples); - samples = llmin(samples, (U32) mMaxDepthTextureSamples); - samples = llmin(samples, (U32) 4); - return samples; -} - void LLGLManager::shutdownGL() { if (mInited) @@ -960,7 +934,6 @@ void LLGLManager::initExtensions() mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); - mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts); mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts); mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE; #if !LL_DARWIN @@ -1198,13 +1171,6 @@ void LLGLManager::initExtensions() { glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT"); } - if (mHasTextureMultisample) - { - glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage2DMultisample"); - glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample"); - glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv"); - glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski"); - } if (mHasTransformFeedback) { glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glBeginTransformFeedback"); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 06f6155c9..84bb96917 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -104,11 +104,7 @@ public: BOOL mHasDrawBuffers; BOOL mHasDepthClamp; BOOL mHasTextureRectangle; - BOOL mHasTextureMultisample; BOOL mHasTransformFeedback; - S32 mMaxSampleMaskWords; - S32 mMaxColorTextureSamples; - S32 mMaxDepthTextureSamples; S32 mMaxIntegerSamples; // Other extensions. @@ -155,7 +151,6 @@ public: void printGLInfoString(); void getGLInfo(LLSD& info); - U32 getNumFBOFSAASamples(U32 desired_samples = 32); // In ALL CAPS std::string mGLVendor; std::string mGLVendorShort; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 1e698adfc..6d7054e7e 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -330,7 +330,6 @@ S32 LLImageGL::updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 categ //static void LLImageGL::destroyGL(BOOL save_state) { - deleteDeadTextures(); //Dump unimportant textures. for (S32 stage = 0; stage < gGLManager.mNumTextureUnits; stage++) { gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE); @@ -364,7 +363,6 @@ void LLImageGL::destroyGL(BOOL save_state) } llinfos << "Storing " << stored_count << " images..." << llendl; sAllowReadBackRaw = false ; - deleteDeadTextures();//Now, actually call glDeleteTextures for everything. } //static @@ -1528,7 +1526,7 @@ void LLImageGL::deleteDeadTextures() { bool reset = false; - for(U32 i=0;iBoolean Value 0 + + SHFMODExStreamBufferSize + + Comment + Sets the streaming buffer size (in milliseconds) + Persist + 1 + Type + U32 + Value + 7000 + + SHFMODExDecodeBufferSize + + Comment + Sets the streaming decode buffer size (in milliseconds) + Persist + 1 + Type + U32 + Value + 1000 SHAllowScriptCommands diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 9e7df265e..1349429ee 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -54,6 +54,7 @@ #include "llaudioengine.h" #include "lloverlaybar.h" #include "slfloatermediafilter.h" +#include "llstreamingaudio.h" // Static Variables @@ -661,6 +662,9 @@ void LLViewerParcelMedia::playStreamingMusic(LLParcel* parcel, bool filter) else if (gAudiop) { LLStringUtil::trim(music_url); + LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); + if(stream && stream->supportsAdjustableBufferSizes()) + stream->setBufferSizes(gSavedSettings.getU32("SHFMODExStreamBufferSize"),gSavedSettings.getU32("SHFMODExDecodeBufferSize")); gAudiop->startInternetStream(music_url); if (music_url.empty()) { diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 0eb0b3cc2..6ab2cfd17 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -343,7 +343,7 @@ void LLViewerShaderMgr::setShaders() //setup preprocessor definitions LLShaderMgr::instance()->mDefinitions.clear(); - LLShaderMgr::instance()->mDefinitions["samples"] = llformat("%d", gSavedSettings.getU32("RenderFSAASamples")/*gGLManager.getNumFBOFSAASamples(gSavedSettings.getU32("RenderFSAASamples"))*/); + LLShaderMgr::instance()->mDefinitions["samples"] = llformat("%d", gSavedSettings.getU32("RenderFSAASamples")); LLShaderMgr::instance()->mDefinitions["NUM_TEX_UNITS"] = llformat("%d", gGLManager.mNumTextureImageUnits); initAttribsAndUniforms(); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index bd2424294..27632dcfc 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -632,12 +632,6 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); U32 samples = RenderFSAASamples.get() - RenderFSAASamples.get() % 2; //Must be multipe of 2. - //Don't multisample if not using FXAA, or if fbos are disabled, or if multisampled fbos are not supported. - if(!LLPipeline::sRenderDeferred && (!LLRenderTarget::sUseFBO || !gGLManager.mHasFramebufferMultisample)) - { - samples = 0; - } - //try to allocate screen buffers at requested resolution and samples // - on failure, shrink number of samples and try again // - if not multisampled, shrink resolution and try again (favor X resolution over Y) @@ -693,6 +687,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) } mSampleBuffer.release(); + mScreen.release(); if (LLPipeline::sRenderDeferred) { @@ -790,7 +785,6 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; if(samples > 1) { - if(mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples)) mScreen.setSampleBuffer(&mSampleBuffer); else @@ -906,6 +900,8 @@ void LLPipeline::releaseScreenBuffers() { mShadow[i].release(); } + + mSampleBuffer.release(); }