From b101bb00013452c6d569cf85a79ae5bc3e8ea9db Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 17 Jul 2012 23:38:34 -0500 Subject: [PATCH 01/29] MAINT-646: Faster traversal of render batch lists. https://bitbucket.org/davep/viewer-development/changeset/38b7779af5f9 --- indra/newview/lldrawpool.cpp | 2 +- indra/newview/lldrawpoolalpha.cpp | 4 +- indra/newview/lldrawpoolavatar.cpp | 68 +++++++++----- indra/newview/lldrawpoolbump.cpp | 12 +-- indra/newview/llspatialpartition.cpp | 135 +++++++++++++++++---------- indra/newview/llspatialpartition.h | 68 +++++++++----- indra/newview/pipeline.cpp | 60 ++++++------ indra/newview/pipeline.h | 8 +- 8 files changed, 214 insertions(+), 143 deletions(-) diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 968ed740a..69a3cf419 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -446,7 +446,7 @@ void LLRenderPass::renderTexture(U32 type, U32 mask) void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) { - for (LLCullResult::drawinfo_list_t::iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) + for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; if (pparams) diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 500f8b67a..865e89f89 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -355,7 +355,7 @@ void LLDrawPoolAlpha::render(S32 pass) void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) { - for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) + for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) { LLSpatialGroup* group = *i; if (group->mSpatialPartition->mRenderByGroup && @@ -392,7 +392,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) BOOL use_shaders = gPipeline.canUseVertexShaders(); - for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) + for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) { LLSpatialGroup* group = *i; llassert(group); diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index a37f117c4..3e818faa4 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1203,15 +1203,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass >= 7 && pass < 9) { - LLGLEnable blend(GL_BLEND); - - gGL.setColorMask(true, true); - gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, - LLRender::BF_ONE_MINUS_SOURCE_ALPHA, - LLRender::BF_ZERO, - LLRender::BF_ONE_MINUS_SOURCE_ALPHA); - - if (pass == 7) { renderRiggedAlpha(avatarp); @@ -1227,20 +1218,8 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass == 9) { - LLGLEnable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - gGL.flush(); - - LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -1.0f); - gGL.setSceneBlendType(LLRender::BT_ADD); - - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - gGL.setColorMask(false, true); - renderRiggedGlow(avatarp); - gGL.setColorMask(true, false); - gGL.setSceneBlendType(LLRender::BT_ALPHA); + return; } @@ -1640,17 +1619,56 @@ void LLDrawPoolAvatar::renderRiggedFullbrightShiny(LLVOAvatar* avatar) void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar) { - renderRigged(avatar, RIGGED_ALPHA); + if (!mRiggedFace[RIGGED_ALPHA].empty()) + { + LLGLEnable blend(GL_BLEND); + + gGL.setColorMask(true, true); + gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, + LLRender::BF_ONE_MINUS_SOURCE_ALPHA, + LLRender::BF_ZERO, + LLRender::BF_ONE_MINUS_SOURCE_ALPHA); + + renderRigged(avatar, RIGGED_ALPHA); + } } void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar) { - renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA); + if (!mRiggedFace[RIGGED_FULLBRIGHT_ALPHA].empty()) + { + LLGLEnable blend(GL_BLEND); + + gGL.setColorMask(true, true); + gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, + LLRender::BF_ONE_MINUS_SOURCE_ALPHA, + LLRender::BF_ZERO, + LLRender::BF_ONE_MINUS_SOURCE_ALPHA); + + renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA); + } } void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar) { - renderRigged(avatar, RIGGED_GLOW, true); + if (!mRiggedFace[RIGGED_GLOW].empty()) + { + LLGLEnable blend(GL_BLEND); + LLGLDisable test(GL_ALPHA_TEST); + gGL.flush(); + + LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1.0f, -1.0f); + gGL.setSceneBlendType(LLRender::BT_ADD); + + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + gGL.setColorMask(false, true); + + renderRigged(avatar, RIGGED_GLOW, true); + + gGL.setColorMask(true, false); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } } diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 65ab71abc..60af91ac8 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -848,12 +848,12 @@ void LLDrawPoolBump::renderDeferred(S32 pass) LLFastTimer ftm(FTM_RENDER_BUMP); U32 type = LLRenderPass::PASS_BUMP; - LLCullResult::drawinfo_list_t::iterator begin = gPipeline.beginRenderMap(type); - LLCullResult::drawinfo_list_t::iterator end = gPipeline.endRenderMap(type); + LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); + LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR; - for (LLCullResult::drawinfo_list_t::iterator i = begin; i != end; ++i) + for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; @@ -1449,10 +1449,10 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI void LLDrawPoolBump::renderBump(U32 type, U32 mask) { - LLCullResult::drawinfo_list_t::iterator begin = gPipeline.beginRenderMap(type); - LLCullResult::drawinfo_list_t::iterator end = gPipeline.endRenderMap(type); + LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); + LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); - for (LLCullResult::drawinfo_list_t::iterator i = begin; i != end; ++i) + for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 2d476dfbb..55e3b758f 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -4476,29 +4476,64 @@ LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage) } LLCullResult::LLCullResult() -{ +{ + mVisibleGroupsAllocated = 0; + mAlphaGroupsAllocated = 0; + mOcclusionGroupsAllocated = 0; + mDrawableGroupsAllocated = 0; + mVisibleListAllocated = 0; + mVisibleBridgeAllocated = 0; + + mVisibleGroups = NULL; + mVisibleGroupsEnd = NULL; + mAlphaGroups = NULL; + mAlphaGroupsEnd = NULL; + mOcclusionGroups = NULL; + mOcclusionGroupsEnd = NULL; + mDrawableGroups = NULL; + mDrawableGroupsEnd = NULL; + mVisibleList = NULL; + mVisibleListEnd = NULL; + mVisibleBridge = NULL; + mVisibleBridgeEnd = NULL; + + for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++) + { + mRenderMap[i] = NULL; + mRenderMapEnd[i] = NULL; + mRenderMapAllocated[i] = 0; + } + clear(); } +void LLCullResult::pushBack(void**& head, U32& count, void* val) +{ + count++; + head = (void**) realloc((void*) head, sizeof(void*) * count); + head[count-1] = val; +} + void LLCullResult::clear() { mVisibleGroupsSize = 0; - mVisibleGroupsEnd = mVisibleGroups.begin(); + mVisibleGroupsEnd = mVisibleGroups; mAlphaGroupsSize = 0; - mAlphaGroupsEnd = mAlphaGroups.begin(); + mAlphaGroupsEnd = mAlphaGroups; mOcclusionGroupsSize = 0; - mOcclusionGroupsEnd = mOcclusionGroups.begin(); + mOcclusionGroupsEnd = mOcclusionGroups; mDrawableGroupsSize = 0; - mDrawableGroupsEnd = mDrawableGroups.begin(); + mDrawableGroupsEnd = mDrawableGroups; mVisibleListSize = 0; - mVisibleListEnd = mVisibleList.begin(); + mVisibleListEnd = mVisibleList; mVisibleBridgeSize = 0; - mVisibleBridgeEnd = mVisibleBridge.begin(); + mVisibleBridgeEnd = mVisibleBridge; + for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++) { @@ -4507,176 +4542,176 @@ void LLCullResult::clear() mRenderMap[i][j] = 0; } mRenderMapSize[i] = 0; - mRenderMapEnd[i] = mRenderMap[i].begin(); + mRenderMapEnd[i] = mRenderMap[i]; } } -LLCullResult::sg_list_t::iterator LLCullResult::beginVisibleGroups() +LLCullResult::sg_iterator LLCullResult::beginVisibleGroups() { - return mVisibleGroups.begin(); + return mVisibleGroups; } -LLCullResult::sg_list_t::iterator LLCullResult::endVisibleGroups() +LLCullResult::sg_iterator LLCullResult::endVisibleGroups() { return mVisibleGroupsEnd; } -LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups() +LLCullResult::sg_iterator LLCullResult::beginAlphaGroups() { - return mAlphaGroups.begin(); + return mAlphaGroups; } -LLCullResult::sg_list_t::iterator LLCullResult::endAlphaGroups() +LLCullResult::sg_iterator LLCullResult::endAlphaGroups() { return mAlphaGroupsEnd; } -LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups() +LLCullResult::sg_iterator LLCullResult::beginOcclusionGroups() { - return mOcclusionGroups.begin(); + return mOcclusionGroups; } -LLCullResult::sg_list_t::iterator LLCullResult::endOcclusionGroups() +LLCullResult::sg_iterator LLCullResult::endOcclusionGroups() { return mOcclusionGroupsEnd; } -LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups() +LLCullResult::sg_iterator LLCullResult::beginDrawableGroups() { - return mDrawableGroups.begin(); + return mDrawableGroups; } -LLCullResult::sg_list_t::iterator LLCullResult::endDrawableGroups() +LLCullResult::sg_iterator LLCullResult::endDrawableGroups() { return mDrawableGroupsEnd; } -LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList() +LLCullResult::drawable_iterator LLCullResult::beginVisibleList() { - return mVisibleList.begin(); + return mVisibleList; } -LLCullResult::drawable_list_t::iterator LLCullResult::endVisibleList() +LLCullResult::drawable_iterator LLCullResult::endVisibleList() { return mVisibleListEnd; } -LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge() +LLCullResult::bridge_iterator LLCullResult::beginVisibleBridge() { - return mVisibleBridge.begin(); + return mVisibleBridge; } -LLCullResult::bridge_list_t::iterator LLCullResult::endVisibleBridge() +LLCullResult::bridge_iterator LLCullResult::endVisibleBridge() { return mVisibleBridgeEnd; } -LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type) +LLCullResult::drawinfo_iterator LLCullResult::beginRenderMap(U32 type) { - return mRenderMap[type].begin(); + return mRenderMap[type]; } -LLCullResult::drawinfo_list_t::iterator LLCullResult::endRenderMap(U32 type) +LLCullResult::drawinfo_iterator LLCullResult::endRenderMap(U32 type) { return mRenderMapEnd[type]; } void LLCullResult::pushVisibleGroup(LLSpatialGroup* group) { - if (mVisibleGroupsSize < mVisibleGroups.size()) + if (mVisibleGroupsSize < mVisibleGroupsAllocated) { mVisibleGroups[mVisibleGroupsSize] = group; } else { - mVisibleGroups.push_back(group); + pushBack((void**&) mVisibleGroups, mVisibleGroupsAllocated, (void*) group); } ++mVisibleGroupsSize; - mVisibleGroupsEnd = mVisibleGroups.begin()+mVisibleGroupsSize; + mVisibleGroupsEnd = mVisibleGroups+mVisibleGroupsSize; } void LLCullResult::pushAlphaGroup(LLSpatialGroup* group) { - if (mAlphaGroupsSize < mAlphaGroups.size()) + if (mAlphaGroupsSize < mAlphaGroupsAllocated) { mAlphaGroups[mAlphaGroupsSize] = group; } else { - mAlphaGroups.push_back(group); + pushBack((void**&) mAlphaGroups, mAlphaGroupsAllocated, (void*) group); } ++mAlphaGroupsSize; - mAlphaGroupsEnd = mAlphaGroups.begin()+mAlphaGroupsSize; + mAlphaGroupsEnd = mAlphaGroups+mAlphaGroupsSize; } void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group) { - if (mOcclusionGroupsSize < mOcclusionGroups.size()) + if (mOcclusionGroupsSize < mOcclusionGroupsAllocated) { mOcclusionGroups[mOcclusionGroupsSize] = group; } else { - mOcclusionGroups.push_back(group); + pushBack((void**&) mOcclusionGroups, mOcclusionGroupsAllocated, (void*) group); } ++mOcclusionGroupsSize; - mOcclusionGroupsEnd = mOcclusionGroups.begin()+mOcclusionGroupsSize; + mOcclusionGroupsEnd = mOcclusionGroups+mOcclusionGroupsSize; } void LLCullResult::pushDrawableGroup(LLSpatialGroup* group) { - if (mDrawableGroupsSize < mDrawableGroups.size()) + if (mDrawableGroupsSize < mDrawableGroupsAllocated) { mDrawableGroups[mDrawableGroupsSize] = group; } else { - mDrawableGroups.push_back(group); + pushBack((void**&) mDrawableGroups, mDrawableGroupsAllocated, (void*) group); } ++mDrawableGroupsSize; - mDrawableGroupsEnd = mDrawableGroups.begin()+mDrawableGroupsSize; + mDrawableGroupsEnd = mDrawableGroups+mDrawableGroupsSize; } void LLCullResult::pushDrawable(LLDrawable* drawable) { - if (mVisibleListSize < mVisibleList.size()) + if (mVisibleListSize < mVisibleListAllocated) { mVisibleList[mVisibleListSize] = drawable; } else { - mVisibleList.push_back(drawable); + pushBack((void**&) mVisibleList, mVisibleListAllocated, (void*) drawable); } ++mVisibleListSize; - mVisibleListEnd = mVisibleList.begin()+mVisibleListSize; + mVisibleListEnd = mVisibleList+mVisibleListSize; } void LLCullResult::pushBridge(LLSpatialBridge* bridge) { - if (mVisibleBridgeSize < mVisibleBridge.size()) + if (mVisibleBridgeSize < mVisibleBridgeAllocated) { mVisibleBridge[mVisibleBridgeSize] = bridge; } else { - mVisibleBridge.push_back(bridge); + pushBack((void**&) mVisibleBridge, mVisibleBridgeAllocated, (void*) bridge); } ++mVisibleBridgeSize; - mVisibleBridgeEnd = mVisibleBridge.begin()+mVisibleBridgeSize; + mVisibleBridgeEnd = mVisibleBridge+mVisibleBridgeSize; } void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info) { - if (mRenderMapSize[type] < mRenderMap[type].size()) + if (mRenderMapSize[type] < mRenderMapAllocated[type]) { mRenderMap[type][mRenderMapSize[type]] = draw_info; } else { - mRenderMap[type].push_back(draw_info); + pushBack((void**&) mRenderMap[type], mRenderMapAllocated[type], (void*) draw_info); } ++mRenderMapSize[type]; - mRenderMapEnd[type] = mRenderMap[type].begin() + mRenderMapSize[type]; + mRenderMapEnd[type] = mRenderMap[type] + mRenderMapSize[type]; } diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 95ba1c036..d86221ddc 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -522,34 +522,39 @@ class LLCullResult public: LLCullResult(); - typedef std::vector sg_list_t; - typedef std::vector drawable_list_t; - typedef std::vector bridge_list_t; - typedef std::vector drawinfo_list_t; + typedef LLSpatialGroup** sg_list_t; + typedef LLDrawable** drawable_list_t; + typedef LLSpatialBridge** bridge_list_t; + typedef LLDrawInfo** drawinfo_list_t; + + typedef LLSpatialGroup** sg_iterator; + typedef LLSpatialBridge** bridge_iterator; + typedef LLDrawInfo** drawinfo_iterator; + typedef LLDrawable** drawable_iterator; void clear(); - sg_list_t::iterator beginVisibleGroups(); - sg_list_t::iterator endVisibleGroups(); + sg_iterator beginVisibleGroups(); + sg_iterator endVisibleGroups(); - sg_list_t::iterator beginAlphaGroups(); - sg_list_t::iterator endAlphaGroups(); + sg_iterator beginAlphaGroups(); + sg_iterator endAlphaGroups(); bool hasOcclusionGroups() { return mOcclusionGroupsSize > 0; } - sg_list_t::iterator beginOcclusionGroups(); - sg_list_t::iterator endOcclusionGroups(); + sg_iterator beginOcclusionGroups(); + sg_iterator endOcclusionGroups(); - sg_list_t::iterator beginDrawableGroups(); - sg_list_t::iterator endDrawableGroups(); + sg_iterator beginDrawableGroups(); + sg_iterator endDrawableGroups(); - drawable_list_t::iterator beginVisibleList(); - drawable_list_t::iterator endVisibleList(); + drawable_iterator beginVisibleList(); + drawable_iterator endVisibleList(); - bridge_list_t::iterator beginVisibleBridge(); - bridge_list_t::iterator endVisibleBridge(); + bridge_iterator beginVisibleBridge(); + bridge_iterator endVisibleBridge(); - drawinfo_list_t::iterator beginRenderMap(U32 type); - drawinfo_list_t::iterator endRenderMap(U32 type); + drawinfo_iterator beginRenderMap(U32 type); + drawinfo_iterator endRenderMap(U32 type); void pushVisibleGroup(LLSpatialGroup* group); void pushAlphaGroup(LLSpatialGroup* group); @@ -569,28 +574,41 @@ public: void assertDrawMapsEmpty(); private: + + void pushBack(void** &head, U32& count, void* val); + U32 mVisibleGroupsSize; U32 mAlphaGroupsSize; U32 mOcclusionGroupsSize; U32 mDrawableGroupsSize; U32 mVisibleListSize; U32 mVisibleBridgeSize; + + U32 mVisibleGroupsAllocated; + U32 mAlphaGroupsAllocated; + U32 mOcclusionGroupsAllocated; + U32 mDrawableGroupsAllocated; + U32 mVisibleListAllocated; + U32 mVisibleBridgeAllocated; + U32 mRenderMapSize[LLRenderPass::NUM_RENDER_TYPES]; sg_list_t mVisibleGroups; - sg_list_t::iterator mVisibleGroupsEnd; + sg_iterator mVisibleGroupsEnd; sg_list_t mAlphaGroups; - sg_list_t::iterator mAlphaGroupsEnd; + sg_iterator mAlphaGroupsEnd; sg_list_t mOcclusionGroups; - sg_list_t::iterator mOcclusionGroupsEnd; + sg_iterator mOcclusionGroupsEnd; sg_list_t mDrawableGroups; - sg_list_t::iterator mDrawableGroupsEnd; + sg_iterator mDrawableGroupsEnd; drawable_list_t mVisibleList; - drawable_list_t::iterator mVisibleListEnd; + drawable_iterator mVisibleListEnd; bridge_list_t mVisibleBridge; - bridge_list_t::iterator mVisibleBridgeEnd; + bridge_iterator mVisibleBridgeEnd; drawinfo_list_t mRenderMap[LLRenderPass::NUM_RENDER_TYPES]; - drawinfo_list_t::iterator mRenderMapEnd[LLRenderPass::NUM_RENDER_TYPES]; + U32 mRenderMapAllocated[LLRenderPass::NUM_RENDER_TYPES]; + drawinfo_iterator mRenderMapEnd[LLRenderPass::NUM_RENDER_TYPES]; + }; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 27632dcfc..f6cdbba74 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1815,19 +1815,19 @@ void LLPipeline::checkReferences(LLFace* face) #if 0 if (sCull) { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) { LLSpatialGroup* group = *iter; check_references(group, face); } - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) { LLSpatialGroup* group = *iter; check_references(group, face); } - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) { LLSpatialGroup* group = *iter; check_references(group, face); @@ -1847,19 +1847,19 @@ void LLPipeline::checkReferences(LLDrawable* drawable) #if 0 if (sCull) { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) { LLSpatialGroup* group = *iter; check_references(group, drawable); } - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) { LLSpatialGroup* group = *iter; check_references(group, drawable); } - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) { LLSpatialGroup* group = *iter; check_references(group, drawable); @@ -1898,19 +1898,19 @@ void LLPipeline::checkReferences(LLDrawInfo* draw_info) #if 0 if (sCull) { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) { LLSpatialGroup* group = *iter; check_references(group, draw_info); } - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) { LLSpatialGroup* group = *iter; check_references(group, draw_info); } - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) { LLSpatialGroup* group = *iter; check_references(group, draw_info); @@ -1924,7 +1924,7 @@ void LLPipeline::checkReferences(LLSpatialGroup* group) #if 0 if (sCull) { - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) { if (group == *iter) { @@ -1932,7 +1932,7 @@ void LLPipeline::checkReferences(LLSpatialGroup* group) } } - for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter) { if (group == *iter) { @@ -1940,7 +1940,7 @@ void LLPipeline::checkReferences(LLSpatialGroup* group) } } - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) { if (group == *iter) { @@ -2282,7 +2282,7 @@ void LLPipeline::doOcclusion(LLCamera& camera) } mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter) { LLSpatialGroup* group = *iter; group->doOcclusion(&camera); @@ -2816,7 +2816,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) //LLVertexBuffer::unbind(); grabReferences(result); - for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter) { LLSpatialGroup* group = *iter; group->checkOcclusion(); @@ -2842,9 +2842,9 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) { LLSpatialGroup* last_group = NULL; - for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + for (LLCullResult::bridge_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) { - LLCullResult::bridge_list_t::iterator cur_iter = i; + LLCullResult::bridge_iterator cur_iter = i; LLSpatialBridge* bridge = *cur_iter; LLSpatialGroup* group = bridge->getSpatialGroup(); @@ -2874,7 +2874,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } } - for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) + for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter) { LLSpatialGroup* group = *iter; group->checkOcclusion(); @@ -2896,7 +2896,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) { LLFastTimer ftm(FTM_STATESORT_DRAWABLE); - for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); + for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) { LLDrawable *drawablep = *iter; @@ -3045,11 +3045,11 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) } -void forAllDrawables(LLCullResult::sg_list_t::iterator begin, - LLCullResult::sg_list_t::iterator end, +void forAllDrawables(LLCullResult::sg_iterator begin, + LLCullResult::sg_iterator end, void (*func)(LLDrawable*)) { - for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i) + for (LLCullResult::sg_iterator i = begin; i != end; ++i) { for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j) { @@ -3219,7 +3219,7 @@ void LLPipeline::postSort(LLCamera& camera) llpushcallstacks ; //rebuild drawable geometry - for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) + for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) { LLSpatialGroup* group = *i; if (!sUseOcclusion || @@ -3237,7 +3237,7 @@ void LLPipeline::postSort(LLCamera& camera) //build render map - for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) + for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) { LLSpatialGroup* group = *i; @@ -4179,7 +4179,7 @@ void LLPipeline::renderPhysicsDisplay() } } - for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + for (LLCullResult::bridge_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) { LLSpatialBridge* bridge = *i; if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) @@ -4238,7 +4238,7 @@ void LLPipeline::renderDebug() } } - for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) + for (LLCullResult::bridge_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) { LLSpatialBridge* bridge = *i; if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) @@ -9328,7 +9328,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture) { - for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) + for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) { LLSpatialGroup* group = *i; if (!group->isDead() && @@ -9593,22 +9593,22 @@ BOOL LLPipeline::hasRenderBatches(const U32 type) const return sCull->getRenderMapSize(type) > 0; } -LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type) +LLCullResult::drawinfo_iterator LLPipeline::beginRenderMap(U32 type) { return sCull->beginRenderMap(type); } -LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type) +LLCullResult::drawinfo_iterator LLPipeline::endRenderMap(U32 type) { return sCull->endRenderMap(type); } -LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups() +LLCullResult::sg_iterator LLPipeline::beginAlphaGroups() { return sCull->beginAlphaGroups(); } -LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups() +LLCullResult::sg_iterator LLPipeline::endAlphaGroups() { return sCull->endAlphaGroups(); } diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 4ad8a5e19..3a89ca0a0 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -296,10 +296,10 @@ public: void setLight(LLDrawable *drawablep, BOOL is_light); BOOL hasRenderBatches(const U32 type) const; - LLCullResult::drawinfo_list_t::iterator beginRenderMap(U32 type); - LLCullResult::drawinfo_list_t::iterator endRenderMap(U32 type); - LLCullResult::sg_list_t::iterator beginAlphaGroups(); - LLCullResult::sg_list_t::iterator endAlphaGroups(); + LLCullResult::drawinfo_iterator beginRenderMap(U32 type); + LLCullResult::drawinfo_iterator endRenderMap(U32 type); + LLCullResult::sg_iterator beginAlphaGroups(); + LLCullResult::sg_iterator endAlphaGroups(); void addTrianglesDrawn(S32 index_count, U32 render_type = LLRender::TRIANGLES); From cc5ffafd7c5696d084761cdb99c013aacaee5dee Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 17 Jul 2012 23:54:10 -0500 Subject: [PATCH 02/29] MAINT-646: Add a lookup map for joints to remove hotspot in LLJoint::findJoint https://bitbucket.org/davep/viewer-development/changeset/15b05dc53770 --- indra/llcharacter/llcharacter.cpp | 5 ----- indra/llcharacter/llmotioncontroller.cpp | 1 + indra/newview/llvoavatar.cpp | 17 ++++++++++++++++- indra/newview/llvoavatar.h | 4 ++++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 85291530c..d62eb8da1 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -194,19 +194,14 @@ void LLCharacter::requestStopMotion( LLMotion* motion) //----------------------------------------------------------------------------- // updateMotions() //----------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_UPDATE_ANIMATION("Update Animation"); -static LLFastTimer::DeclareTimer FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim"); - void LLCharacter::updateMotions(e_update_t update_type) { if (update_type == HIDDEN_UPDATE) { - LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION); mMotionController.updateMotionsMinimal(); } else { - LLFastTimer t(FTM_UPDATE_ANIMATION); // unpause if the number of outstanding pause requests has dropped to the initial one if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1) { diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 3b7dbec33..f0c95560e 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -837,6 +837,7 @@ void LLMotionController::updateMotions(bool force_update) } updateLoadingMotions(); + return; } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 5c4d540ea..d7a6628f2 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1179,6 +1179,7 @@ LLVOAvatar::~LLVOAvatar() lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl; mRoot.removeAllChildren(); + mJointMap.clear(); deleteAndClearArray(mSkeleton); deleteAndClearArray(mCollisionVolumes); @@ -2340,6 +2341,7 @@ void LLVOAvatar::buildCharacter() // remove all of mRoot's children //------------------------------------------------------------------------- mRoot.removeAllChildren(); + mJointMap.clear(); mIsBuilt = FALSE; //------------------------------------------------------------------------- @@ -5887,7 +5889,20 @@ const LLUUID& LLVOAvatar::getID() const // RN: avatar joints are multi-rooted to include screen-based attachments LLJoint *LLVOAvatar::getJoint( const std::string &name ) { - LLJoint* jointp = mRoot.findJoint(name); + joint_map_t::iterator iter = mJointMap.find(name); + + LLJoint* jointp = NULL; + + if (iter == mJointMap.end() || iter->second == NULL) + { //search for joint and cache found joint in lookup table + jointp = mRoot.findJoint(name); + mJointMap[name] = jointp; + } + else + { //return cached pointer + jointp = iter->second; + } + return jointp; } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index e0d4b3bf5..81529a2f3 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -376,6 +376,10 @@ public: LLVector3 mHeadOffset; // current head position LLViewerJoint mRoot; + + typedef std::map joint_map_t; + joint_map_t mJointMap; + protected: static BOOL parseSkeletonFile(const std::string& filename); void buildCharacter(); From a56ad597d414b9604ae1bad32ab883adc55f8e78 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jul 2012 00:54:52 -0500 Subject: [PATCH 03/29] MAINT-646: Factor std::set out of lloctree https://bitbucket.org/davep/viewer-development/changeset/52b6c9168974 --- indra/llmath/lloctree.h | 131 +++++++++++++++++++-------- indra/llmath/llvolume.cpp | 6 +- indra/llmath/llvolumeoctree.cpp | 6 +- indra/llmath/llvolumeoctree.h | 7 +- indra/newview/lldrawable.cpp | 26 +++++- indra/newview/lldrawable.h | 6 +- indra/newview/llface.cpp | 22 +++-- indra/newview/llspatialpartition.cpp | 48 +++++----- indra/newview/llspatialpartition.h | 5 + indra/newview/llvograss.cpp | 2 +- indra/newview/llvopartgroup.cpp | 2 +- indra/newview/llvovolume.cpp | 29 ++++-- indra/newview/pipeline.cpp | 14 +-- 13 files changed, 208 insertions(+), 96 deletions(-) diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index c8a0875f5..9a5918849 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -89,9 +89,9 @@ public: typedef LLOctreeTraveler oct_traveler; typedef LLTreeTraveler tree_traveler; - typedef typename std::set > element_list; - typedef typename element_list::iterator element_iter; - typedef typename element_list::const_iterator const_element_iter; + typedef LLPointer* element_list; + typedef LLPointer* element_iter; + typedef const LLPointer* const_element_iter; typedef typename std::vector*>::iterator tree_listener_iter; typedef typename std::vector* > child_list; typedef LLTreeNode BaseType; @@ -115,6 +115,9 @@ public: : mParent((oct_node*)parent), mOctant(octant) { + mData = NULL; + mDataEnd = NULL; + mCenter = center; mSize = size; @@ -133,6 +136,16 @@ public: { BaseType::destroyListeners(); + for (U32 i = 0; i < mElementCount; ++i) + { + mData[i]->setBinIndex(-1); + mData[i] = NULL; + } + + free(mData); + mData = NULL; + mDataEnd = NULL; + for (U32 i = 0; i < getChildCount(); i++) { delete getChild(i); @@ -232,9 +245,14 @@ public: virtual bool isLeaf() const { return mChild.empty(); } U32 getElementCount() const { return mElementCount; } + bool isEmpty() const { return mElementCount == 0; } element_list& getData() { return mData; } const element_list& getData() const { return mData; } - + element_iter getDataBegin() { return mData; } + element_iter getDataEnd() { return mDataEnd; } + const_element_iter getDataBegin() const { return mData; } + const_element_iter getDataEnd() const { return mDataEnd; } + U32 getChildCount() const { return mChildCount; } oct_node* getChild(U32 index) { return mChild[index]; } const oct_node* getChild(U32 index) const { return mChild[index]; } @@ -299,7 +317,7 @@ public: virtual bool insert(T* data) { - if (data == NULL) + if (data == NULL || data->getBinIndex() != -1) { OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl; return false; @@ -309,22 +327,19 @@ public: //is it here? if (isInside(data->getPositionGroup())) { - if (((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius())) || + if ((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius()) || (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity))) { //it belongs here -#if LL_OCTREE_PARANOIA_CHECK - //if this is a redundant insertion, error out (should never happen) - if (mData.find(data) != mData.end()) - { - llwarns << "Redundant octree insertion detected. " << data << llendl; - return false; - } -#endif + mElementCount++; + mData = (element_list) realloc(mData, sizeof(LLPointer)*mElementCount); - mData.insert(data); + //avoid unref on uninitialized memory + memset(mData+mElementCount-1, 0, sizeof(LLPointer)); + + mData[mElementCount-1] = data; + mDataEnd = mData + mElementCount; + data->setBinIndex(mElementCount-1); BaseType::insert(data); - - mElementCount = mData.size(); return true; } else @@ -358,10 +373,16 @@ public: if( lt == 0x7 ) { - mData.insert(data); - BaseType::insert(data); + mElementCount++; + mData = (element_list) realloc(mData, sizeof(LLPointer)*mElementCount); - mElementCount = mData.size(); + //avoid unref on uninitialized memory + memset(mData+mElementCount-1, 0, sizeof(LLPointer)); + + mData[mElementCount-1] = data; + mDataEnd = mData + mElementCount; + data->setBinIndex(mElementCount-1); + BaseType::insert(data); return true; } @@ -410,23 +431,59 @@ public: return false; } + void _remove(T* data, S32 i) + { //precondition -- mElementCount > 0, idx is in range [0, mElementCount) + + mElementCount--; + data->setBinIndex(-1); + + if (mElementCount > 0) + { + if (mElementCount != i) + { + mData[i] = mData[mElementCount]; //might unref data, do not access data after this point + mData[i]->setBinIndex(i); + } + + mData[mElementCount] = NULL; //needed for unref + mData = (element_list) realloc(mData, sizeof(LLPointer)*mElementCount); + mDataEnd = mData+mElementCount; + } + else + { + mData[0] = NULL; //needed for unref + free(mData); + mData = NULL; + mDataEnd = NULL; + } + + notifyRemoval(data); + checkAlive(); + } + bool remove(T* data) { - if (mData.find(data) != mData.end()) - { //we have data - mData.erase(data); - mElementCount = mData.size(); - this->notifyRemoval(data); - checkAlive(); - return true; + S32 i = data->getBinIndex(); + + if (i >= 0 && i < (S32)mElementCount) + { + if (mData[i] == data) + { //found it + _remove(data, i); + llassert(data->getBinIndex() == -1); + return true; + } } - else if (isInside(data)) + + if (isInside(data)) { oct_node* dest = getNodeAt(data); if (dest != this) { - return dest->remove(data); + bool ret = dest->remove(data); + llassert(data->getBinIndex() == -1); + return ret; } } @@ -445,19 +502,20 @@ public: //node is now root llwarns << "!!! OCTREE REMOVING FACE BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl; node->removeByAddress(data); + llassert(data->getBinIndex() == -1); return true; } void removeByAddress(T* data) { - if (mData.find(data) != mData.end()) + for (U32 i = 0; i < mElementCount; ++i) { - mData.erase(data); - mElementCount = mData.size(); - this->notifyRemoval(data); - llwarns << "FOUND!" << llendl; - checkAlive(); - return; + if (mData[i] == data) + { //we have data + _remove(data, i); + llwarns << "FOUND!" << llendl; + return; + } } for (U32 i = 0; i < getChildCount(); i++) @@ -624,6 +682,7 @@ protected: U32 mChildCount; element_list mData; + element_iter mDataEnd; U32 mElementCount; }; diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 8b47a92ea..99094ce23 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -324,16 +324,16 @@ public: LLVector4a& min = node->mExtents[0]; LLVector4a& max = node->mExtents[1]; - if (!branch->getData().empty()) + if (!branch->isEmpty()) { //node has data, find AABB that binds data set - const LLVolumeTriangle* tri = *(branch->getData().begin()); + const LLVolumeTriangle* tri = *(branch->getDataBegin()); //initialize min/max to first available vertex min = *(tri->mV[0]); max = *(tri->mV[0]); for (LLOctreeNode::const_element_iter iter = - branch->getData().begin(); iter != branch->getData().end(); ++iter) + branch->getDataBegin(); iter != branch->getDataEnd(); ++iter) { //for each triangle in node //stretch by triangles in node diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp index d5bd5a78d..cf9aeece8 100644 --- a/indra/llmath/llvolumeoctree.cpp +++ b/indra/llmath/llvolumeoctree.cpp @@ -131,7 +131,7 @@ void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode* node) { for (LLOctreeNode::const_element_iter iter = - node->getData().begin(); iter != node->getData().end(); ++iter) + node->getDataBegin(); iter != node->getDataEnd(); ++iter) { const LLVolumeTriangle* tri = *iter; @@ -236,8 +236,8 @@ void LLVolumeOctreeValidate::visit(const LLOctreeNode* branch) } //children fit, check data - for (LLOctreeNode::const_element_iter iter = branch->getData().begin(); - iter != branch->getData().end(); ++iter) + for (LLOctreeNode::const_element_iter iter = branch->getDataBegin(); + iter != branch->getDataEnd(); ++iter) { const LLVolumeTriangle* tri = *iter; diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h index 688d91dc4..c25e37f1a 100644 --- a/indra/llmath/llvolumeoctree.h +++ b/indra/llmath/llvolumeoctree.h @@ -39,7 +39,7 @@ class LLVolumeTriangle : public LLRefCount public: LLVolumeTriangle() { - + mBinIndex = -1; } LLVolumeTriangle(const LLVolumeTriangle& rhs) @@ -64,9 +64,14 @@ public: U16 mIndex[3]; F32 mRadius; + mutable S32 mBinIndex; + virtual const LLVector4a& getPositionGroup() const; virtual const F32& getBinRadius() const; + + S32 getBinIndex() const { return mBinIndex; } + void setBinIndex(S32 idx) const { mBinIndex = idx; } }; class LLVolumeOctreeListener : public LLOctreeListener diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index b9df32f06..89e26ccb1 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -113,6 +113,7 @@ void LLDrawable::init() mGeneration = -1; mBinRadius = 1.f; + mBinIndex = -1; mSpatialBridge = NULL; } @@ -963,6 +964,12 @@ void LLDrawable::updateUVMinMax() { } +LLSpatialGroup* LLDrawable::getSpatialGroup() const +{ + llassert((mSpatialGroupp == NULL) ? getBinIndex() == -1 : getBinIndex() != -1); + return mSpatialGroupp; +} + void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp) { /*if (mSpatialGroupp && (groupp != mSpatialGroupp)) @@ -985,6 +992,8 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp) } mSpatialGroupp = groupp; + + llassert((mSpatialGroupp == NULL) ? getBinIndex() == -1 : getBinIndex() != -1); } LLSpatialPartition* LLDrawable::getSpatialPartition() @@ -1107,6 +1116,8 @@ LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 dat mDrawable = root; root->setSpatialBridge(this); + mBinIndex = -1; + mRenderType = mDrawable->mRenderType; mDrawableType = mDrawable->mRenderType; @@ -1500,7 +1511,13 @@ void LLSpatialBridge::cleanupReferences() LLDrawable::cleanupReferences(); if (mDrawable) { - mDrawable->setSpatialGroup(NULL); + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->mOctreeNode->remove(mDrawable); + mDrawable->setSpatialGroup(NULL); + } + if (mDrawable->getVObj()) { LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren(); @@ -1511,7 +1528,12 @@ void LLSpatialBridge::cleanupReferences() LLDrawable* drawable = child->mDrawable; if (drawable) { - drawable->setSpatialGroup(NULL); + LLSpatialGroup* group = drawable->getSpatialGroup(); + if (group) + { + group->mOctreeNode->remove(drawable); + drawable->setSpatialGroup(NULL); + } } } } diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 6f07c82be..bd2d23c5f 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -115,6 +115,9 @@ public: F32 getIntensity() const { return llmin(mXform.getScale().mV[0], 4.f); } S32 getLOD() const { return mVObjp ? mVObjp->getLOD() : 1; } F32 getBinRadius() const { return mBinRadius; } + S32 getBinIndex() const { return mBinIndex; } + void setBinIndex(S32 index) const { mBinIndex = index; } + void getMinMax(LLVector3& min,LLVector3& max) const { mXform.getMinMax(min,max); } LLXformMatrix* getXform() { return &mXform; } @@ -200,7 +203,7 @@ public: S32 findReferences(LLDrawable *drawablep); // Not const because of @#$! iterators... void setSpatialGroup(LLSpatialGroup *groupp); - LLSpatialGroup *getSpatialGroup() const { return mSpatialGroupp; } + LLSpatialGroup *getSpatialGroup() const; LLSpatialPartition* getSpatialPartition(); // Statics @@ -321,6 +324,7 @@ private: mutable U32 mVisible; F32 mRadius; F32 mBinRadius; + mutable S32 mBinIndex; S32 mGeneration; LLVector3 mCurrentScale; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index e52bb5959..38e41c6b4 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1209,19 +1209,25 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { if (num_indices + (S32) mIndicesIndex > mVertexBuffer->getNumIndices()) { - llwarns << "Index buffer overflow!" << llendl; - llwarns << "Indices Count: " << mIndicesCount - << " VF Num Indices: " << num_indices - << " Indices Index: " << mIndicesIndex - << " VB Num Indices: " << mVertexBuffer->getNumIndices() << llendl; - llwarns << " Face Index: " << f - << " Pool Type: " << mPoolType << llendl; + if (gDebugGL) + { + llwarns << "Index buffer overflow!" << llendl; + llwarns << "Indices Count: " << mIndicesCount + << " VF Num Indices: " << num_indices + << " Indices Index: " << mIndicesIndex + << " VB Num Indices: " << mVertexBuffer->getNumIndices() << llendl; + llwarns << " Face Index: " << f + << " Pool Type: " << mPoolType << llendl; + } return FALSE; } if (num_vertices + mGeomIndex > mVertexBuffer->getNumVerts()) { - llwarns << "Vertex buffer overflow!" << llendl; + if (gDebugGL) + { + llwarns << "Vertex buffer overflow!" << llendl; + } return FALSE; } } diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 55e3b758f..784a0e69c 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -424,7 +424,7 @@ void LLSpatialGroup::validate() validateDrawMap(); - for (element_iter i = getData().begin(); i != getData().end(); ++i) + for (element_iter i = getDataBegin(); i != getDataEnd(); ++i) { LLDrawable* drawable = *i; sg_assert(drawable->getSpatialGroup() == this); @@ -640,7 +640,7 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& ma { const OctreeNode* node = mOctreeNode; - if (node->getData().empty()) + if (node->isEmpty()) { //don't do anything if there are no objects if (empty && mOctreeNode->getParent()) { //only root is allowed to be empty @@ -657,14 +657,14 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& ma clearState(OBJECT_DIRTY); //initialize bounding box to first element - OctreeNode::const_element_iter i = node->getData().begin(); + OctreeNode::const_element_iter i = node->getDataBegin(); LLDrawable* drawablep = *i; const LLVector4a* minMax = drawablep->getSpatialExtents(); newMin = minMax[0]; newMax = minMax[1]; - for (++i; i != node->getData().end(); ++i) + for (++i; i != node->getDataEnd(); ++i) { drawablep = *i; minMax = drawablep->getSpatialExtents(); @@ -1124,7 +1124,7 @@ void LLSpatialGroup::updateDistance(LLCamera &camera) llerrs << "Spatial group dirty on distance update." << llendl; } #endif - if (!getData().empty() /*&& !LLSpatialPartition::sFreezeState*/) + if (!isEmpty() /*&& !LLSpatialPartition::sFreezeState*/) { mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() : (F32) mOctreeNode->getSize().getLength3().getF32(); @@ -1276,7 +1276,7 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node) LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); setState(DEAD); - for (element_iter i = getData().begin(); i != getData().end(); ++i) + for (element_iter i = getDataBegin(); i != getDataEnd(); ++i) { LLDrawable* drawable = *i; if (drawable->getSpatialGroup() == this) @@ -1363,7 +1363,7 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion) } - for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i) + for (LLSpatialGroup::element_iter i = getDataBegin(); i != getDataEnd(); ++i) { LLDrawable* drawable = *i; for (S32 j = 0; j < drawable->getNumFaces(); j++) @@ -1720,12 +1720,14 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - drawablep->setSpatialGroup(NULL); - if (!curp->removeObject(drawablep)) { OCT_ERRS << "Failed to remove drawable from octree!" << llendl; } + else + { + drawablep->setSpatialGroup(NULL); + } assert_octree_valid(mOctree); @@ -1996,7 +1998,7 @@ public: virtual void processGroup(LLSpatialGroup* group) { - llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->getData().empty()) + llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->isEmpty()) if (mRes < 2) { @@ -2063,7 +2065,7 @@ public: { LLSpatialGroup::OctreeNode* branch = group->mOctreeNode; - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) + for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) { LLDrawable* drawable = *i; @@ -2187,7 +2189,7 @@ public: LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); group->destroyGL(); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { LLDrawable* drawable = *i; if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup) @@ -2500,7 +2502,7 @@ void renderOctree(LLSpatialGroup* group) gGL.flush(); glLineWidth(1.f); gGL.flush(); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { LLDrawable* drawable = *i; if (!group->mSpatialPartition->isBridge()) @@ -2546,7 +2548,7 @@ void renderOctree(LLSpatialGroup* group) } else { - if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->getData().empty() + if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->isEmpty() && group->mSpatialPartition->mRenderByGroup) { col.setVec(0.8f, 0.4f, 0.1f, 0.1f); @@ -2614,7 +2616,7 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() && - !group->getData().empty(); + !group->isEmpty(); if (render_objects) { @@ -3356,7 +3358,7 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) void renderPhysicsShapes(LLSpatialGroup* group) { - for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { LLDrawable* drawable = *i; LLVOVolume* volume = drawable->getVOVolume(); @@ -3601,7 +3603,7 @@ public: LLVector3 center, size; - if (branch->getData().empty()) + if (branch->isEmpty()) { gGL.diffuseColor3f(1.f,0.2f,0.f); center.set(branch->getCenter().getF32ptr()); @@ -3637,8 +3639,8 @@ public: } gGL.begin(LLRender::TRIANGLES); - for (LLOctreeNode::const_element_iter iter = branch->getData().begin(); - iter != branch->getData().end(); + for (LLOctreeNode::const_element_iter iter = branch->getDataBegin(); + iter != branch->getDataEnd(); ++iter) { const LLVolumeTriangle* tri = *iter; @@ -3875,7 +3877,7 @@ public: if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) { - if (!group->getData().empty()) + if (!group->isEmpty()) { gGL.diffuseColor3f(0,0,1); drawBoxOutline(group->mObjectBounds[0], @@ -3883,7 +3885,7 @@ public: } } - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) + for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) { LLDrawable* drawable = *i; @@ -4068,7 +4070,7 @@ public: return; } - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) + for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) { LLDrawable* drawable = *i; @@ -4291,7 +4293,7 @@ public: virtual void visit(const LLSpatialGroup::OctreeNode* branch) { - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) + for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) { check(*i); } diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index d86221ddc..890a52f0d 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -330,8 +330,13 @@ public: void dirtyGeom() { setState(GEOM_DIRTY); } void dirtyMesh() { setState(MESH_DIRTY); } + + //octree wrappers to make code more readable element_list& getData() { return mOctreeNode->getData(); } + element_iter getDataBegin() { return mOctreeNode->getDataBegin(); } + element_iter getDataEnd() { return mOctreeNode->getDataEnd(); } U32 getElementCount() const { return mOctreeNode->getElementCount(); } + bool isEmpty() const { return mOctreeNode->isEmpty(); } void drawObjectBox(LLColor4 col); diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index 5a58ae770..6434dd619 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -645,7 +645,7 @@ void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count mFaceList.clear(); LLViewerCamera* camera = LLViewerCamera::getInstance(); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { LLDrawable* drawablep = *i; diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 434c8ca64..3dee80cce 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -582,7 +582,7 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co mFaceList.clear(); LLViewerCamera* camera = LLViewerCamera::getInstance(); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { LLDrawable* drawablep = *i; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index d8b34bd30..4431a9a33 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2390,7 +2390,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const produces_light = 1; } - for (S32 i = 0; i < num_faces; ++i) + for (S32 i = 0; i < (S32)num_faces; ++i) { const LLFace* face = drawablep->getFace(i); if (!face) continue; @@ -3481,7 +3481,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) LLFastTimer t(FTM_REBUILD_VOLUME_FACE_LIST); //get all the faces into a list - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) + for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { LLDrawable* drawablep = *drawable_iter; @@ -3887,7 +3887,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (!LLPipeline::sDelayVBUpdate) { //drawables have been rebuilt, clear rebuild status - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) + for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { LLDrawable* drawablep = *drawable_iter; drawablep->clearState(LLDrawable::REBUILD_ALL); @@ -3927,7 +3927,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) std::set mapped_buffers; - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) + for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { LLDrawable* drawablep = *drawable_iter; @@ -3951,8 +3951,14 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) if (buff) { llassert(!face->isState(LLFace::RIGGED)); - face->getGeometryVolume(*volume, face->getTEOffset(), - vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()); + + if (!face->getGeometryVolume(*volume, face->getTEOffset(), + vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex())) + { //something's gone wrong with the vertex buffer accounting, rebuild this group + group->dirtyGeom(); + gPipeline.markRebuild(group, TRUE); + } + if (buff->isLocked()) { @@ -3993,7 +3999,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ; warningsCount = 1; } - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) + for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { LLDrawable* drawablep = *drawable_iter; for (S32 i = 0; i < drawablep->getNumFaces(); ++i) @@ -4294,8 +4300,11 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: llassert(!facep->isState(LLFace::RIGGED)); - facep->getGeometryVolume(*volume, te_idx, - vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true); + if (!facep->getGeometryVolume(*volume, te_idx, + vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true)) + { + llwarns << "Failed to get geometry for face!" << llendl; + } if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) { @@ -4464,7 +4473,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun //for each drawable - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) + for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { LLDrawable* drawablep = *drawable_iter; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index f6cdbba74..9235a7b2a 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1174,7 +1174,7 @@ public: { LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty()) + if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->isEmpty()) { for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) { @@ -1781,7 +1781,7 @@ void LLPipeline::clearReferences() void check_references(LLSpatialGroup* group, LLDrawable* drawable) { - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { if (drawable == *i) { @@ -1803,7 +1803,7 @@ void check_references(LLDrawable* drawable, LLFace* face) void check_references(LLSpatialGroup* group, LLFace* face) { - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { LLDrawable* drawable = *i; check_references(drawable, face); @@ -2179,7 +2179,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) { - if (group->getData().empty()) + if (group->isEmpty()) { return; } @@ -2827,7 +2827,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) else { group->setVisible(); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { markVisible(*i, camera); } @@ -2915,7 +2915,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); if (!sSkipUpdate && group->changeLOD()) { - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { LLDrawable* drawablep = *i; stateSort(drawablep, camera); @@ -3051,7 +3051,7 @@ void forAllDrawables(LLCullResult::sg_iterator begin, { for (LLCullResult::sg_iterator i = begin; i != end; ++i) { - for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j) + for (LLSpatialGroup::element_iter j = (*i)->getDataBegin(); j != (*i)->getDataEnd(); ++j) { func(*j); } From bf3e605d3b47cd715bb76c7789b825b3b164bf80 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jul 2012 01:03:54 -0500 Subject: [PATCH 04/29] MAINT-646: Factor std::vector out of lloctree https://bitbucket.org/davep/viewer-development/changeset/efcec3eb374f --- indra/llmath/lloctree.h | 17 ++++++++++------- indra/llmath/llvolume.cpp | 2 +- indra/newview/llvovolume.cpp | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index 9a5918849..07ca00913 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -37,7 +37,6 @@ #include "v3math.h" #include "llvector4a.h" #include -#include #if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG #define OCT_ERRS LL_ERRS("OctreeErrors") @@ -93,7 +92,8 @@ public: typedef LLPointer* element_iter; typedef const LLPointer* const_element_iter; typedef typename std::vector*>::iterator tree_listener_iter; - typedef typename std::vector* > child_list; + typedef LLOctreeNode** child_list; + typedef LLOctreeNode** child_iter; typedef LLTreeNode BaseType; typedef LLOctreeNode oct_node; typedef LLOctreeListener oct_listener; @@ -242,7 +242,7 @@ public: } void accept(oct_traveler* visitor) { visitor->visit(this); } - virtual bool isLeaf() const { return mChild.empty(); } + virtual bool isLeaf() const { return mChildCount == 0; } U32 getElementCount() const { return mElementCount; } bool isEmpty() const { return mElementCount == 0; } @@ -527,8 +527,8 @@ public: void clearChildren() { - mChild.clear(); mChildCount = 0; + U32* foo = (U32*) mChildMap; foo[0] = foo[1] = 0xFFFFFFFF; } @@ -590,7 +590,7 @@ public: mChildMap[child->getOctant()] = mChildCount; - mChild.push_back(child); + mChild[mChildCount] = child; ++mChildCount; child->setParent(this); @@ -619,9 +619,12 @@ public: mChild[index]->destroy(); delete mChild[index]; } - mChild.erase(mChild.begin() + index); + --mChildCount; + mChild[index] = mChild[mChildCount]; + + //rebuild child map U32* foo = (U32*) mChildMap; foo[0] = foo[1] = 0xFFFFFFFF; @@ -677,7 +680,7 @@ protected: oct_node* mParent; U8 mOctant; - child_list mChild; + LLOctreeNode* mChild[8]; U8 mChildMap[8]; U32 mChildCount; diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 99094ce23..54a88a570 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -348,7 +348,7 @@ public: max.setMax(max, *tri->mV[2]); } } - else if (!branch->getChildren().empty()) + else if (!branch->isLeaf()) { //no data, but child nodes exist LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 4431a9a33..ba9b6c994 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -430,8 +430,8 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { LLViewerObject::idleUpdate(agent, world, time); - static LLFastTimer::DeclareTimer ftm("Volume Idle"); - LLFastTimer t(ftm); + //static LLFastTimer::DeclareTimer ftm("Volume Idle"); + //LLFastTimer t(ftm); if (mDead || mDrawable.isNull()) { From 9c58d42a3c204821221d4be80ffbc1ac57cb0248 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jul 2012 02:40:41 -0500 Subject: [PATCH 05/29] MAINT-646: Don't spend so much time fetching avatar physics params. https://bitbucket.org/davep/viewer-development/changeset/b895285ab0de --- indra/newview/llphysicsmotion.cpp | 117 ++++++++++++++++++++---------- indra/newview/llphysicsmotion.h | 37 ++++------ 2 files changed, 95 insertions(+), 59 deletions(-) diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index fbcd93912..1df29b37e 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -2,31 +2,25 @@ * @file llphysicsmotion.cpp * @brief Implementation of LLPhysicsMotion class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2011, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -74,6 +68,19 @@ inline F64 llsgn(const F64 a) class LLPhysicsMotion { public: + typedef enum + { + SMOOTHING = 0, + MASS, + GRAVITY, + SPRING, + GAIN, + DAMPING, + DRAG, + MAX_EFFECT, + NUM_PARAMS + } eParamName; + /* param_driver_name: The param that controls the params that are being affected by the physics. joint_name: The joint that the body part is attached to. The joint is @@ -107,8 +114,12 @@ public: mVelocity_local(0) { mJointState = new LLJointState; - } + for (U32 i = 0; i < NUM_PARAMS; ++i) + { + mParamCache[i] = NULL; + } + } void getString(std::ostringstream &oss); BOOL initialize(); @@ -124,19 +135,46 @@ public: void reset(); protected: - F32 getParamValue(const std::string& controller_key) - { - const controller_map_t::const_iterator& entry = mParamControllers.find(controller_key); + + F32 getParamValue(eParamName param) + { + static std::string controller_key[] = + { + "Smoothing", + "Mass", + "Gravity", + "Spring", + "Gain", + "Damping", + "Drag", + "MaxEffect" + }; + + if (!mParamCache[param]) + { + const controller_map_t::const_iterator& entry = mParamControllers.find(controller_key[param]); if (entry == mParamControllers.end()) { - return sDefaultController[controller_key]; + return sDefaultController[controller_key[param]]; } const std::string& param_name = (*entry).second.c_str(); - return mCharacter->getVisualParamWeight(param_name.c_str()); - } + mParamCache[param] = mCharacter->getVisualParam(param_name.c_str()); + } + + if (mParamCache[param]) + { + return mParamCache[param]->getWeight(); + } + else + { + return sDefaultController[controller_key[param]]; + } + } + + void setParamValue(LLViewerVisualParam *param, const F32 new_value_local, - F32 behavior_maxeffect); + F32 behavior_maxeffect); F32 toLocal(const LLVector3 &world); F32 calculateVelocity_local(); @@ -164,6 +202,8 @@ private: F32 mLastTime; + LLVisualParam* mParamCache[NUM_PARAMS]; + static default_controller_map_t sDefaultController; }; @@ -268,7 +308,7 @@ void LLPhysicsMotion::getString(std::ostringstream &oss) oss << " Controllers:" << std::endl; for(controller_map_t::const_iterator it = mParamControllers.begin(); it!= mParamControllers.end(); ++it) { - oss << " mParamControllers[\"" << it->first << "\"] = \"" << it->second << "\" =" << getParamValue(it->first) << std::endl; + oss << " mParamControllers[\"" << it->first << "\"] = \"" << it->second << "\" =" << mCharacter->getVisualParamWeight(it->first.c_str()) << std::endl; } } @@ -574,15 +614,16 @@ BOOL LLPhysicsMotion::onUpdate(F32 time) LLJoint *joint = mJointState->getJoint(); - const F32 behavior_mass = getParamValue("Mass"); - const F32 behavior_gravity = getParamValue("Gravity"); - const F32 behavior_spring = getParamValue("Spring"); - const F32 behavior_gain = getParamValue("Gain"); - const F32 behavior_damping = getParamValue("Damping"); - const F32 behavior_drag = getParamValue("Drag"); - const BOOL physics_test = FALSE; // Enable this to simulate bouncing on all parts. + const F32 behavior_mass = getParamValue(MASS); + const F32 behavior_gravity = getParamValue(GRAVITY); + const F32 behavior_spring = getParamValue(SPRING); + const F32 behavior_gain = getParamValue(GAIN); + const F32 behavior_damping = getParamValue(DAMPING); + const F32 behavior_drag = getParamValue(DRAG); + F32 behavior_maxeffect = getParamValue(MAX_EFFECT); + + const BOOL physics_test = FALSE; // Enable this to simulate bouncing on all parts. - F32 behavior_maxeffect = getParamValue("MaxEffect"); if (physics_test) behavior_maxeffect = 1.0f; diff --git a/indra/newview/llphysicsmotion.h b/indra/newview/llphysicsmotion.h index 7e6bddd17..7412c9d88 100644 --- a/indra/newview/llphysicsmotion.h +++ b/indra/newview/llphysicsmotion.h @@ -2,31 +2,25 @@ * @file llphysicsmotion.h * @brief Implementation of LLPhysicsMotion class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2011, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -113,6 +107,7 @@ public: virtual void onDeactivate(); LLCharacter* getCharacter() { return mCharacter; } + protected: void addMotion(LLPhysicsMotion *motion); private: From d57d0ceb0df1a549a3e97aa33030146d9b9da72c Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jul 2012 03:04:12 -0500 Subject: [PATCH 06/29] MAINT-646: Vectorize LLPolyMesh https://bitbucket.org/davep/viewer-development/changeset/668dcacd6e76 --- indra/newview/lldriverparam.cpp | 26 ++- indra/newview/lldriverparam.h | 10 +- indra/newview/llpolymesh.cpp | 349 +++++++++++++++------------- indra/newview/llpolymesh.h | 52 ++--- indra/newview/llpolymorph.cpp | 294 ++++++++++++----------- indra/newview/llpolymorph.h | 18 +- indra/newview/lltexlayerparams.h | 20 +- indra/newview/llviewervisualparam.h | 8 +- 8 files changed, 424 insertions(+), 353 deletions(-) diff --git a/indra/newview/lldriverparam.cpp b/indra/newview/lldriverparam.cpp index 93c437d2d..a1cba861c 100644 --- a/indra/newview/lldriverparam.cpp +++ b/indra/newview/lldriverparam.cpp @@ -155,6 +155,7 @@ LLDriverParam::LLDriverParam(LLVOAvatar *avatarp) : mAvatarp(avatarp), mWearablep(NULL) { + mDefaultVec.clear(); } LLDriverParam::LLDriverParam(LLWearable *wearablep) : @@ -162,6 +163,7 @@ LLDriverParam::LLDriverParam(LLWearable *wearablep) : mAvatarp(NULL), mWearablep(wearablep) { + mDefaultVec.clear(); } LLDriverParam::~LLDriverParam() @@ -341,18 +343,19 @@ F32 LLDriverParam::getTotalDistortion() return sum; } -const LLVector3 &LLDriverParam::getAvgDistortion() +const LLVector4a &LLDriverParam::getAvgDistortion() { // It's not actually correct to take the average of averages, but it good enough here. - LLVector3 sum; + LLVector4a sum; + sum.clear(); S32 count = 0; for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) { LLDrivenEntry* driven = &(*iter); - sum += driven->mParam->getAvgDistortion(); + sum.add(driven->mParam->getAvgDistortion()); count++; } - sum /= (F32)count; + sum.mul( 1.f/(F32)count); mDefaultVec = sum; return mDefaultVec; @@ -375,21 +378,22 @@ F32 LLDriverParam::getMaxDistortion() } -LLVector3 LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) +LLVector4a LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { - LLVector3 sum; + LLVector4a sum; + sum.clear(); for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) { LLDrivenEntry* driven = &(*iter); - sum += driven->mParam->getVertexDistortion( index, poly_mesh ); + sum.add(driven->mParam->getVertexDistortion( index, poly_mesh )); } return sum; } -const LLVector3* LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) +const LLVector4a* LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { mCurrentDistortionParam = NULL; - const LLVector3* v = NULL; + const LLVector4a* v = NULL; for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) { LLDrivenEntry* driven = &(*iter); @@ -404,7 +408,7 @@ const LLVector3* LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly return v; }; -const LLVector3* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) +const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { llassert( mCurrentDistortionParam ); if( !mCurrentDistortionParam ) @@ -432,7 +436,7 @@ const LLVector3* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_ } // We're already in the middle of a param's distortions, so get the next one. - const LLVector3* v = driven->mParam->getNextDistortion( index, poly_mesh ); + const LLVector4a* v = driven->mParam->getNextDistortion( index, poly_mesh ); if( (!v) && (iter != mDriven.end()) ) { // This param is finished, so start the next param. It might not have any diff --git a/indra/newview/lldriverparam.h b/indra/newview/lldriverparam.h index fb1b44458..7a4d711d4 100644 --- a/indra/newview/lldriverparam.h +++ b/indra/newview/lldriverparam.h @@ -105,18 +105,18 @@ public: // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion(); - /*virtual*/ const LLVector3& getAvgDistortion(); + /*virtual*/ const LLVector4a& getAvgDistortion(); /*virtual*/ F32 getMaxDistortion(); - /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh); - /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh); - /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh); + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh); + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); protected: F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight); void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake); - LLVector3 mDefaultVec; // temp holder + LLVector4a mDefaultVec; // temp holder typedef std::vector entry_list_t; entry_list_t mDriven; LLViewerVisualParam* mCurrentDistortionParam; diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp index 491cf43f3..d7b342b25 100644 --- a/indra/newview/llpolymesh.cpp +++ b/indra/newview/llpolymesh.cpp @@ -229,16 +229,20 @@ U32 LLPolyMeshSharedData::getNumKB() BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices ) { U32 i; - mBaseCoords = new LLVector3[ numVertices ]; - mBaseNormals = new LLVector3[ numVertices ]; - mBaseBinormals = new LLVector3[ numVertices ]; + mBaseCoords = new LLVector4a[ numVertices ]; + mBaseNormals = new LLVector4a[ numVertices ]; + mBaseBinormals = new LLVector4a[ numVertices ]; mTexCoords = new LLVector2[ numVertices ]; mDetailTexCoords = new LLVector2[ numVertices ]; mWeights = new F32[ numVertices ]; for (i = 0; i < numVertices; i++) { + mBaseCoords[i].clear(); + mBaseNormals[i].clear(); + mBaseBinormals[i].clear(); + mTexCoords[i].clear(); mWeights[i] = 0.f; - } + } mNumVertices = numVertices; return TRUE; } @@ -408,40 +412,48 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) allocateVertexData( numVertices ); - //---------------------------------------------------------------- - // Coords - //---------------------------------------------------------------- - numRead = fread(mBaseCoords, 3*sizeof(float), numVertices, fp); - llendianswizzle(mBaseCoords, sizeof(float), 3*numVertices); - if (numRead != numVertices) + for (U16 i = 0; i < numVertices; ++i) { - llerrs << "can't read Coordinates from " << fileName << llendl; - return FALSE; - } + //---------------------------------------------------------------- + // Coords + //---------------------------------------------------------------- + numRead = fread(&mBaseCoords[i], sizeof(float), 3, fp); + llendianswizzle(&mBaseCoords[i], sizeof(float), 3); + if (numRead != 3) + { + llerrs << "can't read Coordinates from " << fileName << llendl; + return FALSE; + } + } - //---------------------------------------------------------------- - // Normals - //---------------------------------------------------------------- - numRead = fread(mBaseNormals, 3*sizeof(float), numVertices, fp); - llendianswizzle(mBaseNormals, sizeof(float), 3*numVertices); - if (numRead != numVertices) - { - llerrs << " can't read Normals from " << fileName << llendl; - return FALSE; - } + for (U16 i = 0; i < numVertices; ++i) + { + //---------------------------------------------------------------- + // Normals + //---------------------------------------------------------------- + numRead = fread(&mBaseNormals[i], sizeof(float), 3, fp); + llendianswizzle(&mBaseNormals[i], sizeof(float), 3); + if (numRead != 3) + { + llerrs << " can't read Normals from " << fileName << llendl; + return FALSE; + } + } - //---------------------------------------------------------------- - // Binormals - //---------------------------------------------------------------- - numRead = fread(mBaseBinormals, 3*sizeof(float), numVertices, fp); - llendianswizzle(mBaseBinormals, sizeof(float), 3*numVertices); - if (numRead != numVertices) - { - llerrs << " can't read Binormals from " << fileName << llendl; - return FALSE; + for (U16 i = 0; i < numVertices; ++i) + { + //---------------------------------------------------------------- + // Binormals + //---------------------------------------------------------------- + numRead = fread(&mBaseBinormals[i], sizeof(float), 3, fp); + llendianswizzle(&mBaseBinormals[i], sizeof(float), 3); + if (numRead != 3) + { + llerrs << " can't read Binormals from " << fileName << llendl; + return FALSE; + } } - //---------------------------------------------------------------- // TexCoords //---------------------------------------------------------------- @@ -767,21 +779,28 @@ LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_ { // Allocate memory without initializing every vector // NOTE: This makes asusmptions about the size of LLVector[234] - int nverts = mSharedData->mNumVertices; - int nfloats = nverts * (2*4 + 3*3 + 2 + 4); + S32 nverts = mSharedData->mNumVertices; + //make sure it's an even number of verts for alignment + nverts += nverts%2; + S32 nfloats = nverts * ( + 4 + //coords + 4 + //normals + 4 + //weights + 2 + //coords + 4 + //scaled normals + 4 + //binormals + 4); //scaled binormals + //use 16 byte aligned vertex data to make LLPolyMesh SSE friendly mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4); - int offset = 0; - mCoords = (LLVector4*)(mVertexData + offset); offset += 4*nverts; - mNormals = (LLVector4*)(mVertexData + offset); offset += 4*nverts; - mClothingWeights = (LLVector4*)(mVertexData + offset); offset += 4*nverts; - mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts; - - // these members don't need to be 16-byte aligned, but the first one might be - // read during an aligned memcpy of mTexCoords - mScaledNormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts; - mBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts; - mScaledBinormals = (LLVector3*)(mVertexData + offset); offset += 3*nverts; + S32 offset = 0; + mCoords = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + mNormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + mClothingWeights = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + mTexCoords = (LLVector2*)(mVertexData + offset); offset += 2*nverts; + mScaledNormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + mBinormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; + mScaledBinormals = (LLVector4a*)(mVertexData + offset); offset += 4*nverts; initializeForMorph(); } } @@ -966,38 +985,47 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) //---------------------------------------------------------------- // Coords //---------------------------------------------------------------- - LLVector3* coords = mSharedData->mBaseCoords; - - llendianswizzle(coords, sizeof(float), 3*numVertices); - if (fwrite(coords, 3*sizeof(float), numVertices, fp) != numVertices) + for (U16 i = 0; i < numVertices; ++i) { - llwarns << "Short write" << llendl; + LLVector4a& coords = mSharedData->mBaseCoords[i]; + + llendianswizzle(coords.getF32ptr(), sizeof(float), 3); + if (fwrite(coords.getF32ptr(), 3*sizeof(float), 1, fp) != 1) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(coords.getF32ptr(), sizeof(float), 3); } - llendianswizzle(coords, sizeof(float), 3*numVertices); //---------------------------------------------------------------- // Normals //---------------------------------------------------------------- - LLVector3* normals = mSharedData->mBaseNormals; - - llendianswizzle(normals, sizeof(float), 3*numVertices); - if (fwrite(normals, 3*sizeof(float), numVertices, fp) != numVertices) + for (U16 i = 0; i < numVertices; ++i) { - llwarns << "Short write" << llendl; + LLVector4a& normals = mSharedData->mBaseNormals[i]; + + llendianswizzle(normals.getF32ptr(), sizeof(float), 3); + if (fwrite(normals.getF32ptr(), 3*sizeof(float), 1, fp) != 1) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(normals.getF32ptr(), sizeof(float), 3); } - llendianswizzle(normals, sizeof(float), 3*numVertices); //---------------------------------------------------------------- // Binormals //---------------------------------------------------------------- - LLVector3* binormals = mSharedData->mBaseBinormals; - - llendianswizzle(binormals, sizeof(float), 3*numVertices); - if (fwrite(binormals, 3*sizeof(float), numVertices, fp) != numVertices) + for (U16 i = 0; i < numVertices; ++i) { - llwarns << "Short write" << llendl; + LLVector4a& binormals = mSharedData->mBaseBinormals[i]; + + llendianswizzle(binormals.getF32ptr(), sizeof(float), 3); + if (fwrite(binormals.getF32ptr(), 3*sizeof(float), 1, fp) != 1) + { + llwarns << "Short write" << llendl; + } + llendianswizzle(binormals.getF32ptr(), sizeof(float), 3); } - llendianswizzle(binormals, sizeof(float), 3*numVertices); //---------------------------------------------------------------- // TexCoords @@ -1224,24 +1252,24 @@ BOOL LLPolyMesh::saveOBJ(LLFILE *fp) int nfaces = mSharedData->mNumFaces; int i; - LLVector4* coords = getWritableCoords(); + LLVector4a* coords = getWritableCoords(); for ( i=0; imBaseCoords, mCoords, sizeof(LLVector3) * mSharedData->mNumVertices); - memcpy(mSharedData->mBaseNormals, mNormals, sizeof(LLVector3) * mSharedData->mNumVertices); - memcpy(mSharedData->mBaseBinormals, mBinormals, sizeof(LLVector3) * mSharedData->mNumVertices); - memcpy(mSharedData->mTexCoords, mTexCoords, sizeof(LLVector2) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mSharedData->mBaseCoords, (F32*) mCoords, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mSharedData->mBaseNormals, (F32*) mNormals, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mSharedData->mBaseBinormals, (F32*) mBinormals, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mSharedData->mTexCoords, (F32*) mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2)); // Update all avatars by applying the delta @@ -1479,27 +1496,29 @@ BOOL LLPolyMesh::setSharedFromCurrent() LLPolyMesh* mesh = avatarp->getMesh(mSharedData); if (mesh) { - LLVector4 *mesh_coords = mesh->getWritableCoords(); - LLVector4 *mesh_normals = mesh->getWritableNormals(); - LLVector3 *mesh_binormals = mesh->getWritableBinormals(); - LLVector2 *mesh_tex_coords = mesh->getWritableTexCoords(); - LLVector3 *mesh_scaled_normals = mesh->getScaledNormals(); - LLVector3 *mesh_scaled_binormals = mesh->getScaledBinormals(); + LLVector4a *mesh_coords = mesh->getWritableCoords(); + LLVector4a *mesh_normals = mesh->getWritableNormals(); + LLVector4a *mesh_binormals = mesh->getWritableBinormals(); + LLVector2 *mesh_tex_coords = mesh->getWritableTexCoords(); + LLVector4a *mesh_scaled_normals = mesh->getScaledNormals(); + LLVector4a *mesh_scaled_binormals = mesh->getScaledBinormals(); for( vert_index = 0; vert_index < nverts; vert_index++) { - mesh_coords[vert_index] -= delta_coords[vert_index]; + mesh_coords[vert_index].sub(delta_coords[vert_index]); mesh_tex_coords[vert_index] -= delta_tex_coords[vert_index]; - mesh_scaled_normals[vert_index] -= LLVector3(delta_normals[vert_index]); - LLVector3 normalized_normal = mesh_scaled_normals[vert_index]; - normalized_normal.normVec(); - mesh_normals[vert_index] = LLVector4(normalized_normal); + mesh_scaled_normals[vert_index].sub(delta_normals[vert_index]); + LLVector4a normalized_normal = mesh_scaled_normals[vert_index]; + normalized_normal.normalize3(); + mesh_normals[vert_index] = normalized_normal; - mesh_scaled_binormals[vert_index] -= delta_binormals[vert_index]; - LLVector3 tangent = mesh_scaled_binormals[vert_index] % normalized_normal; - LLVector3 normalized_binormal = normalized_normal % tangent; - normalized_binormal.normVec(); + mesh_scaled_binormals[vert_index].sub(delta_binormals[vert_index]); + LLVector4a tangent; + tangent.setCross3(mesh_scaled_binormals[vert_index], normalized_normal); + LLVector4a normalized_binormal; + normalized_binormal.setCross3(normalized_normal, tangent); + normalized_binormal.normalize3(); mesh_binormals[vert_index] = normalized_binormal; } @@ -1598,7 +1617,7 @@ void LLPolyMesh::dumpDiagInfo(void*) //----------------------------------------------------------------------------- // getWritableCoords() //----------------------------------------------------------------------------- -LLVector4 *LLPolyMesh::getWritableCoords() +LLVector4a *LLPolyMesh::getWritableCoords() { return mCoords; } @@ -1606,7 +1625,7 @@ LLVector4 *LLPolyMesh::getWritableCoords() //----------------------------------------------------------------------------- // getWritableNormals() //----------------------------------------------------------------------------- -LLVector4 *LLPolyMesh::getWritableNormals() +LLVector4a *LLPolyMesh::getWritableNormals() { return mNormals; } @@ -1614,7 +1633,7 @@ LLVector4 *LLPolyMesh::getWritableNormals() //----------------------------------------------------------------------------- // getWritableBinormals() //----------------------------------------------------------------------------- -LLVector3 *LLPolyMesh::getWritableBinormals() +LLVector4a *LLPolyMesh::getWritableBinormals() { return mBinormals; } @@ -1623,7 +1642,7 @@ LLVector3 *LLPolyMesh::getWritableBinormals() //----------------------------------------------------------------------------- // getWritableClothingWeights() //----------------------------------------------------------------------------- -LLVector4 *LLPolyMesh::getWritableClothingWeights() +LLVector4a *LLPolyMesh::getWritableClothingWeights() { return mClothingWeights; } @@ -1639,7 +1658,7 @@ LLVector2 *LLPolyMesh::getWritableTexCoords() //----------------------------------------------------------------------------- // getScaledNormals() //----------------------------------------------------------------------------- -LLVector3 *LLPolyMesh::getScaledNormals() +LLVector4a *LLPolyMesh::getScaledNormals() { return mScaledNormals; } @@ -1647,7 +1666,7 @@ LLVector3 *LLPolyMesh::getScaledNormals() //----------------------------------------------------------------------------- // getScaledBinormals() //----------------------------------------------------------------------------- -LLVector3 *LLPolyMesh::getScaledBinormals() +LLVector4a *LLPolyMesh::getScaledBinormals() { return mScaledBinormals; } @@ -1661,19 +1680,20 @@ void LLPolyMesh::initializeForMorph() if (!mSharedData) return; + LLVector4a::memcpyNonAliased16((F32*) mCoords, (F32*) mSharedData->mBaseCoords, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2)); + for (U32 i = 0; i < (U32)mSharedData->mNumVertices; ++i) { - mCoords[i] = LLVector4(mSharedData->mBaseCoords[i]); - mNormals[i] = LLVector4(mSharedData->mBaseNormals[i]); + mClothingWeights[i].clear(); } - - memcpy(mScaledNormals, mSharedData->mBaseNormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/ - memcpy(mBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/ - memcpy(mScaledBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices); /*Flawfinder: ignore*/ - memcpy(mTexCoords, mSharedData->mTexCoords, sizeof(LLVector2) * mSharedData->mNumVertices); /*Flawfinder: ignore*/ - memset(mClothingWeights, 0, sizeof(LLVector4) * mSharedData->mNumVertices); } + //----------------------------------------------------------------------------- // getMorphList() //----------------------------------------------------------------------------- @@ -1818,8 +1838,8 @@ BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node) //----------------------------------------------------------------------------- LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLVOAvatar *avatarp) { - mAvatar = avatarp; - mDefaultVec.setVec(0.001f, 0.001f, 0.001f); + mAvatar = avatarp; + mDefaultVec.splat(0.001f); } //----------------------------------------------------------------------------- @@ -1947,36 +1967,49 @@ LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data, const LLVector3 &direction, const std::string &name) { - LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); - cloned_morph_data->mName = name; - for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) - { - cloned_morph_data->mCoords[v] = direction; - cloned_morph_data->mNormals[v] = LLVector3(0,0,0); - cloned_morph_data->mBinormals[v] = LLVector3(0,0,0); - } - return cloned_morph_data; + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + LLVector4a dir; + dir.load3(direction.mV); + + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + cloned_morph_data->mCoords[v] = dir; + cloned_morph_data->mNormals[v].clear(); + cloned_morph_data->mBinormals[v].clear(); + } + return cloned_morph_data; } LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data, F32 scale, const std::string &name) { - LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); - cloned_morph_data->mName = name; - for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) - { - cloned_morph_data->mCoords[v] = src_data->mCoords[v]*scale; - cloned_morph_data->mNormals[v] = src_data->mNormals[v]*scale; - cloned_morph_data->mBinormals[v] = src_data->mBinormals[v]*scale; - if (cloned_morph_data->mCoords[v][1] < 0) - { - cloned_morph_data->mCoords[v][1] *= -1; - cloned_morph_data->mNormals[v][1] *= -1; - cloned_morph_data->mBinormals[v][1] *= -1; - } - } - return cloned_morph_data; + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + + LLVector4a sc; + sc.splat(scale); + + LLVector4a nsc; + nsc.set(scale, -scale, scale, scale); + + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + if (cloned_morph_data->mCoords[v][1] < 0) + { + cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc); + cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc); + cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc); + } + else + { + cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc); + cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc); + cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc); + } + } + return cloned_morph_data; } // End diff --git a/indra/newview/llpolymesh.h b/indra/newview/llpolymesh.h index 4b7927564..d09909309 100644 --- a/indra/newview/llpolymesh.h +++ b/indra/newview/llpolymesh.h @@ -73,9 +73,9 @@ private: // vertex data S32 mNumVertices; - LLVector3 *mBaseCoords; - LLVector3 *mBaseNormals; - LLVector3 *mBaseBinormals; + LLVector4a *mBaseCoords; + LLVector4a *mBaseNormals; + LLVector4a *mBaseBinormals; LLVector2 *mTexCoords; LLVector2 *mDetailTexCoords; F32 *mWeights; @@ -235,41 +235,41 @@ public: } // Get coords - const LLVector4 *getCoords() const{ + const LLVector4a *getCoords() const{ return mCoords; } // non const version - LLVector4 *getWritableCoords(); + LLVector4a *getWritableCoords(); // Get normals - const LLVector4 *getNormals() const{ + const LLVector4a *getNormals() const{ return mNormals; } // Get normals - const LLVector3 *getBinormals() const{ + const LLVector4a *getBinormals() const{ return mBinormals; } // Get base mesh normals - const LLVector3 *getBaseNormals() const{ + const LLVector4a *getBaseNormals() const{ llassert(mSharedData); return mSharedData->mBaseNormals; } // Get base mesh normals - const LLVector3 *getBaseBinormals() const{ + const LLVector4a *getBaseBinormals() const{ llassert(mSharedData); return mSharedData->mBaseBinormals; } // intermediate morphed normals and output normals - LLVector4 *getWritableNormals(); - LLVector3 *getScaledNormals(); + LLVector4a *getWritableNormals(); + LLVector4a *getScaledNormals(); - LLVector3 *getWritableBinormals(); - LLVector3 *getScaledBinormals(); + LLVector4a *getWritableBinormals(); + LLVector4a *getScaledBinormals(); // Get texCoords const LLVector2 *getTexCoords() const { @@ -293,9 +293,9 @@ public: F32 *getWritableWeights() const; - LLVector4 *getWritableClothingWeights(); + LLVector4a *getWritableClothingWeights(); - const LLVector4 *getClothingWeights() + const LLVector4a *getClothingWeights() { return mClothingWeights; } @@ -363,17 +363,17 @@ protected: // Single array of floats for allocation / deletion F32 *mVertexData; // deformed vertices (resulting from application of morph targets) - LLVector4 *mCoords; + LLVector4a *mCoords; // deformed normals (resulting from application of morph targets) - LLVector3 *mScaledNormals; + LLVector4a *mScaledNormals; // output normals (after normalization) - LLVector4 *mNormals; + LLVector4a *mNormals; // deformed binormals (resulting from application of morph targets) - LLVector3 *mScaledBinormals; + LLVector4a *mScaledBinormals; // output binormals (after normalization) - LLVector3 *mBinormals; + LLVector4a *mBinormals; // weight values that mark verts as clothing/skin - LLVector4 *mClothingWeights; + LLVector4a *mClothingWeights; // output texture coordinates LLVector2 *mTexCoords; @@ -441,17 +441,17 @@ public: // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion() { return 0.1f; } - /*virtual*/ const LLVector3& getAvgDistortion() { return mDefaultVec; } + /*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; } /*virtual*/ F32 getMaxDistortion() { return 0.1f; } - /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector3(0.001f, 0.001f, 0.001f);} - /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;}; - /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;}; + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector4a(0.001f, 0.001f, 0.001f);} + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;}; + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;}; protected: typedef std::map joint_vec_map_t; joint_vec_map_t mJointScales; joint_vec_map_t mJointOffsets; - LLVector3 mDefaultVec; + LLVector4a mDefaultVec; // Backlink only; don't make this an LLPointer. LLVOAvatar *mAvatar; }; diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp index 73a0b525c..b43837e89 100644 --- a/indra/newview/llpolymorph.cpp +++ b/indra/newview/llpolymorph.cpp @@ -49,7 +49,7 @@ LLPolyMorphData::LLPolyMorphData(const std::string& morph_name) mNumIndices = 0; mCurrentIndex = 0; mTotalDistortion = 0.f; - mAvgDistortion.zeroVec(); + mAvgDistortion.clear(); mMaxDistortion = 0.f; mVertexIndices = NULL; mCoords = NULL; @@ -74,9 +74,9 @@ LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) : { const S32 numVertices = mNumIndices; - mCoords = new LLVector3[numVertices]; - mNormals = new LLVector3[numVertices]; - mBinormals = new LLVector3[numVertices]; + mCoords = new LLVector4a[numVertices]; + mNormals = new LLVector4a[numVertices]; + mBinormals = new LLVector4a[numVertices]; mTexCoords = new LLVector2[numVertices]; mVertexIndices = new U32[numVertices]; @@ -90,6 +90,7 @@ LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) : } } + //----------------------------------------------------------------------------- // ~LLPolyMorphData() //----------------------------------------------------------------------------- @@ -121,16 +122,16 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) //------------------------------------------------------------------------- // allocate vertices //------------------------------------------------------------------------- - mCoords = new LLVector3[numVertices]; - mNormals = new LLVector3[numVertices]; - mBinormals = new LLVector3[numVertices]; + mCoords = new LLVector4a[numVertices]; + mNormals = new LLVector4a[numVertices]; + mBinormals = new LLVector4a[numVertices]; mTexCoords = new LLVector2[numVertices]; // Actually, we are allocating more space than we need for the skiplist mVertexIndices = new U32[numVertices]; mNumIndices = 0; mTotalDistortion = 0.f; mMaxDistortion = 0.f; - mAvgDistortion.zeroVec(); + mAvgDistortion.clear(); mMesh = mesh; //------------------------------------------------------------------------- @@ -152,36 +153,36 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) } - numRead = fread(&mCoords[v].mV, sizeof(F32), 3, fp); - llendianswizzle(&mCoords[v].mV, sizeof(F32), 3); + numRead = fread(&mCoords[v], sizeof(F32), 3, fp); + llendianswizzle(&mCoords[v], sizeof(F32), 3); if (numRead != 3) { llwarns << "Can't read morph target vertex coordinates" << llendl; return FALSE; } - F32 magnitude = mCoords[v].magVec(); + F32 magnitude = mCoords[v].getLength3().getF32(); mTotalDistortion += magnitude; - mAvgDistortion.mV[VX] += fabs(mCoords[v].mV[VX]); - mAvgDistortion.mV[VY] += fabs(mCoords[v].mV[VY]); - mAvgDistortion.mV[VZ] += fabs(mCoords[v].mV[VZ]); + LLVector4a t; + t.setAbs(mCoords[v]); + mAvgDistortion.add(t); if (magnitude > mMaxDistortion) { mMaxDistortion = magnitude; } - numRead = fread(&mNormals[v].mV, sizeof(F32), 3, fp); - llendianswizzle(&mNormals[v].mV, sizeof(F32), 3); + numRead = fread(&mNormals[v], sizeof(F32), 3, fp); + llendianswizzle(&mNormals[v], sizeof(F32), 3); if (numRead != 3) { llwarns << "Can't read morph target normal" << llendl; return FALSE; } - numRead = fread(&mBinormals[v].mV, sizeof(F32), 3, fp); - llendianswizzle(&mBinormals[v].mV, sizeof(F32), 3); + numRead = fread(&mBinormals[v], sizeof(F32), 3, fp); + llendianswizzle(&mBinormals[v], sizeof(F32), 3); if (numRead != 3) { llwarns << "Can't read morph target binormal" << llendl; @@ -200,8 +201,8 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) mNumIndices++; } - mAvgDistortion = mAvgDistortion * (1.f/(F32)mNumIndices); - mAvgDistortion.normVec(); + mAvgDistortion.mul(1.f/(F32)mNumIndices); + mAvgDistortion.normalize3fast(); return TRUE; } @@ -235,26 +236,26 @@ BOOL LLPolyMorphData::saveLLM(LLFILE *fp) } llendianswizzle(&mVertexIndices[v], sizeof(U32), 1); - llendianswizzle(&mCoords[v].mV, sizeof(F32), 3); - if (fwrite(&mCoords[v].mV, sizeof(F32), 3, fp) != 3) + llendianswizzle(mCoords[v].getF32ptr(), sizeof(F32), 3); + if (fwrite(mCoords[v].getF32ptr(), sizeof(F32), 3, fp) != 3) { llwarns << "Short write" << llendl; } - llendianswizzle(&mCoords[v].mV, sizeof(F32), 3); + llendianswizzle(mCoords[v].getF32ptr(), sizeof(F32), 3); - llendianswizzle(&mNormals[v].mV, sizeof(F32), 3); - if (fwrite(&mNormals[v].mV, sizeof(F32), 3, fp) != 3) + llendianswizzle(mNormals[v].getF32ptr(), sizeof(F32), 3); + if (fwrite(mNormals[v].getF32ptr(), sizeof(F32), 3, fp) != 3) { llwarns << "Short write" << llendl; } - llendianswizzle(&mNormals[v].mV, sizeof(F32), 3); + llendianswizzle(mNormals[v].getF32ptr(), sizeof(F32), 3); - llendianswizzle(&mBinormals[v].mV, sizeof(F32), 3); - if (fwrite(&mBinormals[v].mV, sizeof(F32), 3, fp) != 3) + llendianswizzle(mBinormals[v].getF32ptr(), sizeof(F32), 3); + if (fwrite(mBinormals[v].getF32ptr(), sizeof(F32), 3, fp) != 3) { llwarns << "Short write" << llendl; } - llendianswizzle(&mBinormals[v].mV, sizeof(F32), 3); + llendianswizzle(mBinormals[v].getF32ptr(), sizeof(F32), 3); llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2); if (fwrite(&mTexCoords[v].mV, sizeof(F32), 2, fp) != 2) @@ -277,17 +278,17 @@ BOOL LLPolyMorphData::saveOBJ(LLFILE *fp) LLPolyMesh mesh(mMesh, NULL); - LLVector4 *coords = mesh.getWritableCoords(); - LLVector4 *normals = mesh.getWritableNormals(); + LLVector4a *coords = mesh.getWritableCoords(); + LLVector4a *normals = mesh.getWritableNormals(); LLVector2 *tex_coords = mesh.getWritableTexCoords(); for(U32 vert_index_morph = 0; vert_index_morph < mNumIndices; vert_index_morph++) { S32 vert_index_mesh = mVertexIndices[vert_index_morph]; - coords[vert_index_mesh] += LLVector4(mCoords[vert_index_morph]); - normals[vert_index_mesh] += LLVector4(mNormals[vert_index_morph]); - normals[vert_index_mesh].normVec(); + coords[vert_index_mesh].add(mCoords[vert_index_morph]); + normals[vert_index_mesh].add(mNormals[vert_index_morph]); + normals[vert_index_mesh].normalize3(); tex_coords[vert_index_mesh] += mTexCoords[vert_index_morph]; } @@ -302,9 +303,9 @@ BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) if (!morph) return FALSE; - LLVector4 *morph_coords = morph->getWritableCoords(); - LLVector4 *morph_normals = morph->getWritableNormals(); - LLVector3 *morph_binormals = morph->getWritableBinormals(); + LLVector4a *morph_coords = morph->getWritableCoords(); + LLVector4a *morph_normals = morph->getWritableNormals(); + LLVector4a *morph_binormals = morph->getWritableBinormals(); LLVector2 *morph_tex_coords = morph->getWritableTexCoords(); // We now have the morph loaded as a mesh. We have to subtract the @@ -313,19 +314,19 @@ BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) LLPolyMesh delta(mMesh, NULL); U32 nverts = delta.getNumVertices(); - LLVector4 *delta_coords = delta.getWritableCoords(); - LLVector4 *delta_normals = delta.getWritableNormals(); - LLVector3 *delta_binormals = delta.getWritableBinormals(); + LLVector4a *delta_coords = delta.getWritableCoords(); + LLVector4a *delta_normals = delta.getWritableNormals(); + LLVector4a *delta_binormals = delta.getWritableBinormals(); LLVector2 *delta_tex_coords = delta.getWritableTexCoords(); U32 num_significant = 0; U32 vert_index; for( vert_index = 0; vert_index < nverts; vert_index++) { - delta_coords[vert_index] = morph_coords[vert_index] - delta_coords[vert_index]; - delta_normals[vert_index] = morph_normals[vert_index] - delta_normals[vert_index]; - delta_binormals[vert_index] = morph_binormals[vert_index] - delta_binormals[vert_index]; - delta_tex_coords[vert_index] = morph_tex_coords[vert_index] - delta_tex_coords[vert_index]; + delta_coords[vert_index].setSub( morph_coords[vert_index], delta_coords[vert_index]); + delta_normals[vert_index].setSub( morph_normals[vert_index], delta_normals[vert_index]); + delta_binormals[vert_index].setSub( morph_binormals[vert_index], delta_binormals[vert_index]); + delta_tex_coords[vert_index] = morph_tex_coords[vert_index] - delta_tex_coords[vert_index]; // For the normals and binormals, we really want the deltas // to be perpendicular to the mesh (bi)normals in the plane @@ -333,10 +334,10 @@ BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) // that the morph (bi)normals form the hypotenuses of right // triangles. Right now, we just compute the difference vector. - if (delta_coords[vert_index].length() > SIGNIFICANT_DELTA - || delta_normals[vert_index].length() > SIGNIFICANT_DELTA - || delta_binormals[vert_index].length() > SIGNIFICANT_DELTA - || delta_tex_coords[vert_index].length() > SIGNIFICANT_DELTA) + if (delta_coords[vert_index].getLength3().getF32() > SIGNIFICANT_DELTA + || delta_normals[vert_index].getLength3().getF32() > SIGNIFICANT_DELTA + || delta_binormals[vert_index].getLength3().getF32() > SIGNIFICANT_DELTA + || delta_tex_coords[vert_index].length() > SIGNIFICANT_DELTA) { num_significant++; } @@ -353,39 +354,39 @@ BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) if (num_significant == 0) nindices = 1; - LLVector3* new_coords = new LLVector3[nindices]; - LLVector3* new_normals = new LLVector3[nindices]; - LLVector3* new_binormals = new LLVector3[nindices]; + LLVector4a* new_coords = new LLVector4a[nindices]; + LLVector4a* new_normals = new LLVector4a[nindices]; + LLVector4a* new_binormals = new LLVector4a[nindices]; LLVector2* new_tex_coords = new LLVector2[nindices]; U32* new_vertex_indices = new U32[nindices]; // We'll set the distortion directly mTotalDistortion = 0.f; mMaxDistortion = 0.f; - mAvgDistortion.zeroVec(); + mAvgDistortion.clear(); U32 morph_index = 0; for( vert_index = 0; vert_index < nverts; vert_index++) { - if (delta_coords[vert_index].length() > SIGNIFICANT_DELTA - || delta_normals[vert_index].length() > SIGNIFICANT_DELTA - || delta_binormals[vert_index].length() > SIGNIFICANT_DELTA - || delta_tex_coords[vert_index].length() > SIGNIFICANT_DELTA + if (delta_coords[vert_index].getLength3().getF32() > SIGNIFICANT_DELTA + || delta_normals[vert_index].getLength3().getF32() > SIGNIFICANT_DELTA + || delta_binormals[vert_index].getLength3().getF32() > SIGNIFICANT_DELTA + || delta_tex_coords[vert_index].length() > SIGNIFICANT_DELTA || num_significant == 0) { new_vertex_indices[morph_index] = vert_index; - new_coords[morph_index] = LLVector3(delta_coords[vert_index]); - new_normals[morph_index] = LLVector3(delta_normals[vert_index]); + new_coords[morph_index] = delta_coords[vert_index]; + new_normals[morph_index] = delta_normals[vert_index]; new_binormals[morph_index] = delta_binormals[vert_index]; new_tex_coords[morph_index] = delta_tex_coords[vert_index]; - F32 magnitude = new_coords[morph_index].magVec(); + F32 magnitude = new_coords[morph_index].getLength3().getF32(); mTotalDistortion += magnitude; - mAvgDistortion.mV[VX] += fabs(new_coords[morph_index].mV[VX]); - mAvgDistortion.mV[VY] += fabs(new_coords[morph_index].mV[VY]); - mAvgDistortion.mV[VZ] += fabs(new_coords[morph_index].mV[VZ]); + LLVector4a t; + t.setAbs(new_coords[morph_index]); + mAvgDistortion.add(t); if (magnitude > mMaxDistortion) { @@ -397,8 +398,8 @@ BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) } } - mAvgDistortion = mAvgDistortion * (1.f/(F32)nindices); - mAvgDistortion.normVec(); + mAvgDistortion.mul(1.f/(F32)nindices); + mAvgDistortion.normalize3(); //------------------------------------------------------------------------- // compute the change in the morph @@ -412,9 +413,9 @@ BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) { vert_index = mVertexIndices[morph_index]; - delta_coords[vert_index] -= LLVector4(mCoords[morph_index]); - delta_normals[vert_index] -= LLVector4(mNormals[morph_index]); - delta_binormals[vert_index] -= mBinormals[morph_index]; + delta_coords[vert_index].sub( mCoords[morph_index]); + delta_normals[vert_index].sub( mNormals[morph_index]); + delta_binormals[vert_index].sub(mBinormals[morph_index]); delta_tex_coords[vert_index] -= mTexCoords[morph_index]; } @@ -451,27 +452,35 @@ BOOL LLPolyMorphData::setMorphFromMesh(LLPolyMesh *morph) continue; }*/ - LLVector4 *mesh_coords = mesh->getWritableCoords(); - LLVector4 *mesh_normals = mesh->getWritableNormals(); - LLVector3 *mesh_binormals = mesh->getWritableBinormals(); - LLVector2 *mesh_tex_coords = mesh->getWritableTexCoords(); - LLVector3 *mesh_scaled_normals = mesh->getScaledNormals(); - LLVector3 *mesh_scaled_binormals = mesh->getScaledBinormals(); + LLVector4a *mesh_coords = mesh->getWritableCoords(); + LLVector4a *mesh_normals = mesh->getWritableNormals(); + LLVector4a *mesh_binormals = mesh->getWritableBinormals(); + LLVector2 *mesh_tex_coords = mesh->getWritableTexCoords(); + LLVector4a *mesh_scaled_normals = mesh->getScaledNormals(); + LLVector4a *mesh_scaled_binormals = mesh->getScaledBinormals(); for( vert_index = 0; vert_index < nverts; vert_index++) { - mesh_coords[vert_index] += delta_coords[vert_index] * weight; + delta_coords[vert_index].mul(weight); + mesh_coords[vert_index].add(delta_coords[vert_index]); + mesh_tex_coords[vert_index] += delta_tex_coords[vert_index] * weight; - mesh_scaled_normals[vert_index] += LLVector3(delta_normals[vert_index] * weight * NORMAL_SOFTEN_FACTOR); - LLVector3 normalized_normal = mesh_scaled_normals[vert_index]; - normalized_normal.normVec(); - mesh_normals[vert_index] = LLVector4(normalized_normal); + delta_normals[vert_index].mul(weight * NORMAL_SOFTEN_FACTOR); + mesh_scaled_normals[vert_index].add(delta_normals[vert_index]); + + LLVector4a normalized_normal = mesh_scaled_normals[vert_index]; + normalized_normal.normalize3(); + mesh_normals[vert_index] = normalized_normal; - mesh_scaled_binormals[vert_index] += delta_binormals[vert_index] * weight * NORMAL_SOFTEN_FACTOR; - LLVector3 tangent = mesh_scaled_binormals[vert_index] % normalized_normal; - LLVector3 normalized_binormal = normalized_normal % tangent; - normalized_binormal.normVec(); + delta_binormals[vert_index].mul(weight * NORMAL_SOFTEN_FACTOR); + mesh_scaled_binormals[vert_index].add(delta_binormals[vert_index]); + + LLVector4a tangent; + tangent.setCross3(mesh_scaled_binormals[vert_index], normalized_normal); + LLVector4a normalized_binormal; + normalized_binormal.setCross3(normalized_normal, tangent); + normalized_binormal.normalize3(); mesh_binormals[vert_index] = normalized_binormal; } @@ -658,9 +667,9 @@ BOOL LLPolyMorphTarget::parseData(LLXmlTreeNode* node) //----------------------------------------------------------------------------- // getVertexDistortion() //----------------------------------------------------------------------------- -LLVector3 LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh) +LLVector4a LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh) { - if (!mMorphData || mMesh != mesh) return LLVector3::zero; + if (!mMorphData || mMesh != mesh) return LLVector4a::getZero(); for(U32 index = 0; index < mMorphData->mNumIndices; index++) { @@ -670,17 +679,17 @@ LLVector3 LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh } } - return LLVector3::zero; + return LLVector4a::getZero(); } //----------------------------------------------------------------------------- // getFirstDistortion() //----------------------------------------------------------------------------- -const LLVector3 *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) +const LLVector4a *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { - if (!mMorphData) return &LLVector3::zero; + if (!mMorphData) return &LLVector4a::getZero(); - LLVector3* resultVec; + LLVector4a* resultVec; mMorphData->mCurrentIndex = 0; if (mMorphData->mNumIndices) { @@ -702,11 +711,11 @@ const LLVector3 *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh ** //----------------------------------------------------------------------------- // getNextDistortion() //----------------------------------------------------------------------------- -const LLVector3 *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) +const LLVector4a *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { - if (!mMorphData) return &LLVector3::zero; + if (!mMorphData) return &LLVector4a::getZero(); - LLVector3* resultVec; + LLVector4a* resultVec; mMorphData->mCurrentIndex++; if (mMorphData->mCurrentIndex < mMorphData->mNumIndices) { @@ -742,7 +751,7 @@ F32 LLPolyMorphTarget::getTotalDistortion() //----------------------------------------------------------------------------- // getAvgDistortion() //----------------------------------------------------------------------------- -const LLVector3& LLPolyMorphTarget::getAvgDistortion() +const LLVector4a& LLPolyMorphTarget::getAvgDistortion() { if (mMorphData) { @@ -750,7 +759,7 @@ const LLVector3& LLPolyMorphTarget::getAvgDistortion() } else { - return LLVector3::zero; + return LLVector4a::getZero(); } } @@ -799,15 +808,15 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) if (delta_weight != 0.f) { llassert(!mMesh->isLOD()); - LLVector4 *coords = mMesh->getWritableCoords(); + LLVector4a *coords = mMesh->getWritableCoords(); - LLVector3 *scaled_normals = mMesh->getScaledNormals(); - LLVector4 *normals = mMesh->getWritableNormals(); + LLVector4a *scaled_normals = mMesh->getScaledNormals(); + LLVector4a *normals = mMesh->getWritableNormals(); - LLVector3 *scaled_binormals = mMesh->getScaledBinormals(); - LLVector3 *binormals = mMesh->getWritableBinormals(); + LLVector4a *scaled_binormals = mMesh->getScaledBinormals(); + LLVector4a *binormals = mMesh->getWritableBinormals(); - LLVector4 *clothing_weights = mMesh->getWritableClothingWeights(); + LLVector4a *clothing_weights = mMesh->getWritableClothingWeights(); LLVector2 *tex_coords = mMesh->getWritableTexCoords(); F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL; @@ -822,31 +831,38 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) maskWeight = maskWeightArray[vert_index_morph]; } - coords[vert_index_mesh] += LLVector4(mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight); + + LLVector4a pos = mMorphData->mCoords[vert_index_morph]; + pos.mul(delta_weight*maskWeight); + coords[vert_index_mesh].add(pos); if (getInfo()->mIsClothingMorph && clothing_weights) { - LLVector3 clothing_offset = mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight; - LLVector4* clothing_weight = &clothing_weights[vert_index_mesh]; - clothing_weight->mV[VX] += clothing_offset.mV[VX]; - clothing_weight->mV[VY] += clothing_offset.mV[VY]; - clothing_weight->mV[VZ] += clothing_offset.mV[VZ]; - clothing_weight->mV[VW] = maskWeight; + LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph]; + clothing_offset.mul(delta_weight * maskWeight); + LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh]; + clothing_weight->add(clothing_offset); + clothing_weight->getF32ptr()[VW] = maskWeight; } // calculate new normals based on half angles - scaled_normals[vert_index_mesh] += mMorphData->mNormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR; - LLVector3 normalized_normal = scaled_normals[vert_index_mesh]; - normalized_normal.normVec(); - normals[vert_index_mesh] = LLVector4(normalized_normal); + LLVector4a norm = mMorphData->mNormals[vert_index_morph]; + norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR); + scaled_normals[vert_index_mesh].add(norm); + norm = scaled_normals[vert_index_mesh]; + norm.normalize3fast(); + normals[vert_index_mesh] = norm; // calculate new binormals - scaled_binormals[vert_index_mesh] += mMorphData->mBinormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR; - LLVector3 tangent = scaled_binormals[vert_index_mesh] % normalized_normal; - LLVector3 normalized_binormal = normalized_normal % tangent; - normalized_binormal.normVec(); - binormals[vert_index_mesh] = normalized_binormal; - + LLVector4a binorm = mMorphData->mBinormals[vert_index_morph]; + binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR); + scaled_binormals[vert_index_mesh].add(binorm); + LLVector4a tangent; + tangent.setCross3(scaled_binormals[vert_index_mesh], norm); + LLVector4a& normalized_binormal = binormals[vert_index_mesh]; + normalized_binormal.setCross3(norm, tangent); + normalized_binormal.normalize3fast(); + tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight; } @@ -873,7 +889,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) //----------------------------------------------------------------------------- void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert) { - LLVector4 *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL; + LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL; if (!mVertMask) { @@ -887,29 +903,47 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3 if (maskWeights) { - LLVector4 *coords = mMesh->getWritableCoords(); - LLVector3 *scaled_normals = mMesh->getScaledNormals(); - LLVector3 *scaled_binormals = mMesh->getScaledBinormals(); + LLVector4a *coords = mMesh->getWritableCoords(); + LLVector4a *scaled_normals = mMesh->getScaledNormals(); + LLVector4a *scaled_binormals = mMesh->getScaledBinormals(); LLVector2 *tex_coords = mMesh->getWritableTexCoords(); + LLVector4Logical clothing_mask; + clothing_mask.clear(); + clothing_mask.setElement<0>(); + clothing_mask.setElement<1>(); + clothing_mask.setElement<2>(); + + for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++) { F32 lastMaskWeight = mLastWeight * maskWeights[vert]; S32 out_vert = mMorphData->mVertexIndices[vert]; // remove effect of existing masked morph - coords[out_vert] -= LLVector4(mMorphData->mCoords[vert]) * lastMaskWeight; - scaled_normals[out_vert] -= mMorphData->mNormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR; - scaled_binormals[out_vert] -= mMorphData->mBinormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR; + LLVector4a t; + t = mMorphData->mCoords[vert]; + t.mul(lastMaskWeight); + coords[out_vert].sub(t); + + t = mMorphData->mNormals[vert]; + t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR); + scaled_normals[out_vert].sub(t); + + t = mMorphData->mBinormals[vert]; + t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR); + scaled_binormals[out_vert].sub(t); + tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight; if (clothing_weights) { - LLVector3 clothing_offset = mMorphData->mCoords[vert] * lastMaskWeight; - LLVector4* clothing_weight = &clothing_weights[out_vert]; - clothing_weight->mV[VX] -= clothing_offset.mV[VX]; - clothing_weight->mV[VY] -= clothing_offset.mV[VY]; - clothing_weight->mV[VZ] -= clothing_offset.mV[VZ]; + LLVector4a clothing_offset = mMorphData->mCoords[vert]; + clothing_offset.mul(lastMaskWeight); + LLVector4a* clothing_weight = &clothing_weights[out_vert]; + LLVector4a t; + t.setSub(*clothing_weight, clothing_offset); + clothing_weight->setSelectWithMask(clothing_mask, t, *clothing_weight); } } } @@ -945,7 +979,7 @@ LLPolyVertexMask::~LLPolyVertexMask() //----------------------------------------------------------------------------- // generateMask() //----------------------------------------------------------------------------- -void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4 *clothing_weights) +void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights) { // RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/) // BOOL debugImg = FALSE; @@ -989,7 +1023,7 @@ void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, if (clothing_weights) { - clothing_weights[vertIndex].mV[VW] = mWeights[index]; + clothing_weights[vertIndex].getF32ptr()[VW] = mWeights[index]; } } mWeightsGenerated = TRUE; diff --git a/indra/newview/llpolymorph.h b/indra/newview/llpolymorph.h index be7019fdf..dac698437 100644 --- a/indra/newview/llpolymorph.h +++ b/indra/newview/llpolymorph.h @@ -68,14 +68,14 @@ public: U32 mNumIndices; U32* mVertexIndices; U32 mCurrentIndex; - LLVector3* mCoords; - LLVector3* mNormals; - LLVector3* mBinormals; + LLVector4a* mCoords; + LLVector4a* mNormals; + LLVector4a* mBinormals; LLVector2* mTexCoords; F32 mTotalDistortion; // vertex distortion summed over entire morph F32 mMaxDistortion; // maximum single vertex distortion in a given morph - LLVector3 mAvgDistortion; // average vertex distortion, to infer directionality of the morph + LLVector4a mAvgDistortion; // average vertex distortion, to infer directionality of the morph LLPolyMeshSharedData* mMesh; }; @@ -88,7 +88,7 @@ public: LLPolyVertexMask(LLPolyMorphData* morph_data); ~LLPolyVertexMask(); - void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4 *clothing_weights); + void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights); F32* getMorphMaskWeights(); @@ -167,11 +167,11 @@ public: // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion(); - /*virtual*/ const LLVector3& getAvgDistortion(); + /*virtual*/ const LLVector4a& getAvgDistortion(); /*virtual*/ F32 getMaxDistortion(); - /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh); - /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh); - /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh); + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh); + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert); void addPendingMorphMask() { mNumMorphMasksPending++; } diff --git a/indra/newview/lltexlayerparams.h b/indra/newview/lltexlayerparams.h index 74c22b0cd..2c0da60b4 100644 --- a/indra/newview/lltexlayerparams.h +++ b/indra/newview/lltexlayerparams.h @@ -76,11 +76,11 @@ public: // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion() { return 1.f; } - /*virtual*/ const LLVector3& getAvgDistortion() { return mAvgDistortionVec; } + /*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; } /*virtual*/ F32 getMaxDistortion() { return 3.f; } - /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector3(1.f, 1.f, 1.f);} - /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; - /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f);} + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; // New functions BOOL render( S32 x, S32 y, S32 width, S32 height ); @@ -94,7 +94,7 @@ private: LLPointer mStaticImageRaw; BOOL mNeedsCreateTexture; BOOL mStaticImageInvalid; - LLVector3 mAvgDistortionVec; + LLVector4a mAvgDistortionVec; F32 mCachedEffectiveWeight; public: @@ -155,18 +155,18 @@ public: // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion() { return 1.f; } - /*virtual*/ const LLVector3& getAvgDistortion() { return mAvgDistortionVec; } + /*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; } /*virtual*/ F32 getMaxDistortion() { return 3.f; } - /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector3(1.f, 1.f, 1.f); } - /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; - /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f); } + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; // New functions LLColor4 getNetColor() const; protected: virtual void onGlobalColorChanged(bool upload_bake) {} private: - LLVector3 mAvgDistortionVec; + LLVector4a mAvgDistortionVec; }; class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo diff --git a/indra/newview/llviewervisualparam.h b/indra/newview/llviewervisualparam.h index 8eaa0af0a..259c0d6ee 100644 --- a/indra/newview/llviewervisualparam.h +++ b/indra/newview/llviewervisualparam.h @@ -84,11 +84,11 @@ public: // New Virtual functions virtual F32 getTotalDistortion() = 0; - virtual const LLVector3& getAvgDistortion() = 0; + virtual const LLVector4a& getAvgDistortion() = 0; virtual F32 getMaxDistortion() = 0; - virtual LLVector3 getVertexDistortion(S32 index, LLPolyMesh *mesh) = 0; - virtual const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **mesh) = 0; - virtual const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **mesh) = 0; + virtual LLVector4a getVertexDistortion(S32 index, LLPolyMesh *mesh) = 0; + virtual const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **mesh) = 0; + virtual const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **mesh) = 0; // interface methods F32 getDisplayOrder() const { return getInfo()->mEditGroupDisplayOrder; } From 4cbdb7897dc50e9d3d2bb93450785827b2cd492b Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jul 2012 03:08:47 -0500 Subject: [PATCH 07/29] MAINT-646: Knock out some extraneous performance timers. https://bitbucket.org/davep/viewer-development/changeset/71673401390a --- indra/newview/llviewerobject.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 54ed9ac8d..5732027be 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -2245,8 +2245,9 @@ BOOL LLViewerObject::isActive() const BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { - static LLFastTimer::DeclareTimer ftm("Viewer Object"); - LLFastTimer t(ftm); + //static LLFastTimer::DeclareTimer ftm("Viewer Object"); + //LLFastTimer t(ftm); + if (mDead) { // It's dead. Don't update it. From 6736e91ce0367b184ee34369e94d24323b2ce7c2 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jul 2012 03:09:16 -0500 Subject: [PATCH 08/29] MAINT-1147: Don't rebuild volume meshes on region crossing. https://bitbucket.org/davep/viewer-development/changeset/0f20bb7cb9ee --- indra/newview/llspatialpartition.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 784a0e69c..20c390931 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -805,7 +805,7 @@ void LLSpatialGroup::shift(const LLVector4a &offset) mObjectExtents[0].add(offset); mObjectExtents[1].add(offset); - //if (!mSpatialPartition->mRenderByGroup) + if (!mSpatialPartition->mRenderByGroup) { setState(GEOM_DIRTY); gPipeline.markRebuild(this, TRUE); From d8fc6916259edd9822ea36424dfb250cbfbe8160 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jul 2012 20:26:43 -0500 Subject: [PATCH 09/29] MAINT-646: Hotspot in LLViewerObjectList::update --- indra/newview/llviewerobject.cpp | 1 + indra/newview/llviewerobject.h | 5 ++ indra/newview/llviewerobjectlist.cpp | 79 ++++++++++++++++++++++------ indra/newview/llviewerobjectlist.h | 4 +- 4 files changed, 72 insertions(+), 17 deletions(-) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 5732027be..be2d1e065 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -208,6 +208,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mID(id), mLocalID(0), mTotalCRC(0), + mListIndex(-1), mTEImages(NULL), mGLName(0), mbCanSelect(TRUE), diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 403b27490..ee266ce99 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -233,6 +233,8 @@ public: const LLUUID &getID() const { return mID; } U32 getLocalID() const { return mLocalID; } U32 getCRC() const { return mTotalCRC; } + S32 getListIndex() const { return mListIndex; } + void setListIndex(S32 idx) { mListIndex = idx; } virtual BOOL isFlexible() const { return FALSE; } virtual BOOL isSculpted() const { return FALSE; } @@ -604,6 +606,9 @@ public: // Last total CRC received from sim, used for caching U32 mTotalCRC; + // index into LLViewerObjectList::mActiveObjects or -1 if not in list + S32 mListIndex; + LLPointer *mTEImages; // Selection, picking and rendering variables diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 758a8c3e9..1886e4fb8 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -932,21 +932,30 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) LLViewerObject *objectp = NULL; // Make a copy of the list in case something in idleUpdate() messes with it - std::vector idle_list; - + static std::vector idle_list; + + U32 idle_count = 0; + static LLFastTimer::DeclareTimer idle_copy("Idle Copy"); { LLFastTimer t(idle_copy); - idle_list.reserve( mActiveObjects.size() ); - - for (std::set >::iterator active_iter = mActiveObjects.begin(); + + for (std::vector >::iterator active_iter = mActiveObjects.begin(); active_iter != mActiveObjects.end(); active_iter++) { objectp = *active_iter; if (objectp) { - idle_list.push_back( objectp ); + if (idle_count >= idle_list.size()) + { + idle_list.push_back( objectp ); + } + else + { + idle_list[idle_count] = objectp; + } + ++idle_count; } else { // There shouldn't be any NULL pointers in the list, but they have caused @@ -956,11 +965,12 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) } } + std::vector::iterator idle_end = idle_list.begin()+idle_count; static const LLCachedControl freeze_time("FreezeTime",0); if (freeze_time) { for (std::vector::iterator iter = idle_list.begin(); - iter != idle_list.end(); iter++) + iter != idle_end; iter++) { objectp = *iter; if ( @@ -976,17 +986,17 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) else { for (std::vector::iterator idle_iter = idle_list.begin(); - idle_iter != idle_list.end(); idle_iter++) + idle_iter != idle_end; idle_iter++) { objectp = *idle_iter; - if (!objectp->idleUpdate(agent, world, frame_time)) + if (objectp->idleUpdate(agent, world, frame_time)) { - // If Idle Update returns false, kill object! - kill_list.push_back(objectp); + num_active_objects++; } else { - num_active_objects++; + // If Idle Update returns false, kill object! + kill_list.push_back(objectp); } } for (std::vector::iterator kill_iter = kill_list.begin(); @@ -1229,7 +1239,7 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) { //llinfos << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list in cleanupReferences." << llendl; objectp->setOnActiveList(FALSE); - mActiveObjects.erase(objectp); + removeFromActiveList(objectp); } if (objectp->isOnMap()) @@ -1296,6 +1306,7 @@ BOOL LLViewerObjectList::killObject(LLViewerObject *objectp) return TRUE; } + return FALSE; } @@ -1419,6 +1430,26 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer) mNumDeadObjects = 0; } +void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp) +{ + S32 idx = objectp->getListIndex(); + if (idx != -1) + { //remove by moving last element to this object's position + llassert(mActiveObjects[idx] == objectp); + + objectp->setListIndex(-1); + + S32 last_index = mActiveObjects.size()-1; + + if (idx != last_index) + { + mActiveObjects[idx] = mActiveObjects[last_index]; + mActiveObjects[idx]->setListIndex(idx); + mActiveObjects.pop_back(); + } + } +} + void LLViewerObjectList::updateActive(LLViewerObject *objectp) { LLMemType mt(LLMemType::MTYPE_OBJECT); @@ -1433,13 +1464,29 @@ void LLViewerObjectList::updateActive(LLViewerObject *objectp) if (active) { //llinfos << "Adding " << objectp->mID << " " << objectp->getPCodeString() << " to active list." << llendl; - mActiveObjects.insert(objectp); - objectp->setOnActiveList(TRUE); + S32 idx = objectp->getListIndex(); + if (idx <= -1) + { + mActiveObjects.push_back(objectp); + objectp->setListIndex(mActiveObjects.size()-1); + objectp->setOnActiveList(TRUE); + } + else + { + llassert(idx < (S32)mActiveObjects.size()); + llassert(mActiveObjects[idx] == objectp); + + if (idx >= (S32)mActiveObjects.size() || + mActiveObjects[idx] != objectp) + { + llwarns << "Invalid object list index detected!" << llendl; + } + } } else { //llinfos << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list." << llendl; - mActiveObjects.erase(objectp); + removeFromActiveList(objectp); objectp->setOnActiveList(FALSE); } } diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 9266dcf2d..5a48656b7 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -128,7 +128,9 @@ public: void dirtyAllObjectInventory(); + void removeFromActiveList(LLViewerObject* objectp); void updateActive(LLViewerObject *objectp); + void updateAvatarVisibility(); // Selection related stuff @@ -206,7 +208,7 @@ public: typedef std::vector > vobj_list_t; vobj_list_t mObjects; - std::set > mActiveObjects; + std::vector > mActiveObjects; vobj_list_t mMapObjects; From 77dca2ddb2278ed1a5aa74e51414204390ee680f Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jul 2012 21:04:21 -0500 Subject: [PATCH 10/29] FMODEx diagnostics. SHFMODExStreamBufferSize added. Determines stream buffer size in ms. (stream restart required) SHFMODExDecodeBufferSize added. Determines decode buffer size in ms. (stream restart required) Streams will mute themselves if they are starving, until they are free of starvation for 5 full seconds. Streams that fail to accumulate any buffer progress while starving for 10 full updates will be stopped. Stream buffer progress(buffer percent) is llinfos spewed every update. (temporary) Doubled default stream buffer size Increased default decode buffer size to 1000ms (from 400) Temporarily using FMOD::Memory_Initialize to display raw stream/decode buffer sizes via llinfos. Added llwarns messages for SigmaTel hardware or bad audio acceleration configuration. --- indra/llaudio/llaudioengine_fmodex.cpp | 28 +++++++++ indra/llaudio/llstreamingaudio.h | 3 + indra/llaudio/llstreamingaudio_fmodex.cpp | 68 ++++++++++++++++++++-- indra/llaudio/llstreamingaudio_fmodex.h | 7 +++ indra/newview/app_settings/settings_sh.xml | 22 +++++++ indra/newview/llviewerparcelmedia.cpp | 4 ++ 6 files changed, 126 insertions(+), 6 deletions(-) diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp index 2b2bd19d5..83ef4c5b4 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* __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* __stdcall decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) +{ + memset(ptr,0,size); + return ptr; +} +void __stdcall decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr) +{ + delete[] 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, NULL, &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; @@ -156,12 +182,14 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) */ result = mSystem->setDSPBufferSize(1024, 10); Check_FMOD_Error(result, "FMOD::System::setDSPBufferSize"); + llwarns << "Windows audio acceleration is disabled. This may introduce latency issues." << llendl; } result = mSystem->getDriverInfo(0, name, 256, 0); Check_FMOD_Error(result, "FMOD::System::getDriverInfo"); if (strstr(name, "SigmaTel")) { + llwarns << "SigmaTel device detected. This may introduce audio quality issues." << llendl; /* Sigmatel sound devices crackle for some reason if the format is PCM 16bit. PCM floating point output seems to solve it. 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/newview/app_settings/settings_sh.xml b/indra/newview/app_settings/settings_sh.xml index 803f7a12e..feae4cb77 100644 --- a/indra/newview/app_settings/settings_sh.xml +++ b/indra/newview/app_settings/settings_sh.xml @@ -40,6 +40,28 @@ Boolean 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()) { From 1a3c9ac5ef16954e97d80164577c43ec9d6fb671 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jul 2012 21:27:02 -0500 Subject: [PATCH 11/29] GCC being GCC-ey. Fix a couple errors and warnings --- indra/llaudio/llaudioengine_fmodex.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp index 83ef4c5b4..c745dbcd1 100644 --- a/indra/llaudio/llaudioengine_fmodex.cpp +++ b/indra/llaudio/llaudioengine_fmodex.cpp @@ -95,7 +95,7 @@ inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) return true; } -void* __stdcall decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) +void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) { if(type & FMOD_MEMORY_STREAM_DECODE) { @@ -107,14 +107,14 @@ void* __stdcall decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const cha } return new char[size]; } -void* __stdcall decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) +void* F_STDCALL decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) { memset(ptr,0,size); return ptr; } -void __stdcall decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr) +void F_STDCALL decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr) { - delete[] ptr; + delete[] (char*)ptr; } bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) @@ -130,7 +130,7 @@ 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, NULL, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE); + 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; From 6331267df64068e89bc794d80b2fd22cf586e59e Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 20 Jul 2012 08:54:25 -0500 Subject: [PATCH 12/29] MAINT-646: Optimize LLVolumeImplFlexible::doIdleUpdate() https://bitbucket.org/davep/viewer-development/changeset/b0148737d316 --- indra/newview/llflexibleobject.cpp | 134 +++++++++++++++-------------- indra/newview/llflexibleobject.h | 3 +- indra/newview/llvovolume.h | 2 +- 3 files changed, 71 insertions(+), 68 deletions(-) diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 11edb6071..a98bb3b88 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -255,50 +255,28 @@ void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, cons { } -//--------------------------------------------------------------------------------- -// This calculates the physics of the flexible object. Note that it has to be 0 -// updated every time step. In the future, perhaps there could be an -// optimization similar to what Havok does for objects that are stationary. -//--------------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_FLEXIBLE_UPDATE("Update Flexies"); -BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) + +void LLVolumeImplFlexible::updateRenderRes() { - if (mVO->mDrawable.isNull()) - { - // Don't do anything until we have a drawable - return FALSE; // (we are not initialized or updated) - } + LLDrawable* drawablep = mVO->mDrawable; - BOOL force_update = mSimulateRes == 0 ? TRUE : FALSE; - - //flexible objects never go static - mVO->mDrawable->mQuietCount = 0; - if (!mVO->mDrawable->isRoot()) - { - LLViewerObject* parent = (LLViewerObject*) mVO->getParent(); - parent->mDrawable->mQuietCount = 0; - } - - LLFastTimer ftm(FTM_FLEXIBLE_UPDATE); - S32 new_res = mAttributes->getSimulateLOD(); - //number of segments only cares about z axis - F32 app_angle = llround((F32) atan2( mVO->getScale().mV[2]*2.f, mVO->mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); +#if 1 //optimal approximation of previous behavior that doesn't rely on atan2 + F32 app_angle = mVO->getScale().mV[2]/drawablep->mDistanceWRTCamera; // Rendering sections increases with visible angle on the screen + mRenderRes = (S32) (12.f*app_angle); +#else //legacy behavior + //number of segments only cares about z axis + F32 app_angle = llround((F32) atan2( mVO->getScale().mV[2]*2.f, drawablep->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); + + // Rendering sections increases with visible angle on the screen mRenderRes = (S32)(FLEXIBLE_OBJECT_MAX_SECTIONS*4*app_angle*DEG_TO_RAD/LLViewerCamera::getInstance()->getView()); - if (mRenderRes > FLEXIBLE_OBJECT_MAX_SECTIONS) - { - mRenderRes = FLEXIBLE_OBJECT_MAX_SECTIONS; - } - - - // Bottom cap at 1/4 the original number of sections - if (mRenderRes < mAttributes->getSimulateLOD()-1) - { - mRenderRes = mAttributes->getSimulateLOD()-1; - } +#endif + + mRenderRes = llclamp(mRenderRes, new_res-1, (S32) FLEXIBLE_OBJECT_MAX_SECTIONS); + // Throttle back simulation of segments we're not rendering if (mRenderRes < new_res) { @@ -311,43 +289,65 @@ BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F6 setAttributesOfAllSections(); mInitialized = TRUE; } - if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE)) - { - return FALSE; // (we are not initialized or updated) - } +} +//--------------------------------------------------------------------------------- +// This calculates the physics of the flexible object. Note that it has to be 0 +// updated every time step. In the future, perhaps there could be an +// optimization similar to what Havok does for objects that are stationary. +//--------------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_FLEXIBLE_UPDATE("Update Flexies"); +void LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) +{ + LLDrawable* drawablep = mVO->mDrawable; - bool visible = mVO->mDrawable->isVisible(); - - if (force_update && visible) + if (drawablep) { - gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_POSITION, FALSE); - } - else if (visible && - !mVO->mDrawable->isState(LLDrawable::IN_REBUILD_Q1) && - mVO->getPixelArea() > 256.f) - { - U32 id; - F32 pixel_area = mVO->getPixelArea(); + //LLFastTimer ftm(FTM_FLEXIBLE_UPDATE); - if (mVO->isRootEdit()) + //flexible objects never go static + drawablep->mQuietCount = 0; + if (!drawablep->isRoot()) { - id = mID; - } - else - { - LLVOVolume* parent = (LLVOVolume*) mVO->getParent(); - id = parent->getVolumeInterfaceID(); + LLViewerObject* parent = (LLViewerObject*) mVO->getParent(); + parent->mDrawable->mQuietCount = 0; } - U32 update_period = (U32) (LLViewerCamera::getInstance()->getScreenPixelArea()*0.01f/(pixel_area*(sUpdateFactor+1.f)))+1; - - if ((LLDrawable::getCurrentFrame()+id)%update_period == 0) + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE)) { - gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_POSITION, FALSE); + bool visible = drawablep->isVisible(); + + if ((mSimulateRes == 0) && visible) + { + updateRenderRes(); + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_POSITION, FALSE); + } + else if (visible && + !drawablep->isState(LLDrawable::IN_REBUILD_Q1) && + mVO->getPixelArea() > 256.f) + { + U32 id; + F32 pixel_area = mVO->getPixelArea(); + + if (mVO->isRootEdit()) + { + id = mID; + } + else + { + LLVOVolume* parent = (LLVOVolume*) mVO->getParent(); + id = parent->getVolumeInterfaceID(); + } + + U32 update_period = (U32) (LLViewerCamera::getInstance()->getScreenPixelArea()*0.01f/(pixel_area*(sUpdateFactor+1.f)))+1; + + if ((LLDrawable::getCurrentFrame()+id)%update_period == 0) + { + updateRenderRes(); + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_POSITION, FALSE); + } + } } } - - return force_update; } inline S32 log2(S32 x) @@ -369,7 +369,9 @@ void LLVolumeImplFlexible::doFlexibleUpdate() if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) { //mVO->markForUpdate(TRUE); - if (!doIdleUpdate(gAgent, *LLWorld::getInstance(), 0.0)) + doIdleUpdate(gAgent, *LLWorld::getInstance(), 0.0); + + if (mSimulateRes == 0) { return; // we did not get updated or initialized, proceeding without can be dangerous } diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h index faed3801b..7d68a67da 100644 --- a/indra/newview/llflexibleobject.h +++ b/indra/newview/llflexibleobject.h @@ -84,7 +84,8 @@ class LLVolumeImplFlexible : public LLVolumeInterface LLVector3 getFramePosition() const; LLQuaternion getFrameRotation() const; LLVolumeInterfaceType getInterfaceType() const { return INTERFACE_FLEXIBLE; } - BOOL doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); + void updateRenderRes(); + void doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); BOOL doUpdateGeometry(LLDrawable *drawable); LLVector3 getPivotPosition() const; void onSetVolume(const LLVolumeParams &volume_params, const S32 detail); diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index cc7b5cf10..9fbc50208 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -70,7 +70,7 @@ class LLVolumeInterface public: virtual ~LLVolumeInterface() { } virtual LLVolumeInterfaceType getInterfaceType() const = 0; - virtual BOOL doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) = 0; + virtual void doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) = 0; virtual BOOL doUpdateGeometry(LLDrawable *drawable) = 0; virtual LLVector3 getPivotPosition() const = 0; virtual void onSetVolume(const LLVolumeParams &volume_params, const S32 detail) = 0; From c9e0a6c533525b9921109316f2b9f4e591434915 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 20 Jul 2012 08:55:02 -0500 Subject: [PATCH 13/29] MAINT-1270: Fix for some flexi prims becoming flat at some LoDs. https://bitbucket.org/davep/viewer-development/changeset/47f0d08ba7ad --- indra/newview/llflexibleobject.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index a98bb3b88..5ff314865 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -368,10 +368,11 @@ void LLVolumeImplFlexible::doFlexibleUpdate() LLPath *path = &volume->getPath(); if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) { - //mVO->markForUpdate(TRUE); + BOOL force_update = mSimulateRes == 0 ? TRUE : FALSE; + doIdleUpdate(gAgent, *LLWorld::getInstance(), 0.0); - if (mSimulateRes == 0) + if (!force_update || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE)) { return; // we did not get updated or initialized, proceeding without can be dangerous } From 531af998fbb8342774e1bfc7aa17059afc0cd49e Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 20 Jul 2012 11:29:11 -0500 Subject: [PATCH 14/29] MAINT-775: Fix for particle index pool corruption on teleport. (And removed alternative workaround) https://bitbucket.org/davep/viewer-development/changeset/04fdf7945708 --- indra/newview/llappviewer.cpp | 5 +++++ indra/newview/llface.cpp | 28 ++++++------------------ indra/newview/llface.h | 1 + indra/newview/llvopartgroup.cpp | 38 ++++++--------------------------- indra/newview/llvopartgroup.h | 1 + 5 files changed, 20 insertions(+), 53 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index c0bb21085..9d8d68c13 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -83,6 +83,7 @@ #include "llvector4a.h" #include "llfont.h" #include "llvocache.h" +#include "llvopartgroup.h" #include "llfloaterteleporthistory.h" #include "llweb.h" @@ -602,6 +603,10 @@ bool LLAppViewer::init() // initialize SSE options LLVector4a::initClass(); + + //initialize particle index pool + LLVOPartGroup::initClass(); + // Need to do this initialization before we do anything else, since anything // that touches files should really go through the lldir API gDirUtilp->initAppDirs("SecondLife"); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 38e41c6b4..59deb7c44 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -169,19 +169,10 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mGeomCount = 0; mGeomIndex = 0; mIndicesCount = 0; - if (drawablep->getRenderType() == LLPipeline::RENDER_TYPE_PARTICLES || - drawablep->getRenderType() == LLPipeline::RENDER_TYPE_HUD_PARTICLES -#if ENABLE_CLASSIC_CLOUDS - || drawablep->getRenderType() == LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS -#endif - ) - { //indicate to LLParticlePartition that this particle is uninitialized - mIndicesIndex = 0xFFFFFFFF; - } - else - { - mIndicesIndex = 0; - } + + //special value to indicate uninitialized position + mIndicesIndex = 0xFFFFFFFF; + mIndexInTex = 0; mTexture = NULL; mTEOffset = -1; @@ -214,17 +205,10 @@ void LLFace::destroy() mTexture->removeFace(this) ; } - if (mDrawablep.notNull() && - (mDrawablep->getRenderType() == LLPipeline::RENDER_TYPE_PARTICLES || - mDrawablep->getRenderType() == LLPipeline::RENDER_TYPE_HUD_PARTICLES -#if ENABLE_CLASSIC_CLOUDS - || mDrawablep->getRenderType() == LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS -#endif - ) && - mIndicesIndex != 0xFFFFFFFF) + if (isState(LLFace::PARTICLE)) { LLVOPartGroup::freeVBSlot(getGeomIndex()/4); - mIndicesIndex = 0xFFFFFFFF; + clearState(LLFace::PARTICLE); } if (mDrawPoolp) diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 5513ecd41..4cab49205 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -84,6 +84,7 @@ public: USE_FACE_COLOR = 0x0010, TEXTURE_ANIM = 0x0020, RIGGED = 0x0040, + PARTICLE = 0x0080, }; static void initClass(); diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 3dee80cce..0a5a76900 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -49,7 +49,6 @@ #include "llviewerregion.h" #include "pipeline.h" #include "llspatialpartition.h" -#include "llviewerobjectlist.h" const F32 MAX_PART_LIFETIME = 120.f; @@ -59,8 +58,7 @@ LLPointer LLVOPartGroup::sVB = NULL; S32 LLVOPartGroup::sVBSlotFree[]; S32* LLVOPartGroup::sVBSlotCursor = NULL; -//static -void LLVOPartGroup::restoreGL() +void LLVOPartGroup::initClass() { for (S32 i = 0; i < LL_MAX_PARTICLE_COUNT; ++i) { @@ -68,7 +66,11 @@ void LLVOPartGroup::restoreGL() } sVBSlotCursor = sVBSlotFree; +} +//static +void LLVOPartGroup::restoreGL() +{ sVB = new LLVertexBuffer(VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); U32 count = LL_MAX_PARTICLE_COUNT; sVB->allocateBuffer(count*4, count*6, true); @@ -120,32 +122,6 @@ void LLVOPartGroup::restoreGL() //static void LLVOPartGroup::destroyGL() { - //Just iterate over all particle faces and mark their vbo index as 'uninitialized' since sVBSlotFree & sVBSlotCursor will be clobbered. - for (int i=0; imDrawable) - { - if (obj->mDrawable->getRenderType() == LLPipeline::RENDER_TYPE_PARTICLES || - obj->mDrawable->getRenderType() == LLPipeline::RENDER_TYPE_HUD_PARTICLES -#if ENABLE_CLASSIC_CLOUDS - || obj->mDrawable->getRenderType() == LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS -#endif - ) - { - for (S32 j = 0; j < obj->mDrawable->getNumFaces(); ++j) - { - LLFace* facep = obj->mDrawable->getFace(j); - if(facep) - facep->setIndicesIndex(0xFFFFFFFF); - } - } - } - } - for (S32 i = 0; i < LL_MAX_PARTICLE_COUNT; ++i) - { - sVBSlotFree[i] = i; - } sVB = NULL; } @@ -160,7 +136,6 @@ S32 LLVOPartGroup::findAvailableVBSlot() S32 ret = *sVBSlotCursor; sVBSlotCursor++; - return ret; } @@ -654,7 +629,7 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) LLFace* facep = *i; LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject(); - if (facep->getIndicesStart() == 0xFFFFFFFF) + if (!facep->isState(LLFace::PARTICLE)) { //set the indices of this face S32 idx = LLVOPartGroup::findAvailableVBSlot(); if (idx >= 0) @@ -663,6 +638,7 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) facep->setIndicesIndex(idx*6); facep->setVertexBuffer(LLVOPartGroup::sVB); facep->setPoolType(LLDrawPool::POOL_ALPHA); + facep->setState(LLFace::PARTICLE); } else { diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h index 4c2e073d7..4948ddf55 100644 --- a/indra/newview/llvopartgroup.h +++ b/indra/newview/llvopartgroup.h @@ -51,6 +51,7 @@ public: static S32 sVBSlotFree[LL_MAX_PARTICLE_COUNT]; static S32* sVBSlotCursor; + static void initClass(); static void restoreGL(); static void destroyGL(); static S32 findAvailableVBSlot(); From 7b23aece00e1ee4853f7110700ba46c554776bdd Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 20 Jul 2012 11:37:01 -0500 Subject: [PATCH 15/29] Missed a couple LLCullResult::drawable_list_t -> LLCullResult::drawable_iterator replacements, albeit in #if'd out code blocks. --- indra/newview/pipeline.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 9235a7b2a..83ef73155 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1833,7 +1833,7 @@ void LLPipeline::checkReferences(LLFace* face) check_references(group, face); } - for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) + for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) { LLDrawable* drawable = *iter; check_references(drawable, face); @@ -1865,7 +1865,7 @@ void LLPipeline::checkReferences(LLDrawable* drawable) check_references(group, drawable); } - for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) + for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) { if (drawable == *iter) { From b8b235df09a77a37e2ccfd78f7b06423d208621a Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 20 Jul 2012 12:03:41 -0500 Subject: [PATCH 16/29] And suddeny the texture index attrib(for batching) is now an integer! (Changing switch to an if block on nividia hardware seems like the real solution to pink textures... not the index datatype) --- indra/llrender/llshadermgr.cpp | 10 +++++----- indra/llrender/llvertexbuffer.cpp | 6 +++--- .../shaders/class1/objects/indexedTextureV.glsl | 4 ++-- indra/newview/llface.cpp | 14 ++++++-------- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 0c17fbfb5..a37604ae5 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -680,7 +680,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade vec4 diffuseLookup(vec2 texcoord) { - switch (vary_texture_index.r)) + switch (vary_texture_index)) { case 0: ret = texture2D(tex0, texcoord); break; case 1: ret = texture2D(tex1, texcoord); break; @@ -704,7 +704,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (texture_index_channels > 1) { - text[count++] = strdup("VARYING_FLAT ivec4 vary_texture_index;\n"); + text[count++] = strdup("VARYING_FLAT int vary_texture_index;\n"); } text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n"); @@ -722,7 +722,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade { //switches are unreliable on some NVIDIA drivers for (S32 i = 0; i < texture_index_channels; ++i) { - std::string if_string = llformat("\t%sif (vary_texture_index.r == %d) { return texture2D(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i); + std::string if_string = llformat("\t%sif (vary_texture_index == %d) { return texture2D(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i); text[count++] = strdup(if_string.c_str()); } text[count++] = strdup("\treturn vec4(1,0,1,1);\n"); @@ -731,13 +731,13 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade else { text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n"); - text[count++] = strdup("\tswitch (vary_texture_index.r)\n"); + text[count++] = strdup("\tswitch (vary_texture_index)\n"); text[count++] = strdup("\t{\n"); //switch body for (S32 i = 0; i < texture_index_channels; ++i) { - std::string case_str = llformat("\t\tcase %d: ret = texture2D(tex%d, texcoord); break;\n", i, i); + std::string case_str = llformat("\t\tcase %d: return texture2D(tex%d, texcoord);\n", i, i); text[count++] = strdup(case_str.c_str()); } diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index bc4c201d9..896560d4d 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1249,7 +1249,7 @@ void LLVertexBuffer::setupVertexArray() 1, //TYPE_WEIGHT, 4, //TYPE_WEIGHT4, 4, //TYPE_CLOTHWEIGHT, - 4, //TYPE_TEXTURE_INDEX + 1, //TYPE_TEXTURE_INDEX }; U32 attrib_type[] = @@ -1266,7 +1266,7 @@ void LLVertexBuffer::setupVertexArray() GL_FLOAT, //TYPE_WEIGHT, GL_FLOAT, //TYPE_WEIGHT4, GL_FLOAT, //TYPE_CLOTHWEIGHT, - GL_UNSIGNED_BYTE, //TYPE_TEXTURE_INDEX + GL_UNSIGNED_INT, //TYPE_TEXTURE_INDEX }; bool attrib_integer[] = @@ -2313,7 +2313,7 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) #if !LL_DARWIN S32 loc = TYPE_TEXTURE_INDEX; void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12); - glVertexAttribIPointer(loc, 4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); + glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); #endif } if (data_mask & MAP_VERTEX) diff --git a/indra/newview/app_settings/shaders/class1/objects/indexedTextureV.glsl b/indra/newview/app_settings/shaders/class1/objects/indexedTextureV.glsl index 7c0699d72..ca29bf314 100644 --- a/indra/newview/app_settings/shaders/class1/objects/indexedTextureV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/indexedTextureV.glsl @@ -23,9 +23,9 @@ * $/LicenseInfo$ */ -ATTRIBUTE ivec4 texture_index; +ATTRIBUTE int texture_index; -VARYING_FLAT ivec4 vary_texture_index; +VARYING_FLAT int vary_texture_index; void passTextureIndex() { diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 59deb7c44..fc7a2ae49 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1622,7 +1622,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (!do_xform) { LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM); - LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, tc_size); } else { @@ -1843,15 +1844,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector4a texIdx; - U8 index = mTextureIndex < 255 ? mTextureIndex : 0; + S32 index = mTextureIndex < 255 ? mTextureIndex : 0; F32 val = 0.f; - U8* vp = (U8*) &val; - vp[0] = index; - vp[1] = 0; - vp[2] = 0; - vp[3] = 0; - + S32* vp = (S32*) &val; + *vp = index; + llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); LLVector4Logical mask; From 73bc656e63dace4a1e891a4546c40c94349a0906 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 20 Jul 2012 12:04:24 -0500 Subject: [PATCH 17/29] Flexis were not being reliably initialized before being drawn. --- indra/newview/llflexibleobject.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 5ff314865..8b0fd109f 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -346,7 +346,9 @@ void LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F6 gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_POSITION, FALSE); } } - } + } + if(!mInitialized) + updateRenderRes(); } } From 3710ea903e553d272ff94c1d4aa784c52e4f2f14 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 21 Jul 2012 03:27:43 -0500 Subject: [PATCH 18/29] Enable texture auditing categories, also fixed potential buffer underread related to auditing. --- indra/llrender/llimagegl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 6d7054e7e..42139dfec 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -2001,7 +2001,6 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) void LLImageGL::setCategory(S32 category) { -#if 0 //turn this off temporarily because it is not in use now. if(!gAuditTexture) { return ; @@ -2022,7 +2021,6 @@ void LLImageGL::setCategory(S32 category) mCategory = -1 ; } } -#endif } //for debug use @@ -2053,14 +2051,16 @@ S32 LLImageGL::getTextureCounterIndex(U32 val) void LLImageGL::incTextureCounter(U32 val, S32 ncomponents, S32 category) { sTextureLoadedCounter[getTextureCounterIndex(val)]++ ; - sTextureMemByCategory[category] += (S32)val * ncomponents ; + if(category > -1) + sTextureMemByCategory[category] += (S32)val * ncomponents ; } //static void LLImageGL::decTextureCounter(U32 val, S32 ncomponents, S32 category) { sTextureLoadedCounter[getTextureCounterIndex(val)]-- ; - sTextureMemByCategory[category] += (S32)val * ncomponents ; + if(category > -1) + sTextureMemByCategory[category] -= (S32)val * ncomponents ; } void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size) From a1e714dce7fe3b6e79f5c729a78a44e62c29c206 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 21 Jul 2012 03:43:30 -0500 Subject: [PATCH 19/29] mDeferredVB only needs allocated when rendering in deferred mode. mCubeVB only needs allocated when occlusion is working. Let them be lazy-allocated on an as-needed basis. --- indra/newview/pipeline.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 83ef73155..a3f4374a4 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -453,15 +453,6 @@ void LLPipeline::init() mSpotLightFade[i] = 1.f; } - if (mCubeVB.isNull()) - { - mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); - } - if(mDeferredVB.isNull()) - { - mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0); - mDeferredVB->allocateBuffer(8, 0, true); - } setLightingDetail(-1); gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); From 32f407340fc8c07097f4ea856c044ff0ab267c76 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 21 Jul 2012 21:16:41 -0500 Subject: [PATCH 20/29] Call LLImageGL::initClass to avoid crash when calling LLFeatureManager::applyRecommendedSettings. (texauditing vectors must be allocated) --- indra/newview/llviewerwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 833d6412d..acd55d913 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1562,6 +1562,7 @@ LLViewerWindow::LLViewerWindow( LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable")); LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ; gGL.init() ; + LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ; if (LLFeatureManager::getInstance()->isSafe() || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion()) @@ -1586,7 +1587,6 @@ LLViewerWindow::LLViewerWindow( // Init the image list. Must happen after GL is initialized and before the images that // LLViewerWindow needs are requested. - LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ; gTextureList.init(); LLViewerTextureManager::init() ; gBumpImageList.init(); From 21f61748460223dc942bfdc1076b621e5ed5692c Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 24 Jul 2012 11:27:23 -0500 Subject: [PATCH 21/29] Use glFramebufferTexture2D to detach textures from FBOs before said textures are 'deleted'(set to NULL via zeroing dimensions). May avoid odd LLImageGL::deleteTextures crash on some apple systems. --- indra/llrender/llrendertarget.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 589c0dc0d..93aaf0510 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -308,6 +308,8 @@ void LLRenderTarget::release() } else { + //Release before delete. + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0); LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true); stop_glerror(); } @@ -339,6 +341,9 @@ void LLRenderTarget::release() if (mTex.size() > 0) { + //Release before delete. + for (U32 i = 0; i < mTex.size(); ++i) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, LLTexUnit::getInternalType(mUsage), 0, 0); sBytesAllocated -= mResX*mResY*4*mTex.size(); LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true); mTex.clear(); @@ -490,10 +495,21 @@ void LLRenderTarget::flush(bool fetch_depth) } stop_glerror(); + //Following case never currently evalutes true, but it's still good to have. if (mTex.size() > 1) - { + { for (U32 i = 1; i < mTex.size(); ++i) { + glDrawBuffer(GL_COLOR_ATTACHMENT0 + i); + glReadBuffer(GL_COLOR_ATTACHMENT0 + i); + stop_glerror(); + glBlitFramebuffer(0, 0, mResX, mResY, 0, 0, mResX, mResY, GL_COLOR_BUFFER_BIT, GL_NEAREST); + stop_glerror(); + } + + /*for (U32 i = 1; i < mTex.size(); ++i) + { + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, LLTexUnit::getInternalType(mUsage), mTex[i], 0); stop_glerror(); @@ -510,7 +526,7 @@ void LLRenderTarget::flush(bool fetch_depth) stop_glerror(); glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_RENDERBUFFER, mSampleBuffer->mTex[i]); stop_glerror(); - } + }*/ } glBindFramebuffer(GL_FRAMEBUFFER, 0); } From eeea2b4de481c2ff5669f8c7b24cb945f1f6ddd9 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 24 Jul 2012 20:18:35 -0500 Subject: [PATCH 22/29] Don't batch faces that are animating, ever (hopefully). Should fix texture animations breaking when rendermaxtextureindex > 1 --- indra/newview/llvovolume.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index ba9b6c994..6773e9fd3 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4165,11 +4165,16 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: facep->setTextureIndex(cur_tex); texture_list.push_back(tex); - //if (can_batch_texture(facep)) + if (can_batch_texture(facep)) { while (i != faces.end()) { facep = *i; + if (!can_batch_texture(facep)) + { //face is bump mapped or has an animated texture matrix -- can't + //batch more than 1 texture at a time + break; + } if (facep->getTexture() != tex) { if (distance_sort) @@ -4195,12 +4200,6 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: cur_tex++; } - if (!can_batch_texture(facep)) - { //face is bump mapped or has an animated texture matrix -- can't - //batch more than 1 texture at a time - break; - } - if (cur_tex >= texture_index_channels) { //cut batches when index channels are depleted break; @@ -4222,9 +4221,8 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: facep->setTextureIndex(cur_tex); } + tex = texture_list[0]; } - - tex = texture_list[0]; } else { From 726d8248c5da697dd3ae3ba01bfa24c593c8b61c Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 26 Jul 2012 00:17:38 -0500 Subject: [PATCH 23/29] Trying alpha-face rebuild using LL's method. --- indra/newview/lldrawable.cpp | 14 +------------- indra/newview/llface.cpp | 15 ++++++++++++++- indra/newview/llvovolume.h | 1 + 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 89e26ccb1..97b9764ab 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -791,19 +791,7 @@ void LLDrawable::updateTexture() if (getVOVolume()) { - /*if (isActive()) - { - if (isRoot()) - { - mQuietCount = 0; - } - else - { - getParent()->mQuietCount = 0; - } - }*/ - - getVOVolume()->mFaceMappingChanged = TRUE; + //getVOVolume()->mFaceMappingChanged = TRUE; gPipeline.markRebuild(this, LLDrawable::REBUILD_MATERIAL, TRUE); } } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index fc7a2ae49..ba818ed90 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -319,7 +319,20 @@ void LLFace::setTexture(LLViewerTexture* tex) void LLFace::dirtyTexture() { - gPipeline.markTextured(getDrawable()); + LLDrawable* drawablep = getDrawable(); + + if (mVObjp.notNull() && mVObjp->getVolume() && + mTexture.notNull() && mTexture->getComponents() == 4) + { //dirty texture on an alpha object should be treated as an LoD update + LLVOVolume* vobj = drawablep->getVOVolume(); + if (vobj) + { + vobj->mLODChanged = TRUE; + } + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE); + } + + gPipeline.markTextured(drawablep); } void LLFace::switchTexture(LLViewerTexture* new_texture) diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 9fbc50208..dbf9800db 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -297,6 +297,7 @@ public: U8 mTexAnimMode; private: friend class LLDrawable; + friend class LLFace; BOOL mFaceMappingChanged; LLFrameTimer mTextureUpdateTimer; From 701230b49cffa1ca3144c4f98647731094308252 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 26 Jul 2012 03:05:22 -0500 Subject: [PATCH 24/29] Added LLRenderTarget::resize and did a little cleanup. --- indra/llrender/llrendertarget.cpp | 100 ++++++++++++++++++--- indra/llrender/llrendertarget.h | 8 ++ indra/newview/pipeline.cpp | 139 +++++++++++++++--------------- 3 files changed, 166 insertions(+), 81 deletions(-) diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 93aaf0510..27fec6843 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -76,6 +76,42 @@ LLRenderTarget::~LLRenderTarget() release(); } +void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt) +{ + //for accounting, get the number of pixels added/subtracted + S32 pix_diff = (resx*resy)-(mResX*mResY); + + mResX = resx; + mResY = resy; + + for (U32 i = 0; i < mTex.size(); ++i) + { //resize color attachments + gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]); + LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false); + sBytesAllocated += pix_diff*4; + } + + if (mDepth) + { //resize depth attachment + if (mStencil) + { + //use render buffers where stencil buffers are in play + glBindRenderbuffer(GL_RENDERBUFFER, mDepth); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + else + { + gGL.getTexUnit(0)->bindManual(mUsage, mDepth); + U32 internal_type = LLTexUnit::getInternalType(mUsage); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + } + + sBytesAllocated += pix_diff*4; + } + if(mSampleBuffer) + mSampleBuffer->resize(resx,resy); +} void LLRenderTarget::setSampleBuffer(LLMultisampleBuffer* buffer) { @@ -241,14 +277,14 @@ bool LLRenderTarget::allocateDepth() gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } - sBytesAllocated += mResX*mResY*4; - if (glGetError() != GL_NO_ERROR) { llwarns << "Unable to allocate depth buffer for render target." << llendl; return false; } + sBytesAllocated += mResX*mResY*4; + return true; } @@ -309,7 +345,11 @@ void LLRenderTarget::release() else { //Release before delete. - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0); + if(mFBO) + { + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0); + } LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true); stop_glerror(); } @@ -341,9 +381,6 @@ void LLRenderTarget::release() if (mTex.size() > 0) { - //Release before delete. - for (U32 i = 0; i < mTex.size(); ++i) - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, LLTexUnit::getInternalType(mUsage), 0, 0); sBytesAllocated -= mResX*mResY*4*mTex.size(); LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true); mTex.clear(); @@ -472,7 +509,7 @@ void LLRenderTarget::flush(bool fetch_depth) stop_glerror(); glBindFramebuffer(GL_FRAMEBUFFER, 0); stop_glerror(); - + if (mSampleBuffer) { LLGLEnable multisample(GL_MULTISAMPLE); @@ -482,7 +519,7 @@ void LLRenderTarget::flush(bool fetch_depth) check_framebuffer_status(); glBindFramebuffer(GL_READ_FRAMEBUFFER, mSampleBuffer->mFBO); check_framebuffer_status(); - + stop_glerror(); if(gGLManager.mIsATI) { @@ -532,7 +569,6 @@ void LLRenderTarget::flush(bool fetch_depth) } } } - void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter) { @@ -642,7 +678,8 @@ void LLRenderTarget::getViewport(S32* viewport) // LLMultisampleBuffer implementation //================================================== LLMultisampleBuffer::LLMultisampleBuffer() : - mSamples(0) + mSamples(0), + mColorFormat(0) { } @@ -743,6 +780,7 @@ bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth mUsage = usage; mUseDepth = depth; mStencil = stencil; + mColorFormat = color_fmt; { @@ -780,6 +818,42 @@ bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth return addColorAttachment(color_fmt); } +void LLMultisampleBuffer::resize(U32 resx, U32 resy) +{ + //for accounting, get the number of pixels added/subtracted + S32 pix_diff = (resx*resy)-(mResX*mResY); + + mResX = resx; + mResY = resy; + + for (U32 i = 0; i < mTex.size(); ++i) + { //resize color attachments + glBindRenderbuffer(GL_RENDERBUFFER, mTex[i]); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, mColorFormat, mResX, mResY); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + sBytesAllocated += pix_diff*4; + } + + if (mDepth) + { //resize depth attachment + if (mStencil) + { + //use render buffers where stencil buffers are in play + glBindRenderbuffer(GL_RENDERBUFFER, mDepth); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + else + { + glBindRenderbuffer(GL_RENDERBUFFER, mDepth); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT24, mResX, mResY); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + } + sBytesAllocated += pix_diff*4; + } +} + bool LLMultisampleBuffer::addColorAttachment(U32 color_fmt) { if (color_fmt == 0) @@ -829,12 +903,13 @@ bool LLMultisampleBuffer::allocateDepth() clear_glerror(); if (mStencil) { - glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY); } else { - glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT24, mResX, mResY); } + if (glGetError() != GL_NO_ERROR) { llwarns << "Unable to allocate depth buffer for multisample render target." << llendl; @@ -845,4 +920,3 @@ bool LLMultisampleBuffer::allocateDepth() return true; } - diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 9ed95770e..8268f1984 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -80,6 +80,12 @@ public: //multiple calls will release previously allocated resources bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = FALSE); + //resize existing attachments to use new resolution and color format + // CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined + // DO NOT use for screen space buffers or for scratch space for an image that might be uploaded + // DO use for render targets that resize often and aren't likely to ruin someone's day if they break + void resize(U32 resx, U32 resy, U32 color_fmt); + //provide this render target with a multisample resource. void setSampleBuffer(LLMultisampleBuffer* buffer); @@ -168,6 +174,7 @@ protected: class LLMultisampleBuffer : public LLRenderTarget { U32 mSamples; + U32 mColorFormat; public: LLMultisampleBuffer(); virtual ~LLMultisampleBuffer(); @@ -180,6 +187,7 @@ public: bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, U32 samples); virtual bool addColorAttachment(U32 color_fmt); virtual bool allocateDepth(); + void resize(U32 resx, U32 resy); }; #endif //!LL_MESA_HEADLESS diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index a3f4374a4..9f4c7b1f7 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -693,9 +693,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) //allocate deferred rendering color buffers - static const LLCachedControl shadow_precision("DeferredHighPrecision",true); - const GLuint format = shadow_precision ? GL_RGBA : GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later - if (!mDeferredScreen.allocate(resX, resY, format, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + if (!mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; if (!addDeferredAttachments(mDeferredScreen)) return false; @@ -9409,81 +9407,86 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) stateSort(*LLViewerCamera::getInstance(), result); - const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); - LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); - LLCamera camera = *viewer_camera; - - camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis()); - LLVector2 tdim; + U32 resY = 0; + U32 resX = 0; - - LLVector4a half_height; - half_height.setSub(ext[1], ext[0]); - half_height.mul(0.5f); - - LLVector4a left; - left.load3(camera.getLeftAxis().mV); - left.mul(left); - left.normalize3fast(); - - LLVector4a up; - up.load3(camera.getUpAxis().mV); - up.mul(up); - up.normalize3fast(); - - tdim.mV[0] = fabsf(half_height.dot3(left).getF32()); - tdim.mV[1] = fabsf(half_height.dot3(up).getF32()); - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - - F32 distance = (pos-camera.getOrigin()).length(); - F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; - F32 aspect = tdim.mV[0]/tdim.mV[1]; - glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); - glh_set_current_projection(persp); - gGL.loadMatrix(persp.m); - - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - glh::matrix4f mat; - camera.getOpenGLTransform(mat.m); - - mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; - - gGL.loadMatrix(mat.m); - glh_set_current_modelview(mat); - - glClearColor(0.0f,0.0f,0.0f,0.0f); - gGL.setColorMask(true, true); - - // get the number of pixels per angle - F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); - - //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing) - U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); - U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); - - if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() || - resY != avatar->mImpostor.getHeight()) { - static const LLCachedControl shadow_precision("DeferredHighPrecision",true); //TO-DO: Profile 16bit format later - avatar->mImpostor.allocate(resX,resY, (!LLPipeline::sRenderDeferred || shadow_precision) ? GL_RGBA : GL_RGBA16F_ARB,TRUE,FALSE); + const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); + LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); - if (LLPipeline::sRenderDeferred) + camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis()); + + LLVector4a half_height; + half_height.setSub(ext[1], ext[0]); + half_height.mul(0.5f); + + LLVector4a left; + left.load3(camera.getLeftAxis().mV); + left.mul(left); + left.normalize3fast(); + + LLVector4a up; + up.load3(camera.getUpAxis().mV); + up.mul(up); + up.normalize3fast(); + + tdim.mV[0] = fabsf(half_height.dot3(left).getF32()); + tdim.mV[1] = fabsf(half_height.dot3(up).getF32()); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + + F32 distance = (pos-camera.getOrigin()).length(); + F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; + F32 aspect = tdim.mV[0]/tdim.mV[1]; + glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); + glh_set_current_projection(persp); + gGL.loadMatrix(persp.m); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + glh::matrix4f mat; + camera.getOpenGLTransform(mat.m); + + mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; + + gGL.loadMatrix(mat.m); + glh_set_current_modelview(mat); + + glClearColor(0.0f,0.0f,0.0f,0.0f); + gGL.setColorMask(true, true); + + // get the number of pixels per angle + F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); + + //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing) + resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); + resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); + + if (!avatar->mImpostor.isComplete()) { - addDeferredAttachments(avatar->mImpostor); + avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); + + if (LLPipeline::sRenderDeferred) + { + addDeferredAttachments(avatar->mImpostor); + } + + gGL.getTexUnit(0)->bind(&avatar->mImpostor); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + else if(resX != avatar->mImpostor.getWidth() || + resY != avatar->mImpostor.getHeight()) + { + avatar->mImpostor.resize(resX,resY,GL_RGBA); } - gGL.getTexUnit(0)->bind(&avatar->mImpostor); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + avatar->mImpostor.bindTarget(); } - avatar->mImpostor.bindTarget(); - if (LLPipeline::sRenderDeferred) { avatar->mImpostor.clear(); From 1d1947c51a5599566318ba55cd09db71f388de73 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sun, 29 Jul 2012 04:28:11 -0500 Subject: [PATCH 25/29] Reworked LLPostProcess and implemented FBO support (much faster if multiple post shaders are enabled, or need a lot of passes). Tweaked LLRenderTarget to support depth textures if FBO support is lacking. Prefer LLRenderTarget::getFBO() over LLRenderTarget::sUseFBO when determining how to handle a specific LLRenderTarget object. (Decoupling to simplify logic without having to track a global) --- indra/llrender/llpostprocess.cpp | 696 +++++++++++------- indra/llrender/llpostprocess.h | 274 +++---- indra/llrender/llrender.cpp | 2 +- indra/llrender/llrendertarget.cpp | 37 +- indra/llrender/llrendertarget.h | 2 + .../shaders/class1/effects/PosterizeF.glsl | 23 + .../windlight/postprocesseffects.xml | 6 +- indra/newview/llfloaterdaycycle.cpp | 1 - indra/newview/llfloaterpostprocess.cpp | 26 +- indra/newview/llfloaterwater.cpp | 1 - indra/newview/llfloaterwindlight.cpp | 1 - indra/newview/llstartup.cpp | 1 - indra/newview/llviewerdisplay.cpp | 14 +- indra/newview/llviewershadermgr.cpp | 18 + indra/newview/llviewerwindow.cpp | 2 +- indra/newview/pipeline.cpp | 10 +- .../xui/en-us/floater_post_process.xml | 19 + 17 files changed, 660 insertions(+), 473 deletions(-) create mode 100644 indra/newview/app_settings/shaders/class1/effects/PosterizeF.glsl diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index 25e775c1e..e09d0f349 100644 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -33,34 +33,247 @@ #include "linden_common.h" #include "llpostprocess.h" -#include "llglslshader.h" -#include "llsdserialize.h" -#include "llrender.h" -#include "llvertexbuffer.h" #include "lldir.h" +#include "llgl.h" +#include "llglslshader.h" +#include "llrender.h" +#include "llsdserialize.h" +#include "llsdutil.h" +#include "llsdutil_math.h" +#include "llvertexbuffer.h" +#include "llfasttimer.h" + extern LLGLSLShader gPostColorFilterProgram; extern LLGLSLShader gPostNightVisionProgram; extern LLGLSLShader gPostGaussianBlurProgram; +extern LLGLSLShader gPostPosterizeProgram; static const unsigned int NOISE_SIZE = 512; -/// CALCULATING LUMINANCE (Using NTSC lum weights) -/// http://en.wikipedia.org/wiki/Luma_%28video%29 -static const float LUMINANCE_R = 0.299f; -static const float LUMINANCE_G = 0.587f; -static const float LUMINANCE_B = 0.114f; - static const char * const XML_FILENAME = "postprocesseffects.xml"; -LLPostProcess::LLPostProcess(void) : - mVBO(NULL), - mAllEffects(LLSD::emptyMap()), - mScreenWidth(1), mScreenHeight(1) +template<> LLSD LLPostProcessShader::LLShaderSetting::getDefaultValue() { - mSceneRenderTexture = NULL ; - mNoiseTexture = NULL ; - + return mDefault.getValue(); +} +template<> void LLPostProcessShader::LLShaderSetting::setValue(const LLSD& value) +{ + mValue = ll_vector4_from_sd(value); +} + +LLSD LLPostProcessShader::getDefaults() +{ + LLSD defaults; + for(std::vector::iterator it=mSettings.begin();it!=mSettings.end();++it) + { + defaults[(*it)->mSettingName]=(*it)->getDefaultValue(); + } + return defaults; +} +void LLPostProcessShader::loadSettings(const LLSD& settings) +{ + for(std::vector::iterator it=mSettings.begin();it!=mSettings.end();++it) + { + LLSD value = settings[(*it)->mSettingName]; + (*it)->setValue(value); + } +} + +class LLColorFilterShader : public LLPostProcessShader +{ +private: + LLShaderSetting mEnabled; + LLShaderSetting mGamma, mBrightness, mContrast, mSaturation; + LLShaderSetting mContrastBase; +public: + LLColorFilterShader() : + mEnabled("enable_color_filter",false), + mGamma("gamma",1.f), + mBrightness("brightness",1.f), + mContrast("contrast",1.f), + mSaturation("saturation",1.f), + mContrastBase("contrast_base",LLVector4(1.f,1.f,1.f,0.5f)) + { + mSettings.push_back(&mEnabled); + mSettings.push_back(&mGamma); + mSettings.push_back(&mBrightness); + mSettings.push_back(&mContrast); + mSettings.push_back(&mSaturation); + mSettings.push_back(&mContrastBase); + } + + bool isEnabled() { return mEnabled && gPostColorFilterProgram.mProgramObject; } + S32 getColorChannel() { return 0; } + S32 getDepthChannel() { return -1; } + + QuadType bind() + { + if(!isEnabled()) + return QUAD_NONE; + + /// CALCULATING LUMINANCE (Using NTSC lum weights) + /// http://en.wikipedia.org/wiki/Luma_%28video%29 + static const float LUMINANCE_R = 0.299f; + static const float LUMINANCE_G = 0.587f; + static const float LUMINANCE_B = 0.114f; + + gPostColorFilterProgram.bind(); + + gPostColorFilterProgram.uniform1f("gamma", mGamma); + gPostColorFilterProgram.uniform1f("brightness", mBrightness); + gPostColorFilterProgram.uniform1f("contrast", mContrast); + float baseI = (mContrastBase.mValue[VX] + mContrastBase.mValue[VY] + mContrastBase.mValue[VZ]) / 3.0f; + baseI = mContrastBase.mValue[VW] / ((baseI < 0.001f) ? 0.001f : baseI); + float baseR = mContrastBase.mValue[VX] * baseI; + float baseG = mContrastBase.mValue[VY] * baseI; + float baseB = mContrastBase.mValue[VZ] * baseI; + gPostColorFilterProgram.uniform3fv("contrastBase", 1, LLVector3(baseR, baseG, baseB).mV); + gPostColorFilterProgram.uniform1f("saturation", mSaturation); + gPostColorFilterProgram.uniform3fv("lumWeights", 1, LLVector3(LUMINANCE_R, LUMINANCE_G, LUMINANCE_B).mV); + return QUAD_NORMAL; + } + bool draw(U32 pass) {return pass == 1;} + void unbind() + { + gPostColorFilterProgram.unbind(); + } +}; + +class LLNightVisionShader : public LLPostProcessShader +{ +private: + LLShaderSetting mEnabled; + LLShaderSetting mBrightnessMult, mNoiseStrength; +public: + LLNightVisionShader() : + mEnabled("enable_night_vision",false), + mBrightnessMult("brightness_multiplier",3.f), + mNoiseStrength("noise_strength",.4f) + { + mSettings.push_back(&mEnabled); + mSettings.push_back(&mBrightnessMult); + mSettings.push_back(&mNoiseStrength); + } + bool isEnabled() { return mEnabled && gPostNightVisionProgram.mProgramObject; } + S32 getColorChannel() { return 0; } + S32 getDepthChannel() { return -1; } + QuadType bind() + { + if(!isEnabled()) + return QUAD_NONE; + + gPostNightVisionProgram.bind(); + + LLPostProcess::getInstance()->bindNoise(1); + + gPostNightVisionProgram.uniform1f("brightMult", mBrightnessMult); + gPostNightVisionProgram.uniform1f("noiseStrength", mNoiseStrength); + + return QUAD_NOISE; + + } + bool draw(U32 pass) {return pass == 1;} + void unbind() + { + gPostNightVisionProgram.unbind(); + } +}; + +class LLGaussBlurShader : public LLPostProcessShader +{ +private: + LLShaderSetting mEnabled; + LLShaderSetting mNumPasses; + GLint mPassLoc; +public: + LLGaussBlurShader() : + mEnabled("enable_gauss_blur",false), + mNumPasses("gauss_blur_passes",2), + mPassLoc(0) + { + mSettings.push_back(&mEnabled); + mSettings.push_back(&mNumPasses); + } + bool isEnabled() { return mEnabled && mNumPasses && gPostGaussianBlurProgram.mProgramObject; } + S32 getColorChannel() { return 0; } + S32 getDepthChannel() { return -1; } + QuadType bind() + { + if(!isEnabled()) + return QUAD_NONE; + + gPostGaussianBlurProgram.bind(); + + mPassLoc = gPostGaussianBlurProgram.getUniformLocation("horizontalPass"); + + return QUAD_NORMAL; + } + bool draw(U32 pass) + { + if((S32)pass > mNumPasses*2) + return false; + glUniform1iARB(mPassLoc, (pass-1) % 2); + return true; + } + void unbind() + { + gPostGaussianBlurProgram.unbind(); + } +}; + +class LLPosterizeShader : public LLPostProcessShader +{ +private: + LLShaderSetting mEnabled; + LLShaderSetting mNumLayers; +public: + LLPosterizeShader() : + mEnabled("enable_posterize",false), + mNumLayers("posterize_layers",2) + { + mSettings.push_back(&mEnabled); + mSettings.push_back(&mNumLayers); + } + bool isEnabled() { return mEnabled && gPostPosterizeProgram.mProgramObject; } + S32 getColorChannel() { return 0; } + S32 getDepthChannel() { return -1; } + QuadType bind() + { + if(!isEnabled()) + return QUAD_NONE; + + gPostPosterizeProgram.bind(); + + gPostPosterizeProgram.uniform1i("layerCount", mNumLayers); + + return QUAD_NORMAL; + } + bool draw(U32 pass) + { + return pass == 1; + } + void unbind() + { + gPostPosterizeProgram.unbind(); + } +}; + +LLPostProcess::LLPostProcess(void) : + mVBO(NULL), + mDepthTexture(0), + mNoiseTexture(NULL), + mScreenWidth(0), + mScreenHeight(0), + mNoiseTextureScale(0.f), + mSelectedEffectInfo(LLSD::emptyMap()), + mAllEffectInfo(LLSD::emptyMap()) +{ + mShaders.push_back(new LLColorFilterShader()); + mShaders.push_back(new LLNightVisionShader()); + mShaders.push_back(new LLGaussBlurShader()); + mShaders.push_back(new LLPosterizeShader()); + /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.*/ std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); LL_DEBUGS2("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL; @@ -71,99 +284,43 @@ LLPostProcess::LLPostProcess(void) : { LLPointer parser = new LLSDXMLParser(); - parser->parse(effectsXML, mAllEffects, LLSDSerialize::SIZE_UNLIMITED); + parser->parse(effectsXML, mAllEffectInfo, LLSDSerialize::SIZE_UNLIMITED); } - if (!mAllEffects.has("default")) + if (!mAllEffectInfo.has("default")) + mAllEffectInfo["default"] = LLSD::emptyMap(); + + LLSD& defaults = mAllEffectInfo["default"]; + + for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) { - LLSD & defaultEffect = (mAllEffects["default"] = LLSD::emptyMap()); - - /*defaultEffect["enable_night_vision"] = LLSD::Boolean(false); - defaultEffect["enable_color_filter"] = LLSD::Boolean(false);*/ - - /// NVG Defaults - defaultEffect["brightness_multiplier"] = 3.0; - defaultEffect["noise_size"] = 25.0; - defaultEffect["noise_strength"] = 0.4; - - // TODO BTest potentially add this to tweaks? - mNoiseTextureScale = 1.0f; - - /// Color Filter Defaults - defaultEffect["gamma"] = 1.0; - defaultEffect["brightness"] = 1.0; - defaultEffect["contrast"] = 1.0; - defaultEffect["saturation"] = 1.0; - - LLSD& contrastBase = (defaultEffect["contrast_base"] = LLSD::emptyArray()); - contrastBase.append(1.0); - contrastBase.append(1.0); - contrastBase.append(1.0); - contrastBase.append(0.5); - - defaultEffect["gauss_blur_passes"] = 2; + LLSD shader_defaults = (*it)->getDefaults(); + for (LLSD::map_const_iterator it2 = defaults.beginMap();it2 != defaults.endMap();++it2) + { + if(!defaults.has(it2->first)) + defaults[it2->first]=it2->second; + } + } + for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) + { + (*it)->loadSettings(defaults); } - setSelectedEffect("default"); - // */ } LLPostProcess::~LLPostProcess(void) { - invalidate() ; -} - -/*static*/void LLPostProcess::cleanupClass() -{ - if(instanceExists()) - getInstance()->invalidate() ; -} - -void LLPostProcess::setSelectedEffect(std::string const & effectName) -{ - mSelectedEffectName = effectName; - static_cast(tweaks) = mAllEffects[effectName]; -} - -void LLPostProcess::saveEffect(std::string const & effectName) -{ - mAllEffects[effectName] = tweaks; - - std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); - //llinfos << "Saving PostProcess Effects settings to " << pathName << llendl; - - llofstream effectsXML(pathName); - - LLPointer formatter = new LLSDXMLFormatter(); - - formatter->format(mAllEffects, effectsXML); -} -void LLPostProcess::invalidate() -{ - mSceneRenderTexture = NULL ; - mNoiseTexture = NULL ; - mVBO = NULL ; -} - -void LLPostProcess::apply(unsigned int width, unsigned int height) -{ - if(shadersEnabled()) - { - if (mVBO.isNull() || width != mScreenWidth || height != mScreenHeight) - { - initialize(width, height); - } - doEffects(); - } + destroyGL() ; } void LLPostProcess::initialize(unsigned int width, unsigned int height) { - invalidate(); + destroyGL(); mScreenWidth = width; mScreenHeight = height; - createScreenTexture(); + createScreenTextures(); + createNoiseTexture(); //Setup our VBO. { @@ -185,127 +342,129 @@ void LLPostProcess::initialize(unsigned int width, unsigned int height) mVBO->flush(); } - - checkError(); - createNoiseTexture(); - checkError(); + stop_glerror(); } -inline bool LLPostProcess::shadersEnabled(void) +void LLPostProcess::createScreenTextures() { - return (tweaks.useColorFilter().asBoolean() || - tweaks.useNightVisionShader().asBoolean() || - tweaks.useGaussBlurFilter().asBoolean() ); + const LLTexUnit::eTextureType type = LLTexUnit::TT_RECT_TEXTURE; + + mRenderTarget[0].allocate(mScreenWidth,mScreenHeight,GL_RGBA,FALSE,FALSE,type,FALSE); + if(mRenderTarget[0].getFBO())//Only need pingpong between two rendertargets if FBOs are supported. + mRenderTarget[1].allocate(mScreenWidth,mScreenHeight,GL_RGBA,FALSE,FALSE,type,FALSE); + stop_glerror(); + + if(mDepthTexture) + LLImageGL::deleteTextures(type, 0, 0, 1, &mDepthTexture, true); + + LLImageGL::generateTextures(type, GL_DEPTH_COMPONENT24, 1, &mDepthTexture); + gGL.getTexUnit(0)->bindManual(type, mDepthTexture); + LLImageGL::setManualImage(LLTexUnit::getInternalType(type), 0, GL_DEPTH_COMPONENT24, mScreenWidth, mScreenHeight, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + stop_glerror(); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); } -void LLPostProcess::applyShaders(void) -{ - bool copy_buffer = false; - if (tweaks.useColorFilter()) - { - applyColorFilterShader(); - checkError(); - copy_buffer = true; - } - if (tweaks.useGaussBlurFilter()) - { - /// If any of the above shaders have been called update the frame buffer; - if (copy_buffer) - copyFrameBuffer(); - applyGaussBlurShader(); - checkError(); - copy_buffer = true; - } - if (tweaks.useNightVisionShader()) - { - /// If any of the above shaders have been called update the frame buffer; - if (copy_buffer) - copyFrameBuffer(); - applyNightVisionShader(); - checkError(); - copy_buffer = true; - } -} - -void LLPostProcess::applyColorFilterShader(void) +void LLPostProcess::createNoiseTexture() { - if(gPostColorFilterProgram.mProgramObject == 0) - return; - - gPostColorFilterProgram.bind(); - - gGL.getTexUnit(0)->bind(mSceneRenderTexture); - - gPostColorFilterProgram.uniform1f("gamma", tweaks.getGamma()); - gPostColorFilterProgram.uniform1f("brightness", tweaks.getBrightness()); - gPostColorFilterProgram.uniform1f("contrast", tweaks.getContrast()); - float baseI = (tweaks.getContrastBaseR() + tweaks.getContrastBaseG() + tweaks.getContrastBaseB()) / 3.0f; - baseI = tweaks.getContrastBaseIntensity() / ((baseI < 0.001f) ? 0.001f : baseI); - float baseR = tweaks.getContrastBaseR() * baseI; - float baseG = tweaks.getContrastBaseG() * baseI; - float baseB = tweaks.getContrastBaseB() * baseI; - gPostColorFilterProgram.uniform3fv("contrastBase", 1, LLVector3(baseR, baseG, baseB).mV); - gPostColorFilterProgram.uniform1f("saturation", tweaks.getSaturation()); - gPostColorFilterProgram.uniform3fv("lumWeights", 1, LLVector3(LUMINANCE_R, LUMINANCE_G, LUMINANCE_B).mV); - - /// Draw a screen space quad - drawOrthoQuad(QUAD_NORMAL); - gPostColorFilterProgram.unbind(); -} - -void LLPostProcess::applyNightVisionShader(void) -{ - if(gPostNightVisionProgram.mProgramObject == 0) - return; - - gPostNightVisionProgram.bind(); - - gGL.getTexUnit(0)->bind(mSceneRenderTexture); - gGL.getTexUnit(1)->bind(mNoiseTexture); - - gPostNightVisionProgram.uniform1f("brightMult", tweaks.getBrightMult()); - gPostNightVisionProgram.uniform1f("noiseStrength", tweaks.getNoiseStrength()); - mNoiseTextureScale = 0.001f + ((100.f - tweaks.getNoiseSize()) / 100.f); - mNoiseTextureScale *= (mScreenHeight / NOISE_SIZE); - - /// Draw a screen space quad - drawOrthoQuad(QUAD_NOISE); - gPostNightVisionProgram.unbind(); -} - -void LLPostProcess::applyGaussBlurShader(void) -{ - int pass_count = tweaks.getGaussBlurPasses(); - if(!pass_count || gPostGaussianBlurProgram.mProgramObject == 0) - return; - - gPostGaussianBlurProgram.bind(); - - gGL.getTexUnit(0)->bind(mSceneRenderTexture); - - GLint horiz_pass = gPostGaussianBlurProgram.getUniformLocation("horizontalPass"); - for(int i = 0;i buffer(NOISE_SIZE * NOISE_SIZE); + for (unsigned int i = 0; i < NOISE_SIZE; i++){ + for (unsigned int k = 0; k < NOISE_SIZE; k++){ + buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f); + } + } + + for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) + { + if((*it)->getDepthChannel()>=0) + { + mNoiseTexture = new LLImageGL(FALSE) ; + if(mNoiseTexture->createGLTexture()) + { + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseTexture->getTexName()); + LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]); + stop_glerror(); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); + stop_glerror(); + break; + } + } + } +} + +void LLPostProcess::destroyGL() +{ + mRenderTarget[0].release(); + mRenderTarget[1].release(); + if(mDepthTexture) + LLImageGL::deleteTextures(LLTexUnit::TT_RECT_TEXTURE, 0, 0, 1, &mDepthTexture, true); + mDepthTexture=0; + mNoiseTexture = NULL ; + mVBO = NULL ; +} + +/*static*/void LLPostProcess::cleanupClass() +{ + if(instanceExists()) + getInstance()->destroyGL() ; +} + +void LLPostProcess::copyFrameBuffer() +{ + mRenderTarget[!!mRenderTarget[0].getFBO()].bindTexture(0,0); + glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,0,0,mScreenWidth, mScreenHeight); + + if(mDepthTexture) + { + for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) + { + if((*it)->isEnabled() && (*it)->getDepthChannel()>=0) + { + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mDepthTexture); + glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,0,0,mScreenWidth, mScreenHeight); + break; + } + } + } + +} + +void LLPostProcess::bindNoise(U32 channel) +{ + gGL.getTexUnit(channel)->bind(mNoiseTexture); +} + +void LLPostProcess::renderEffects(unsigned int width, unsigned int height) +{ + for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) + { + if((*it)->isEnabled()) + { + if (mVBO.isNull() || width != mScreenWidth || height != mScreenHeight) + { + initialize(width, height); + } + doEffects(); + return; } } - gPostGaussianBlurProgram.unbind(); } void LLPostProcess::doEffects(void) { LLVertexBuffer::unbind(); + mNoiseTextureScale = 0.001f + ((100.f - mSelectedEffectInfo["noise_size"].asFloat()) / 100.f); + mNoiseTextureScale *= (mScreenHeight / NOISE_SIZE); + /// Copy the screen buffer to the render texture copyFrameBuffer(); + stop_glerror(); //Disable depth. Set blendmode to replace. - LLGLDepthTest depth(GL_FALSE); + LLGLDepthTest depth(GL_FALSE,GL_FALSE); LLGLEnable blend(GL_BLEND); gGL.setSceneBlendType(LLRender::BT_REPLACE); @@ -319,7 +478,6 @@ void LLPostProcess::doEffects(void) gGL.loadIdentity(); applyShaders(); - checkError(); LLGLSLShader::bindNoShader(); @@ -333,13 +491,46 @@ void LLPostProcess::doEffects(void) gGL.setSceneBlendType(LLRender::BT_ALPHA); //Restore blendstate. Alpha is ASSUMED for hud/ui render, etc. gGL.getTexUnit(1)->disable(); - checkError(); } -void LLPostProcess::copyFrameBuffer() +void LLPostProcess::applyShaders(void) { - gGL.getTexUnit(0)->bindManual(mSceneRenderTexture->getTarget(), mSceneRenderTexture->getTexName()); - glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, mScreenWidth, mScreenHeight, 0); + QuadType quad; + bool primary_rendertarget = 1; + for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) + { + if((quad = (*it)->bind()) != QUAD_NONE) + { + S32 color_channel = (*it)->getColorChannel(); + S32 depth_channel = (*it)->getDepthChannel(); + + if(depth_channel >= 0) + gGL.getTexUnit(depth_channel)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mDepthTexture); + + U32 pass = 1; + + while((*it)->draw(pass++)) + { + mRenderTarget[!primary_rendertarget].bindTarget(); + + if(color_channel >= 0) + mRenderTarget[mRenderTarget[0].getFBO() ? primary_rendertarget : !primary_rendertarget].bindTexture(0,color_channel); + + drawOrthoQuad(quad); + mRenderTarget[!primary_rendertarget].flush(); + if(mRenderTarget[0].getFBO()) + primary_rendertarget = !primary_rendertarget; + } + (*it)->unbind(); + } + } + //Only need to copy to framebuffer if FBOs are supported, else we've already been drawing to the framebuffer to begin with. + if(mRenderTarget[0].getFBO()) + { + //copyContentsToFramebuffer also binds the main framebuffer. + LLRenderTarget::copyContentsToFramebuffer(mRenderTarget[primary_rendertarget],0,0,mScreenWidth,mScreenHeight,0,0,mScreenWidth,mScreenHeight,GL_COLOR_BUFFER_BIT, GL_NEAREST); + } + stop_glerror(); } void LLPostProcess::drawOrthoQuad(QuadType type) @@ -364,64 +555,59 @@ void LLPostProcess::drawOrthoQuad(QuadType type) mVBO->drawArrays(LLRender::TRIANGLE_STRIP, 0, 4); } -void LLPostProcess::createScreenTexture() +void LLPostProcess::setSelectedEffect(std::string const & effectName) { - std::vector data(mScreenWidth * mScreenHeight * 3, 0) ; - - mSceneRenderTexture = new LLImageGL(FALSE) ; - if(mSceneRenderTexture->createGLTexture()) + mSelectedEffectName = effectName; + mSelectedEffectInfo = mAllEffectInfo[effectName]; + for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mSceneRenderTexture->getTexName()); - LLImageGL::setManualImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, mScreenWidth, mScreenHeight, GL_RGB, GL_UNSIGNED_BYTE, &data[0]); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + (*it)->loadSettings(mSelectedEffectInfo); } } -void LLPostProcess::createNoiseTexture() -{ - std::vector buffer(NOISE_SIZE * NOISE_SIZE); - for (unsigned int i = 0; i < NOISE_SIZE; i++){ - for (unsigned int k = 0; k < NOISE_SIZE; k++){ - buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f); - } - } - - mNoiseTexture = new LLImageGL(FALSE) ; - if(mNoiseTexture->createGLTexture()) - { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseTexture->getTexName()); - LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); - } -} - -bool LLPostProcess::checkError(void) +void LLPostProcess::setSelectedEffectValue(std::string const & setting, LLSD& value) { - GLenum glErr; - bool retCode = false; - - glErr = glGetError(); - while (glErr != GL_NO_ERROR) - { - // shaderErrorLog << (const char *) gluErrorString(glErr) << std::endl; - char const * err_str_raw = (const char *) gluErrorString(glErr); - - if(err_str_raw == NULL) - { - std::ostringstream err_builder; - err_builder << "unknown error number " << glErr; - mShaderErrorString = err_builder.str(); - } - else - { - mShaderErrorString = err_str_raw; - } - - retCode = true; - glErr = glGetError(); - } - return retCode; + char buf[256]; + S32 elem=0; + if(sscanf(setting.c_str(),"%255[^[][%d]", buf, &elem) == 2) + { + mSelectedEffectInfo[buf][elem] = value; + } + else + { + mSelectedEffectInfo[setting] = value; + } + for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) + { + (*it)->loadSettings(mSelectedEffectInfo); + } } +void LLPostProcess::resetSelectedEffect() +{ + if(!llsd_equals(mAllEffectInfo[mSelectedEffectName], mSelectedEffectInfo)) + { + mSelectedEffectInfo = mAllEffectInfo[mSelectedEffectName]; + for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) + { + (*it)->loadSettings(mSelectedEffectInfo); + } + } +} + +void LLPostProcess::saveEffectAs(std::string const & effectName) +{ + mAllEffectInfo[effectName] = mSelectedEffectInfo; + + std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); + //llinfos << "Saving PostProcess Effects settings to " << pathName << llendl; + + llofstream effectsXML(pathName); + + LLPointer formatter = new LLSDXMLFormatter(); + + formatter->format(mAllEffectInfo, effectsXML); +} + + + diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h index 459fa6851..830598a92 100644 --- a/indra/llrender/llpostprocess.h +++ b/indra/llrender/llpostprocess.h @@ -34,189 +34,123 @@ #define LL_POSTPROCESS_H #include -#include -#include "llgl.h" -#include "llglheaders.h" +#include "llsd.h" +#include "llrendertarget.h" + +class LLSD; + +typedef enum _QuadType { + QUAD_NONE, + QUAD_NORMAL, + QUAD_NOISE +} QuadType; + +//LLPostProcessShader is an attempt to encapsulate the shaders a little better. +class LLPostProcessShader : public LLRefCount //Abstract. PostProcess shaders derive off of this common base. +{ +protected: + //LLShaderSetting is used to associate key names to member variables to avoid LLSD lookups when drawing. + //It also facilitates automating the assigning of defaults to, as well as parsing from, the effects LLSD list. + //This replaces the entire old PostProcessTweaks structure. More will be done in the future to move into a more + //xml-driven configuration. + struct LLShaderSettingBase + { + LLShaderSettingBase(const char* name) : mSettingName(name) {} + const char* mSettingName; //LLSD key names as found in postprocesseffects.xml. eg 'contrast_base' + virtual LLSD getDefaultValue() = 0; //Converts the member variable as an LLSD. Used to set defaults absent in postprocesseffects.xml + virtual void setValue(const LLSD& value) = 0; //Connects the LLSD element to the member variable. Used when loading effects (such as default) + }; + template + struct LLShaderSetting : public LLShaderSettingBase + { + LLShaderSetting(const char* setting_name, T def) : LLShaderSettingBase(setting_name), mValue(def), mDefault(def) {} + T mValue; //The member variable mentioned above. + T mDefault; //Set via ctor. Value is inserted into the defaults LLSD list if absent from postprocesseffects.xml + LLSD getDefaultValue() { return mDefault; } //See LLShaderSettingBase::getDefaultValue + void setValue(const LLSD& value) { mValue = value; } //See LLShaderSettingBase::setValue + operator T() { return mValue; } //Typecast operator overload so this object can be handled as if it was whatever T represents. + }; + std::vector mSettings; //Contains a list of all the 'settings' this shader uses. Manually add via push_back in ctor. +public: + virtual ~LLPostProcessShader() {}; + virtual bool isEnabled() = 0; //Returning false avoids bind/draw/unbind calls. If no shaders are enabled, framebuffer copying is skipped. + virtual S32 getColorChannel() = 0; //If color buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer. + virtual S32 getDepthChannel() = 0; //If depth buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer. + virtual QuadType bind() = 0; //Bind shader and textures, set up attribs. Returns the 'type' of quad to be drawn. + virtual bool draw(U32 pass) = 0; //returning false means finished. Used to update per-pass attributes and such. LLPostProcess will call + //drawOrthoQuad when this returns true, increment pass, then call this again, and keep repeating this until false is returned. + virtual void unbind() = 0; //Unbind shader and textures. + + LLSD getDefaults(); //Returns a full LLSD kvp list filled with default values. + void loadSettings(const LLSD& settings); //Parses the effects LLSD list and sets the member variables linked to them (via LLShaderSetting::setValue()) +}; + +//LLVector4 does not implicitly convert to and from LLSD, so template specilizations are necessary. +template<> LLSD LLPostProcessShader::LLShaderSetting::getDefaultValue(); +template<> void LLPostProcessShader::LLShaderSetting::setValue(const LLSD& value); class LLPostProcess : public LLSingleton { -public: - - typedef enum _QuadType { - QUAD_NORMAL, - QUAD_NOISE - } QuadType; - - /// GLSL Shader Encapsulation Struct - //typedef std::map glslUniforms; - - struct PostProcessTweaks : public LLSD { - inline PostProcessTweaks() : LLSD(LLSD::emptyMap()) - { - } - - inline LLSD & brightMult() { - return (*this)["brightness_multiplier"]; - } - - inline LLSD & noiseStrength() { - return (*this)["noise_strength"]; - } - - inline LLSD & noiseSize() { - return (*this)["noise_size"]; - } - - inline LLSD & brightness() { - return (*this)["brightness"]; - } - - inline LLSD & contrast() { - return (*this)["contrast"]; - } - - inline LLSD & contrastBaseR() { - return (*this)["contrast_base"][0]; - } - - inline LLSD & contrastBaseG() { - return (*this)["contrast_base"][1]; - } - - inline LLSD & contrastBaseB() { - return (*this)["contrast_base"][2]; - } - - inline LLSD & contrastBaseIntensity() { - return (*this)["contrast_base"][3]; - } - - inline LLSD & saturation() { - return (*this)["saturation"]; - } - - inline LLSD & useNightVisionShader() { - return (*this)["enable_night_vision"]; - } - - inline LLSD & useColorFilter() { - return (*this)["enable_color_filter"]; - } - - inline LLSD & useGaussBlurFilter() { - return (*this)["enable_gauss_blur"]; - } - - inline F32 getBrightMult() const { - return F32((*this)["brightness_multiplier"].asReal()); - } - - inline F32 getNoiseStrength() const { - return F32((*this)["noise_strength"].asReal()); - } - - inline F32 getNoiseSize() const { - return F32((*this)["noise_size"].asReal()); - } - - inline F32 getGamma() const { - return F32((*this)["gamma"].asReal()); - } - - inline F32 getBrightness() const { - return F32((*this)["brightness"].asReal()); - } - - inline F32 getContrast() const { - return F32((*this)["contrast"].asReal()); - } - - inline F32 getContrastBaseR() const { - return F32((*this)["contrast_base"][0].asReal()); - } - - inline F32 getContrastBaseG() const { - return F32((*this)["contrast_base"][1].asReal()); - } - - inline F32 getContrastBaseB() const { - return F32((*this)["contrast_base"][2].asReal()); - } - - inline F32 getContrastBaseIntensity() const { - return F32((*this)["contrast_base"][3].asReal()); - } - - inline F32 getSaturation() const { - return F32((*this)["saturation"].asReal()); - } - - inline LLSD & getGaussBlurPasses() { - return (*this)["gauss_blur_passes"]; - } - }; - - PostProcessTweaks tweaks; - - // the map of all availible effects - LLSD mAllEffects; - private: + std::list > mShaders; //List of all registered LLPostProcessShader instances. + LLPointer mVBO; - LLPointer mSceneRenderTexture ; + U32 mNextDrawTarget; //Need to pingpong between two rendertargets. Cannot sample target texture of currently bound FBO. + // However this is ONLY the case if fbos are actually supported, else swapping isn't needed. + LLRenderTarget mRenderTarget[2]; + U32 mDepthTexture; LLPointer mNoiseTexture ; + + U32 mScreenWidth; + U32 mScreenHeight; + F32 mNoiseTextureScale; + + // The name of currently selected effect in mAllEffectInfo + std::string mSelectedEffectName; + // The map of settings for currently selected effect. + LLSD mSelectedEffectInfo; + // The map of all availible effects + LLSD mAllEffectInfo; public: LLPostProcess(void); - ~LLPostProcess(void); +private: + // OpenGL initialization + void initialize(unsigned int width, unsigned int height); //Sets mScreenWidth and mScreenHeight + // calls createScreenTextures and createNoiseTexture + // creates VBO + void createScreenTextures(); //Creates color texture and depth texture(if needed). + void createNoiseTexture(); //Creates 'random' noise texture. - void apply(unsigned int width, unsigned int height); - void invalidate() ; - - // Cleanup of global data that's only inited once per class. +public: + // Teardown + // Called on destroyGL or cleanupClass. Releases VBOs, rendertargets and textures. + void destroyGL(); + // Cleanup of global data that's only inited once per class. static void cleanupClass(); - void setSelectedEffect(std::string const & effectName); - - inline std::string const & getSelectedEffect(void) const { - return mSelectedEffectName; - } - - void saveEffect(std::string const & effectName); - -private: - /// read in from file - std::string mShaderErrorString; - unsigned int mScreenWidth; - unsigned int mScreenHeight; - - float mNoiseTextureScale; - - // the name of currently selected effect in mAllEffects - // invariant: tweaks == mAllEffects[mSelectedEffectName] - std::string mSelectedEffectName; - - /// General functions - void initialize(unsigned int width, unsigned int height); - void doEffects(void); - void applyShaders(void); - bool shadersEnabled(void); - - /// Night Vision Functions - void applyNightVisionShader(void); - - /// Color Filter Functions - void applyColorFilterShader(void); - - /// Gaussian blur Filter Functions - void applyGaussBlurShader(void); - - /// OpenGL Helper Functions + // Setup for draw. void copyFrameBuffer(); - void createScreenTexture(); - void createNoiseTexture(); - bool checkError(void); - void drawOrthoQuad(QuadType type); + void bindNoise(U32 channel); + + // Draw + void renderEffects(unsigned int width, unsigned int height); //Entry point for newview. +private: + void doEffects(void); //Sets up viewmatrix, blits the framebuffer, then calls applyShaders. + void applyShaders(void); //Iterates over all active post shaders, manages binding, calls drawOrthoQuad for render. + void drawOrthoQuad(QuadType type); //Finally draws fullscreen quad with the shader currently bound. + +public: + // UI interaction + // Getters + inline LLSD const & getAllEffectInfo(void) const { return mAllEffectInfo; } + inline std::string const & getSelectedEffectName(void) const { return mSelectedEffectName; } + inline LLSD const & getSelectedEffectInfo(void) const { return mSelectedEffectInfo; } + // Setters + void setSelectedEffect(std::string const & effectName); + void setSelectedEffectValue(std::string const & setting, LLSD& value); + void resetSelectedEffect(); + void saveEffectAs(std::string const & effectName); }; #endif // LL_POSTPROCESS_H diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index d73b17a51..b952a0e4b 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -380,7 +380,7 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) if (bindDepth) { - if (renderTarget->hasStencil()) + if (renderTarget->hasStencil() && renderTarget->getFBO()) { llerrs << "Cannot bind a render buffer for sampling. Allocate render target without a stencil buffer if sampling of depth buffer is required." << llendl; } diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 27fec6843..c75304957 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -93,7 +93,7 @@ void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt) if (mDepth) { //resize depth attachment - if (mStencil) + if (mStencil && mFBO) { //use render buffers where stencil buffers are in play glBindRenderbuffer(GL_RENDERBUFFER, mDepth); @@ -104,7 +104,10 @@ void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt) { gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + if(!mStencil) + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + else + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8, mResX, mResY, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL, false); } sBytesAllocated += pix_diff*4; @@ -131,9 +134,10 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo mUsage = usage; mUseDepth = depth; - if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject) { + glGenFramebuffers(1, (GLuint *) &mFBO); + if (depth) { if (!allocateDepth()) @@ -143,8 +147,6 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo } } - glGenFramebuffers(1, (GLuint *) &mFBO); - if (mDepth) { glBindFramebuffer(GL_FRAMEBUFFER, mFBO); @@ -162,7 +164,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo } glBindFramebuffer(GL_FRAMEBUFFER, 0); } - + stop_glerror(); } @@ -255,7 +257,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) bool LLRenderTarget::allocateDepth() { - if (mStencil) + if (mStencil && mFBO) { //use render buffers where stencil buffers are in play glGenRenderbuffers(1, (GLuint *) &mDepth); @@ -267,13 +269,19 @@ bool LLRenderTarget::allocateDepth() } else { - LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth); + if(!mStencil) + LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth); + else + LLImageGL::generateTextures(mUsage, GL_DEPTH24_STENCIL8, 1, &mDepth); gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); stop_glerror(); clear_glerror(); - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + if(!mStencil) + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + else + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8, mResX, mResY, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL, false); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } @@ -337,7 +345,7 @@ void LLRenderTarget::release() { if (mDepth) { - if (mStencil) + if (mStencil && mFBO) { glDeleteRenderbuffers(1, (GLuint*) &mDepth); stop_glerror(); @@ -490,6 +498,7 @@ void LLRenderTarget::flush(bool fetch_depth) { gGL.getTexUnit(0)->bind(this); glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, 0, 0, 0, 0, mResX, mResY); + stop_glerror(); if (fetch_depth) { @@ -498,8 +507,10 @@ void LLRenderTarget::flush(bool fetch_depth) allocateDepth(); } - gGL.getTexUnit(0)->bind(this); - glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8, 0, 0, mResX, mResY, 0); + gGL.getTexUnit(0)->bind(this,true); + glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, 0, 0, 0, 0, mResX, mResY); + stop_glerror(); + //glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8, 0, 0, mResX, mResY, 0); } gGL.getTexUnit(0)->disable(); @@ -589,7 +600,7 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, } else { - if (mask == GL_DEPTH_BUFFER_BIT && source.mStencil != mStencil) + if (mask == GL_DEPTH_BUFFER_BIT && !mStencil && source.mStencil != mStencil) { stop_glerror(); diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 8268f1984..d9a529ff0 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -151,6 +151,8 @@ public: //one renderable attachment (i.e. color buffer, depth buffer). bool isComplete() const; + U32 getFBO() const {return mFBO;} + static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; } protected: diff --git a/indra/newview/app_settings/shaders/class1/effects/PosterizeF.glsl b/indra/newview/app_settings/shaders/class1/effects/PosterizeF.glsl new file mode 100644 index 000000000..1da0cdbad --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/effects/PosterizeF.glsl @@ -0,0 +1,23 @@ +/** + * @file colorFilterF.glsl + * + * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#extension GL_ARB_texture_rectangle : enable + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 gl_FragColor; +#endif + +uniform sampler2DRect tex0; +uniform int layerCount; + +VARYING vec2 vary_texcoord0; + +void main(void) +{ + vec3 color = pow(floor(pow(vec3(texture2D(tex0, vary_texcoord0.st)),vec3(.6)) * layerCount)/layerCount,vec3(1.66666)); + gl_FragColor = vec4(color, 1.0); +} diff --git a/indra/newview/app_settings/windlight/postprocesseffects.xml b/indra/newview/app_settings/windlight/postprocesseffects.xml index 9261f3287..0914b275a 100644 --- a/indra/newview/app_settings/windlight/postprocesseffects.xml +++ b/indra/newview/app_settings/windlight/postprocesseffects.xml @@ -174,6 +174,8 @@ 0 enable_gauss_blur 0 + enable_posterize + 0 gauss_blur_passes 2 extract_high @@ -186,6 +188,8 @@ 0.40000000000000002 saturation 1 - + posterize_layers + 10 + \ No newline at end of file diff --git a/indra/newview/llfloaterdaycycle.cpp b/indra/newview/llfloaterdaycycle.cpp index 4f6b5fb5a..7028e5016 100644 --- a/indra/newview/llfloaterdaycycle.cpp +++ b/indra/newview/llfloaterdaycycle.cpp @@ -57,7 +57,6 @@ #include "lldaycyclemanager.h" #include "llwlparamset.h" #include "llwlparammanager.h" -#include "llpostprocess.h" #include "llfloaterwindlight.h" diff --git a/indra/newview/llfloaterpostprocess.cpp b/indra/newview/llfloaterpostprocess.cpp index 40eb5e048..dc4af9e94 100644 --- a/indra/newview/llfloaterpostprocess.cpp +++ b/indra/newview/llfloaterpostprocess.cpp @@ -115,17 +115,7 @@ LLFloaterPostProcess* LLFloaterPostProcess::instance() void LLFloaterPostProcess::onControlChanged(LLUICtrl* ctrl, void* userData) { - char const *VariableName = (char const *)userData; - char buf[256]; - S32 elem=0; - if(sscanf(VariableName,"%255[^[][%d]", buf, &elem) == 2) - { - LLPostProcess::getInstance()->tweaks[(const char*)buf][elem] = ctrl->getValue(); - } - else - { - LLPostProcess::getInstance()->tweaks[VariableName] = ctrl->getValue(); - } + LLPostProcess::getInstance()->setSelectedEffectValue((char const *)userData,ctrl->getValue()); } void LLFloaterPostProcess::onLoadEffect(void* userData) @@ -145,7 +135,7 @@ void LLFloaterPostProcess::onSaveEffect(void* userData) std::string effectName(editBox->getValue().asString()); - if (LLPostProcess::getInstance()->mAllEffects.has(effectName)) + if (LLPostProcess::getInstance()->getAllEffectInfo().has(effectName)) { LLSD payload; payload["effect_name"] = effectName; @@ -153,7 +143,7 @@ void LLFloaterPostProcess::onSaveEffect(void* userData) } else { - LLPostProcess::getInstance()->saveEffect(effectName); + LLPostProcess::getInstance()->saveEffectAs(effectName); sPostProcess->syncMenu(); } } @@ -175,7 +165,7 @@ bool LLFloaterPostProcess::saveAlertCallback(const LLSD& notification, const LLS // if they choose save, do it. Otherwise, don't do anything if (option == 0) { - LLPostProcess::getInstance()->saveEffect(notification["payload"]["effect_name"].asString()); + LLPostProcess::getInstance()->saveEffectAs(notification["payload"]["effect_name"].asString()); sPostProcess->syncMenu(); } @@ -209,17 +199,17 @@ void LLFloaterPostProcess::syncMenu() comboBox->removeall(); LLSD::map_const_iterator currEffect; - for(currEffect = LLPostProcess::getInstance()->mAllEffects.beginMap(); - currEffect != LLPostProcess::getInstance()->mAllEffects.endMap(); + for(currEffect = LLPostProcess::getInstance()->getAllEffectInfo().beginMap(); + currEffect != LLPostProcess::getInstance()->getAllEffectInfo().endMap(); ++currEffect) { comboBox->add(currEffect->first); } // set the current effect as selected. - comboBox->selectByValue(LLPostProcess::getInstance()->getSelectedEffect()); + comboBox->selectByValue(LLPostProcess::getInstance()->getSelectedEffectName()); - LLSD &tweaks = LLPostProcess::getInstance()->tweaks; + const LLSD &tweaks = LLPostProcess::getInstance()->getSelectedEffectInfo(); //Iterate down all uniforms handled by post-process shaders. Update any linked ui elements. for (LLSD::map_const_iterator it = tweaks.beginMap(); it != tweaks.endMap(); ++it) { diff --git a/indra/newview/llfloaterwater.cpp b/indra/newview/llfloaterwater.cpp index 04ef4e5af..0a72fdadf 100644 --- a/indra/newview/llfloaterwater.cpp +++ b/indra/newview/llfloaterwater.cpp @@ -62,7 +62,6 @@ #include "llwaterparamset.h" #include "llwaterparammanager.h" -#include "llpostprocess.h" #undef max diff --git a/indra/newview/llfloaterwindlight.cpp b/indra/newview/llfloaterwindlight.cpp index 942763ad8..d84eaf2a2 100644 --- a/indra/newview/llfloaterwindlight.cpp +++ b/indra/newview/llfloaterwindlight.cpp @@ -62,7 +62,6 @@ #include "llwlparamset.h" #include "llwlparammanager.h" -#include "llpostprocess.h" #undef max diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 18aaabef4..973ca7ad2 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -200,7 +200,6 @@ #include "llnamelistctrl.h" #include "llnamebox.h" #include "llnameeditor.h" -#include "llpostprocess.h" #include "llwlparammanager.h" #include "llwaterparammanager.h" #include "llagentlanguage.h" diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 8b8c8b703..2279197e5 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1009,7 +1009,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) { gPipeline.mDeferredScreen.flush(); - if(LLRenderTarget::sUseFBO) + if(gPipeline.mDeferredScreen.getFBO()) { LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(), 0, 0, @@ -1021,7 +1021,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo else { gPipeline.mScreen.flush(); - if(LLRenderTarget::sUseFBO) + if(gPipeline.mScreen.getFBO()) { LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(), gPipeline.mScreen.getHeight(), 0, 0, @@ -1283,14 +1283,12 @@ void render_ui(F32 zoom_factor, int subfield, bool tiling) if (to_texture) { gPipeline.renderBloom(gSnapshot, zoom_factor, subfield, tiling); - gPipeline.mScreen.flush(); //blit, etc. } - /// We copy the frame buffer straight into a texture here, - /// and then display it again with compositor effects. - /// Using render to texture would be faster/better, but I don't have a - /// grasp of their full display stack just yet. + if(gPipeline.canUseVertexShaders()) - LLPostProcess::getInstance()->apply(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight()); + { + LLPostProcess::getInstance()->renderEffects(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight()); + } render_hud_elements(); render_hud_attachments(); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 6ab2cfd17..2b2de806f 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -170,6 +170,7 @@ LLGLSLShader gGlowExtractProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in LLGLSLShader gPostColorFilterProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList LLGLSLShader gPostNightVisionProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList LLGLSLShader gPostGaussianBlurProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList +LLGLSLShader gPostPosterizeProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList // Deferred rendering shaders LLGLSLShader gDeferredImpostorProgram(LLViewerShaderMgr::SHADER_DEFERRED); @@ -958,6 +959,23 @@ BOOL LLViewerShaderMgr::loadShadersEffects() gPostGaussianBlurProgram.uniform1i("tex0", 0); } } + + { + vector shaderUniforms; + shaderUniforms.reserve(1); + shaderUniforms.push_back("layerCount"); + + gPostPosterizeProgram.mName = "Posterize Shader (Post)"; + gPostPosterizeProgram.mShaderFiles.clear(); + gPostPosterizeProgram.mShaderFiles.push_back(make_pair("effects/PosterizeF.glsl", GL_FRAGMENT_SHADER_ARB)); + gPostPosterizeProgram.mShaderFiles.push_back(make_pair("interface/onetexturenocolorV.glsl", GL_VERTEX_SHADER_ARB)); + gPostPosterizeProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT]; + if(gPostPosterizeProgram.createShader(NULL, &shaderUniforms)) + { + gPostPosterizeProgram.bind(); + gPostPosterizeProgram.uniform1i("tex0", 0); + } + } #endif return success; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index acd55d913..d31c262ea 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4839,7 +4839,7 @@ void LLViewerWindow::stopGL(BOOL save_state) if(LLPostProcess::instanceExists()) { - LLPostProcess::getInstance()->invalidate(); + LLPostProcess::getInstance()->destroyGL(); } gTextureList.destroyGL(save_state); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 9f4c7b1f7..ff866877d 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -54,6 +54,7 @@ #include "llglheaders.h" #include "llrender.h" #include "llwindow.h" +#include "llpostprocess.h" // newview includes #include "llagent.h" @@ -863,6 +864,9 @@ void LLPipeline::releaseGLBuffers() gBumpImageList.destroyGL(); LLVOAvatar::resetImpostors(); + + if(LLPostProcess::instanceExists()) + LLPostProcess::getInstance()->destroyGL(); } void LLPipeline::releaseLUTBuffers() @@ -6111,12 +6115,14 @@ void LLPipeline::doResetVertexBuffers() LLVOPartGroup::destroyGL(); + if(LLPostProcess::instanceExists()) + LLPostProcess::getInstance()->destroyGL(); + LLVertexBuffer::cleanupClass(); //delete all name pool caches LLGLNamePool::cleanupPools(); - if (LLVertexBuffer::sGLCount > 0) { llwarns << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << llendl; @@ -6923,7 +6929,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b } - if (LLRenderTarget::sUseFBO) + if (mScreen.getFBO()) { //copy depth buffer from mScreen to framebuffer LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); diff --git a/indra/newview/skins/default/xui/en-us/floater_post_process.xml b/indra/newview/skins/default/xui/en-us/floater_post_process.xml index 179a40e2e..bde532911 100644 --- a/indra/newview/skins/default/xui/en-us/floater_post_process.xml +++ b/indra/newview/skins/default/xui/en-us/floater_post_process.xml @@ -146,6 +146,25 @@ left="14" max_val="1" min_val="0" mouse_opaque="true" name="noise_strength" show_text="true" value="1.0" width="200" /> + + + + Layer Count + + +