summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt6
-rw-r--r--indra/newview/app_settings/settings.xml2
-rw-r--r--indra/newview/featuretable.txt6
-rw-r--r--indra/newview/featuretable_mac.txt2
-rw-r--r--indra/newview/llagentcamera.cpp19
-rw-r--r--indra/newview/llagentcamera.h6
-rw-r--r--indra/newview/llappviewer.cpp2
-rw-r--r--indra/newview/lldrawpool.h1
-rw-r--r--indra/newview/lldrawpoolalpha.cpp170
-rw-r--r--indra/newview/lldrawpoolalpha.h4
-rw-r--r--indra/newview/lldrawpoolbump.cpp226
-rw-r--r--indra/newview/lldrawpoolbump.h2
-rw-r--r--indra/newview/lldrawpoolwater.cpp11
-rw-r--r--indra/newview/llfloatermodelpreview.cpp9
-rw-r--r--indra/newview/llinventorybridge.cpp5
-rw-r--r--indra/newview/llinventorybridge.h1
-rw-r--r--indra/newview/llmodelpreview.cpp135
-rw-r--r--indra/newview/llnetmap.cpp4
-rw-r--r--indra/newview/llspatialpartition.cpp31
-rw-r--r--indra/newview/llspatialpartition.h13
-rw-r--r--indra/newview/lltoolmorph.cpp13
-rw-r--r--indra/newview/lltracker.cpp11
-rw-r--r--indra/newview/llviewercontrol.cpp3
-rw-r--r--indra/newview/llviewerdisplay.cpp5
-rw-r--r--indra/newview/llviewermedia.cpp408
-rw-r--r--indra/newview/llviewermedia.h13
-rw-r--r--indra/newview/llvieweroctree.cpp65
-rw-r--r--indra/newview/llviewerparcelmgr.cpp2
-rw-r--r--indra/newview/llviewertexture.cpp27
-rw-r--r--indra/newview/llviewerwindow.cpp6
-rw-r--r--indra/newview/llvoavatar.cpp39
-rw-r--r--indra/newview/llvoavatar.h7
-rw-r--r--indra/newview/llvovolume.cpp62
-rw-r--r--indra/newview/llvovolume.h1
-rw-r--r--indra/newview/pipeline.cpp192
-rw-r--r--indra/newview/pipeline.h3
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml7
37 files changed, 1022 insertions, 497 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 73b234eb75..e7f0af84ef 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1697,6 +1697,8 @@ set(viewer_APPSETTINGS_FILES
${CMAKE_SOURCE_DIR}/../etc/message.xml
${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg
packages-info.txt
+ featuretable.txt
+ featuretable_mac.txt
)
source_group("App Settings" FILES ${viewer_APPSETTINGS_FILES})
@@ -1751,10 +1753,6 @@ endif (HAVOK OR HAVOK_TPV)
# progress view disables/enables icons based on available packages
set_source_files_properties(llprogressview.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
-if (GLODLIB)
- set_source_files_properties(llfloatermodelpreview.cpp PROPERTIES COMPILE_FLAGS "-DLL_GLOD")
-endif (GLODLIB)
-
list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES})
set_source_files_properties(${viewer_HEADER_FILES}
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index bb83824628..bfc47d2c65 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9886,7 +9886,7 @@
<key>Value</key>
<real>2.2</real>
</map>
- <key>RenderGLCoreProfile</key>
+ <key>RenderGLContextCoreProfile</key>
<map>
<key>Comment</key>
<string>Don't use a compatibility profile OpenGL context. Requires restart. Basic shaders MUST be enabled.</string>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index a5e0e395de..ff7ac84803 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -70,7 +70,7 @@ RenderShadowDetail 1 2
RenderUseStreamVBO 1 1
RenderFSAASamples 1 16
RenderMaxTextureIndex 1 16
-RenderGLCoreProfile 1 1
+RenderGLContextCoreProfile 1 1
RenderGLMultiThreaded 1 1
@@ -320,12 +320,12 @@ list Intel
RenderAnisotropic 1 0
RenderFSAASamples 1 0
RenderGLMultiThreaded 1 0
-RenderGLCoreProfile 1 0
+RenderGLContextCoreProfile 1 0
// AMD cards generally perform better when not using VBOs for streaming data
// AMD cards also prefer an OpenGL Compatibility Profile Context
list AMD
RenderUseStreamVBO 1 0
-RenderGLCoreProfile 1 0
+RenderGLContextCoreProfile 1 0
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 5140614bab..248eb68ee9 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -70,7 +70,7 @@ RenderShadowDetail 1 2
RenderUseStreamVBO 1 1
RenderFSAASamples 1 16
RenderMaxTextureIndex 1 16
-RenderGLCoreProfile 1 0
+RenderGLContextCoreProfile 1 0
RenderGLMultiThreaded 1 0
//
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index ed6c3c307f..84a41113be 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -210,9 +210,6 @@ void LLAgentCamera::init()
mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPresetType");
- mCameraOffsetInitial = gSavedSettings.getControl("CameraOffsetRearView");
- mFocusOffsetInitial = gSavedSettings.getControl("FocusOffsetRearView");
-
mCameraCollidePlane.clearVec();
mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale");
mTargetCameraDistance = mCurrentCameraDistance;
@@ -1672,8 +1669,8 @@ LLVector3d LLAgentCamera::calcThirdPersonFocusOffset()
agent_rot *= ((LLViewerObject*)(gAgentAvatarp->getParent()))->getRenderRotation();
}
- focus_offset = convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, "");
- return focus_offset * agent_rot;
+ static LLCachedControl<LLVector3d> focus_offset_initial(gSavedSettings, "FocusOffsetRearView", LLVector3d());
+ return focus_offset_initial * agent_rot;
}
void LLAgentCamera::setupSitCamera()
@@ -1810,8 +1807,9 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
}
else
{
- local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * gSavedSettings.getF32("CameraOffsetScale");
-
+ static LLCachedControl<F32> camera_offset_scale(gSavedSettings, "CameraOffsetScale");
+ local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * camera_offset_scale;
+
// are we sitting down?
if (isAgentAvatarValid() && gAgentAvatarp->getParent())
{
@@ -2028,12 +2026,15 @@ bool LLAgentCamera::isJoystickCameraUsed()
LLVector3 LLAgentCamera::getCameraOffsetInitial()
{
- return convert_from_llsd<LLVector3>(mCameraOffsetInitial->get(), TYPE_VEC3, "");
+ // getCameraOffsetInitial and getFocusOffsetInitial can be called on update from idle before init()
+ static LLCachedControl<LLVector3> camera_offset_initial (gSavedSettings, "CameraOffsetRearView", LLVector3());
+ return camera_offset_initial;
}
LLVector3d LLAgentCamera::getFocusOffsetInitial()
{
- return convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, "");
+ static LLCachedControl<LLVector3d> focus_offset_initial(gSavedSettings, "FocusOffsetRearView", LLVector3d());
+ return focus_offset_initial;
}
F32 LLAgentCamera::getCameraMaxZoomDistance()
diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h
index ec1ed433d7..89680f95dc 100644
--- a/indra/newview/llagentcamera.h
+++ b/indra/newview/llagentcamera.h
@@ -131,12 +131,6 @@ private:
/** Camera preset in Third Person Mode */
ECameraPreset mCameraPreset;
- /** Initial camera offset */
- LLPointer<LLControlVariable> mCameraOffsetInitial;
-
- /** Initial focus offset */
- LLPointer<LLControlVariable> mFocusOffsetInitial;
-
LLQuaternion mInitSitRot;
//--------------------------------------------------------------------
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 73d0eac0ac..66c44ef6a6 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -532,7 +532,7 @@ static void settings_to_globals()
LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
- LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLCoreProfile");
+ LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLContextCoreProfile");
LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport");
LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index d4f30fc51a..fd1b022e5b 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -183,6 +183,7 @@ public:
PASS_GLOW,
PASS_GLOW_RIGGED,
PASS_ALPHA,
+ PASS_ALPHA_RIGGED,
PASS_ALPHA_MASK,
PASS_ALPHA_MASK_RIGGED,
PASS_FULLBRIGHT_ALPHA_MASK, // Diffuse texture used as alpha mask and fullbright
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 9da20cc375..2bf8e9b911 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -129,23 +129,26 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
deferred_render = TRUE;
- // first pass, regular forward alpha rendering
- {
- emissive_shader = (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
- prepare_alpha_shader(emissive_shader, true, false);
-
- fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram :
- (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram;
- prepare_alpha_shader(fullbright_shader, true, false);
-
- simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
- (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
- prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms)
-
- forwardRender();
- }
+ // prepare shaders
+ emissive_shader = (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
+ prepare_alpha_shader(emissive_shader, true, false);
+
+ fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram :
+ (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram;
+ prepare_alpha_shader(fullbright_shader, true, false);
+
+ simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
+ (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
+ prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms)
+
- // second pass, render to depth for depth of field effects
+ // first pass, render rigged objects only and render to depth buffer
+ forwardRender(true);
+
+ // second pass, regular forward alpha rendering
+ forwardRender();
+
+ // final pass, render to depth for depth of field effects
if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField"))
{
//update depth buffer sampler
@@ -209,10 +212,14 @@ void LLDrawPoolAlpha::render(S32 pass)
prepare_forward_shader(fullbright_shader, minimum_alpha);
prepare_forward_shader(simple_shader, minimum_alpha);
+ //first pass -- rigged only and drawn to depth buffer
+ forwardRender(true);
+
+ //second pass -- non-rigged, no depth buffer writes
forwardRender();
}
-void LLDrawPoolAlpha::forwardRender()
+void LLDrawPoolAlpha::forwardRender(bool rigged)
{
gPipeline.enableLightsDynamic();
@@ -221,7 +228,8 @@ void LLDrawPoolAlpha::forwardRender()
//enable writing to alpha for emissive effects
gGL.setColorMask(true, true);
- bool write_depth = LLDrawPoolWater::sSkipScreenCopy
+ bool write_depth = rigged
+ || LLDrawPoolWater::sSkipScreenCopy
// we want depth written so that rendered alpha will
// contribute to the alpha mask used for impostors
|| LLPipeline::sImpostorRenderAlphaDepthPass;
@@ -236,11 +244,17 @@ void LLDrawPoolAlpha::forwardRender()
// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
// We don't want the nearly invisible objects to cause of DoF effects
- renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
+ renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged);
gGL.setColorMask(true, false);
- renderDebugAlpha();
+ if (!rigged)
+ { //render "highlight alpha" on final non-rigged pass
+ // NOTE -- hacky call here protected by !rigged instead of alongside "forwardRender"
+ // so renderDebugAlpha is executed while gls_pipeline_alpha and depth GL state
+ // variables above are still in scope
+ renderDebugAlpha();
+ }
}
void LLDrawPoolAlpha::renderDebugAlpha()
@@ -291,54 +305,60 @@ void LLDrawPoolAlpha::renderDebugAlpha()
void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
{
- LLVOAvatar* lastAvatar = nullptr;
- U64 lastMeshId = 0;
+ for (int pass = 0; pass < 2; ++pass)
+ { //two passes, one rigged and one not
+ LLVOAvatar* lastAvatar = nullptr;
+ U64 lastMeshId = 0;
- for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (group->getSpatialPartition()->mRenderByGroup &&
- !group->isDead())
- {
- LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];
+ LLCullResult::sg_iterator begin = pass == 0 ? gPipeline.beginAlphaGroups() : gPipeline.beginRiggedAlphaGroups();
+ LLCullResult::sg_iterator end = pass == 0 ? gPipeline.endAlphaGroups() : gPipeline.endRiggedAlphaGroups();
- for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
- {
- LLDrawInfo& params = **k;
-
- if (params.mParticle)
- {
- continue;
- }
-
- bool rigged = (params.mAvatar != nullptr);
- gHighlightProgram.bind(rigged);
- gGL.diffuseColor4f(1, 0, 0, 1);
+ for (LLCullResult::sg_iterator i = begin; i != end; ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (group->getSpatialPartition()->mRenderByGroup &&
+ !group->isDead())
+ {
+ LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA+pass]; // <-- hacky + pass to use PASS_ALPHA_RIGGED on second pass
- if (rigged)
+ for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
{
- if (lastAvatar != params.mAvatar ||
- lastMeshId != params.mSkinInfo->mHash)
+ LLDrawInfo& params = **k;
+
+ if (params.mParticle)
{
- if (!uploadMatrixPalette(params))
+ continue;
+ }
+
+ bool rigged = (params.mAvatar != nullptr);
+ gHighlightProgram.bind(rigged);
+ gGL.diffuseColor4f(1, 0, 0, 1);
+
+ if (rigged)
+ {
+ if (lastAvatar != params.mAvatar ||
+ lastMeshId != params.mSkinInfo->mHash)
{
- continue;
+ if (!uploadMatrixPalette(params))
+ {
+ continue;
+ }
+ lastAvatar = params.mAvatar;
+ lastMeshId = params.mSkinInfo->mHash;
}
- lastAvatar = params.mAvatar;
- lastMeshId = params.mSkinInfo->mHash;
}
- }
- LLRenderPass::applyModelMatrix(params);
- if (params.mGroup)
- {
- params.mGroup->rebuildMesh();
- }
- params.mVertexBuffer->setBufferFast(rigged ? mask | LLVertexBuffer::MAP_WEIGHT4 : mask);
- params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
- }
- }
- }
+ LLRenderPass::applyModelMatrix(params);
+ if (params.mGroup)
+ {
+ params.mGroup->rebuildMesh();
+ }
+ params.mVertexBuffer->setBufferFast(rigged ? mask | LLVertexBuffer::MAP_WEIGHT4 : mask);
+ params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+ }
+ }
+ }
+ }
// make sure static version of highlight shader is bound before returning
gHighlightProgram.bind();
@@ -471,6 +491,8 @@ void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>&
LLVOAvatar* lastAvatar = nullptr;
U64 lastMeshId = 0;
+ mask |= LLVertexBuffer::MAP_WEIGHT4;
+
for (LLDrawInfo* draw : emissives)
{
bool tex_setup = TexSetup(draw, false);
@@ -488,7 +510,7 @@ void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>&
}
}
-void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
+void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
BOOL initialized_lighting = FALSE;
@@ -498,7 +520,21 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
U64 lastMeshId = 0;
LLGLSLShader* lastAvatarShader = nullptr;
- for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
+ LLCullResult::sg_iterator begin;
+ LLCullResult::sg_iterator end;
+
+ if (rigged)
+ {
+ begin = gPipeline.beginRiggedAlphaGroups();
+ end = gPipeline.endRiggedAlphaGroups();
+ }
+ else
+ {
+ begin = gPipeline.beginAlphaGroups();
+ end = gPipeline.endAlphaGroups();
+ }
+
+ for (LLCullResult::sg_iterator i = begin; i != end; ++i)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group");
LLSpatialGroup* group = *i;
@@ -521,12 +557,18 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
bool disable_cull = is_particle_or_hud_particle;
LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0);
- LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];
+ LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA];
for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
{
- LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch")
LLDrawInfo& params = **k;
+ if ((bool)params.mAvatar != rigged)
+ {
+ continue;
+ }
+
+ LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch")
+
U32 have_mask = params.mVertexBuffer->getTypeMask() & mask;
if (have_mask != mask)
{ //FIXME!
@@ -753,7 +795,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params)
{
- const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar->updateSkinInfoMatrixPalette(params.mSkinInfo);
+ const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar.get()->updateSkinInfoMatrixPalette(params.mSkinInfo);
U32 count = mpc.mMatrixPalette.size();
if (count == 0)
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index 1f6909e282..fa8ef0f227 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -55,13 +55,13 @@ public:
/*virtual*/ S32 getNumPasses() { return 1; }
virtual void render(S32 pass = 0);
- void forwardRender();
+ void forwardRender(bool write_depth = false);
/*virtual*/ void prerender();
void renderDebugAlpha();
void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
- void renderAlpha(U32 mask, bool depth_only = false);
+ void renderAlpha(U32 mask, bool depth_only = false, bool rigged = false);
void renderAlphaHighlight(U32 mask);
bool uploadMatrixPalette(const LLDrawInfo& params);
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 471b0e2c48..1d5419b515 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -54,6 +54,8 @@
// static
LLStandardBumpmap gStandardBumpmapList[TEM_BUMPMAP_COUNT];
+LL::WorkQueue::weak_t LLBumpImageList::sMainQueue;
+LL::WorkQueue::weak_t LLBumpImageList::sTexUpdateQueue;
// static
U32 LLStandardBumpmap::sStandardBumpmapCount = 0;
@@ -74,6 +76,8 @@ static S32 cube_channel = -1;
static S32 diffuse_channel = -1;
static S32 bump_channel = -1;
+#define LL_BUMPLIST_MULTITHREADED 0
+
// static
void LLStandardBumpmap::init()
{
@@ -761,6 +765,8 @@ void LLBumpImageList::init()
LLStandardBumpmap::init();
LLStandardBumpmap::restoreGL();
+ sMainQueue = LL::WorkQueue::getInstance("mainloop");
+ sTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader.
}
void LLBumpImageList::clear()
@@ -909,10 +915,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
}
else
{
- LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
- raw->clear(0x77, 0x77, 0xFF, 0xFF);
-
- (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
+ (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( TRUE );
bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image
}
@@ -1043,16 +1046,13 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
iter->second->getWidth() != src->getWidth() ||
iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
{ //make sure an entry exists for this image
- LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
- raw->clear(0x77, 0x77, 0xFF, 0xFF);
-
- entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
+ entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(TRUE);
iter = entries_list.find(src_vi->getID());
}
}
- //if (iter->second->getWidth() != src->getWidth() ||
- // iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
+ if (iter->second->getWidth() != src->getWidth() ||
+ iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
{
LLPointer<LLImageRaw> dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1);
U8* dst_data = dst_image->getData();
@@ -1166,108 +1166,178 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
}
//---------------------------------------------------
- // immediately assign bump to a global smart pointer in case some local smart pointer
+ // immediately assign bump to a smart pointer in case some local smart pointer
// accidentally releases it.
- LLPointer<LLViewerTexture> bump = LLViewerTextureManager::getLocalTexture( TRUE );
+ LLPointer<LLViewerTexture> bump = iter->second;
if (!LLPipeline::sRenderDeferred)
{
bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
- bump->createGLTexture(0, dst_image);
+
+#if LL_BUMPLIST_MULTITHREADED
+ auto tex_queue = LLImageGLThread::sEnabled ? sTexUpdateQueue.lock() : nullptr;
+
+ if (tex_queue)
+ { //dispatch creation to background thread
+ LLImageRaw* dst_ptr = dst_image;
+ LLViewerTexture* bump_ptr = bump;
+ dst_ptr->ref();
+ bump_ptr->ref();
+ tex_queue->post(
+ [=]()
+ {
+ LL_PROFILE_ZONE_NAMED("bil - create texture");
+ bump_ptr->createGLTexture(0, dst_ptr);
+ bump_ptr->unref();
+ dst_ptr->unref();
+ });
+
+ }
+ else
+#endif
+ {
+ bump->createGLTexture(0, dst_image);
+ }
}
else
{ //convert to normal map
//disable compression on normal maps to prevent errors below
bump->getGLTexture()->setAllowCompression(false);
+ bump->getGLTexture()->setUseMipMaps(TRUE);
- {
- bump->setExplicitFormat(GL_RGBA8, GL_ALPHA);
- bump->createGLTexture(0, dst_image);
- }
+ auto* bump_ptr = bump.get();
+ auto* dst_ptr = dst_image.get();
- {
- gPipeline.mScreen.bindTarget();
-
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable cull(GL_CULL_FACE);
- LLGLDisable blend(GL_BLEND);
- gGL.setColorMask(TRUE, TRUE);
- gNormalMapGenProgram.bind();
+#if LL_BUMPLIST_MULTITHREADED
+ bump_ptr->ref();
+ dst_ptr->ref();
+#endif
- static LLStaticHashedString sNormScale("norm_scale");
- static LLStaticHashedString sStepX("stepX");
- static LLStaticHashedString sStepY("stepY");
+ bump_ptr->setExplicitFormat(GL_RGBA8, GL_ALPHA);
- gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale"));
- gNormalMapGenProgram.uniform1f(sStepX, 1.f/bump->getWidth());
- gNormalMapGenProgram.uniform1f(sStepY, 1.f/bump->getHeight());
+ auto create_texture = [=]()
+ {
+#if LL_IMAGEGL_THREAD_CHECK
+ bump_ptr->getGLTexture()->mActiveThread = LLThread::currentID();
+#endif
+ LL_PROFILE_ZONE_NAMED("bil - create texture deferred");
+ bump_ptr->createGLTexture(0, dst_ptr);
+ };
+
+ auto gen_normal_map = [=]()
+ {
+#if LL_IMAGEGL_THREAD_CHECK
+ bump_ptr->getGLTexture()->mActiveThread = LLThread::currentID();
+#endif
+ LL_PROFILE_ZONE_NAMED("bil - generate normal map");
+ if (gNormalMapGenProgram.mProgramObject == 0)
+ {
+#if LL_BUMPLIST_MULTITHREADED
+ bump_ptr->unref();
+ dst_ptr->unref();
+#endif
+ return;
+ }
+ gPipeline.mScreen.bindTarget();
- LLVector2 v((F32) bump->getWidth()/gPipeline.mScreen.getWidth(),
- (F32) bump->getHeight()/gPipeline.mScreen.getHeight());
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+ LLGLDisable blend(GL_BLEND);
+ gGL.setColorMask(TRUE, TRUE);
+ gNormalMapGenProgram.bind();
- gGL.getTexUnit(0)->bind(bump);
-
- S32 width = bump->getWidth();
- S32 height = bump->getHeight();
+ static LLStaticHashedString sNormScale("norm_scale");
+ static LLStaticHashedString sStepX("stepX");
+ static LLStaticHashedString sStepY("stepY");
- S32 screen_width = gPipeline.mScreen.getWidth();
- S32 screen_height = gPipeline.mScreen.getHeight();
+ gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale"));
+ gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth());
+ gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight());
- glViewport(0, 0, screen_width, screen_height);
+ LLVector2 v((F32)bump_ptr->getWidth() / gPipeline.mScreen.getWidth(),
+ (F32)bump_ptr->getHeight() / gPipeline.mScreen.getHeight());
- for (S32 left = 0; left < width; left += screen_width)
- {
- S32 right = left + screen_width;
- right = llmin(right, width);
-
- F32 left_tc = (F32) left/ width;
- F32 right_tc = (F32) right/width;
+ gGL.getTexUnit(0)->bind(bump_ptr);
- for (S32 bottom = 0; bottom < height; bottom += screen_height)
- {
- S32 top = bottom+screen_height;
- top = llmin(top, height);
+ S32 width = bump_ptr->getWidth();
+ S32 height = bump_ptr->getHeight();
- F32 bottom_tc = (F32) bottom/height;
- F32 top_tc = (F32)(bottom+screen_height)/height;
- top_tc = llmin(top_tc, 1.f);
+ S32 screen_width = gPipeline.mScreen.getWidth();
+ S32 screen_height = gPipeline.mScreen.getHeight();
- F32 screen_right = (F32) (right-left)/screen_width;
- F32 screen_top = (F32) (top-bottom)/screen_height;
+ glViewport(0, 0, screen_width, screen_height);
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(left_tc, bottom_tc);
- gGL.vertex2f(0, 0);
+ for (S32 left = 0; left < width; left += screen_width)
+ {
+ S32 right = left + screen_width;
+ right = llmin(right, width);
- gGL.texCoord2f(left_tc, top_tc);
- gGL.vertex2f(0, screen_top);
+ F32 left_tc = (F32)left / width;
+ F32 right_tc = (F32)right / width;
- gGL.texCoord2f(right_tc, bottom_tc);
- gGL.vertex2f(screen_right, 0);
+ for (S32 bottom = 0; bottom < height; bottom += screen_height)
+ {
+ S32 top = bottom + screen_height;
+ top = llmin(top, height);
- gGL.texCoord2f(right_tc, top_tc);
- gGL.vertex2f(screen_right, screen_top);
+ F32 bottom_tc = (F32)bottom / height;
+ F32 top_tc = (F32)(bottom + screen_height) / height;
+ top_tc = llmin(top_tc, 1.f);
- gGL.end();
+ F32 screen_right = (F32)(right - left) / screen_width;
+ F32 screen_top = (F32)(top - bottom) / screen_height;
- gGL.flush();
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(left_tc, bottom_tc);
+ gGL.vertex2f(0, 0);
- S32 w = right-left;
- S32 h = top-bottom;
+ gGL.texCoord2f(left_tc, top_tc);
+ gGL.vertex2f(0, screen_top);
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h);
- }
- }
+ gGL.texCoord2f(right_tc, bottom_tc);
+ gGL.vertex2f(screen_right, 0);
- glGenerateMipmap(GL_TEXTURE_2D);
+ gGL.texCoord2f(right_tc, top_tc);
+ gGL.vertex2f(screen_right, screen_top);
- gPipeline.mScreen.flush();
+ gGL.end();
- gNormalMapGenProgram.unbind();
-
- //generateNormalMapFromAlpha(dst_image, nrm_image);
- }
+ gGL.flush();
+
+ S32 w = right - left;
+ S32 h = top - bottom;
+
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h);
+ }
+ }
+
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ gPipeline.mScreen.flush();
+
+ gNormalMapGenProgram.unbind();
+
+ //generateNormalMapFromAlpha(dst_image, nrm_image);
+#if LL_BUMPLIST_MULTITHREADED
+ bump_ptr->unref();
+ dst_ptr->unref();
+#endif
+ };
+
+#if LL_BUMPLIST_MULTITHREADED
+ auto main_queue = sMainQueue.lock();
+
+ if (LLImageGLThread::sEnabled)
+ { //dispatch creation to background thread
+ main_queue->postTo(sTexUpdateQueue, create_texture, gen_normal_map);
+ }
+ else
+#endif
+ {
+ create_texture();
+ gen_normal_map();
+ }
}
iter->second = bump; // derefs (and deletes) old image
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 38744a7d98..6e21859738 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -161,6 +161,8 @@ private:
typedef std::unordered_map<LLUUID, LLPointer<LLViewerTexture> > bump_image_map_t;
bump_image_map_t mBrightnessEntries;
bump_image_map_t mDarknessEntries;
+ static LL::WorkQueue::weak_t sMainQueue;
+ static LL::WorkQueue::weak_t sTexUpdateQueue;
};
extern LLBumpImageList gBumpImageList;
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 0f2bcf4708..6762b38c39 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -520,9 +520,10 @@ void LLDrawPoolWater::renderWater()
LLColor4 specular(sun_up ? psky->getSunlightColor() : psky->getMoonlightColor());
F32 phase_time = (F32) LLFrameTimer::getElapsedSeconds() * 0.5f;
- bool edge = false;
LLGLSLShader *shader = nullptr;
- do // twice through, once with normal shader bound & once with edge shader bound
+
+ // two passes, first with standard water shader bound, second with edge water shader bound
+ for( int edge = 0 ; edge < 2; edge++ )
{
// select shader
if (underwater && LLPipeline::sWaterReflections)
@@ -675,7 +676,7 @@ void LLDrawPoolWater::renderWater()
gGL.getTexUnit(diffTex)->bind(face->getTexture());
- if (edge == (bool) water->getIsEdgePatch())
+ if ((bool)edge == (bool) water->getIsEdgePatch())
{
face->renderIndexed();
@@ -699,9 +700,7 @@ void LLDrawPoolWater::renderWater()
shader->unbind();
gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
-
- edge = !edge;
- } while (!edge);
+ }
gGL.getTexUnit(0)->activate();
gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 6135c4f13e..fe5120376c 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -351,15 +351,6 @@ void LLFloaterModelPreview::initModelPreview()
//static
bool LLFloaterModelPreview::showModelPreview()
{
-#ifdef LL_GLOD
- if (LLRender::sGLCoreProfile)
- {
- // GLOD is incompatible with RenderGLCoreProfile, will crash on init
- LLNotificationsUtil::add("MeshUploadProfilerError");
- return false;
- }
-#endif
-
LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)LLFloaterReg::getInstance("upload_model");
if (fmp && !fmp->isModelLoading())
{
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 06c8f66c1e..a0de3a2af1 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -5777,12 +5777,13 @@ LLCallingCardBridge::LLCallingCardBridge(LLInventoryPanel* inventory,
LLItemBridge(inventory, root, uuid)
{
mObserver = new LLCallingCardObserver(this);
- LLAvatarTracker::instance().addParticularFriendObserver(getItem()->getCreatorUUID(), mObserver);
+ mCreatorUUID = getItem()->getCreatorUUID();
+ LLAvatarTracker::instance().addParticularFriendObserver(mCreatorUUID, mObserver);
}
LLCallingCardBridge::~LLCallingCardBridge()
{
- LLAvatarTracker::instance().removeParticularFriendObserver(getItem()->getCreatorUUID(), mObserver);
+ LLAvatarTracker::instance().removeParticularFriendObserver(mCreatorUUID, mObserver);
delete mObserver;
}
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index c21bfbd02d..0b0ef273e1 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -457,6 +457,7 @@ public:
void checkSearchBySuffixChanges();
protected:
LLCallingCardObserver* mObserver;
+ LLUUID mCreatorUUID;
};
class LLNotecardBridge : public LLItemBridge
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index c9bf0b0a12..d3eb2dd4d4 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1235,6 +1235,11 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
size_vertices += face.mNumVertices;
}
+ if (size_indices < 3)
+ {
+ return -1;
+ }
+
// Allocate buffers, note that we are using U32 buffer instead of U16
U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
@@ -1279,10 +1284,10 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
// Now that we have buffers, optimize
S32 target_indices = 0;
- F32 result_code = 0; // how far from original the model is, 1 == 100%
+ F32 result_error = 0; // how far from original the model is, 1 == 100%
S32 new_indices = 0;
- target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle
+ target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle
new_indices = LLMeshOptimizer::simplifyU32(
output_indices,
combined_indices,
@@ -1293,17 +1298,27 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
target_indices,
error_threshold,
sloppy,
- &result_code);
+ &result_error);
- if (result_code < 0)
+ if (result_error < 0)
{
- LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel
+ LL_WARNS() << "Negative result error from meshoptimizer for model " << target_model->mLabel
<< " target Indices: " << target_indices
<< " new Indices: " << new_indices
<< " original count: " << size_indices << LL_ENDL;
}
+ if (new_indices < 3)
+ {
+ // Model should have at least one visible triangle
+ ll_aligned_free<64>(combined_positions);
+ ll_aligned_free_32(output_indices);
+ ll_aligned_free_32(combined_indices);
+
+ return -1;
+ }
+
// repack back into individual faces
LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
@@ -1456,16 +1471,20 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
{
const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
S32 size_indices = face.mNumIndices;
+ if (size_indices < 3)
+ {
+ return -1;
+ }
// todo: do not allocate per each face, add one large buffer somewhere
// faces have limited amount of indices
S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
U16* output = (U16*)ll_aligned_malloc_16(size);
S32 target_indices = 0;
- F32 result_code = 0; // how far from original the model is, 1 == 100%
+ F32 result_error = 0; // how far from original the model is, 1 == 100%
S32 new_indices = 0;
- target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle
+ target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle
new_indices = LLMeshOptimizer::simplify(
output,
face.mIndices,
@@ -1476,12 +1495,12 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
target_indices,
error_threshold,
sloppy,
- &result_code);
+ &result_error);
- if (result_code < 0)
+ if (result_error < 0)
{
- LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx
+ LL_WARNS() << "Negative result error from meshoptimizer for face " << face_idx
<< " of model " << target_model->mLabel
<< " target Indices: " << target_indices
<< " new Indices: " << new_indices
@@ -1693,21 +1712,21 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
// Run meshoptimizer for each face
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
{
- genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true);
+ if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true) < 0)
+ {
+ // Sloppy failed and returned an invalid model
+ genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
+ }
}
-
- LL_INFOS() << "Model " << target_model->getName()
- << " lod " << which_lod
- << " simplified using per face method." << LL_ENDL;
}
if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
{
- // Switches between 'combine' method and 'per model sloppy' based on combine's result.
+ // Switches between 'combine' method and 'sloppy' based on combine's result.
F32 allowed_ratio_drift = 2.f;
- F32 res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
-
- if (res_ratio < 0)
+ F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+
+ if (precise_ratio < 0)
{
// U16 vertices overflow, shouldn't happen, but just in case
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
@@ -1715,42 +1734,101 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
}
}
- else if (res_ratio * allowed_ratio_drift < indices_decimator)
+ else if (precise_ratio * allowed_ratio_drift < indices_decimator)
{
// Try sloppy variant if normal one failed to simplify model enough.
- res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
+ // Sloppy variant can fail entirely and has issues with precision,
+ // so code needs to do multiple attempts with different decimators.
+ // Todo: this is a bit of a mess, needs to be refined and improved
+ F32 last_working_decimator = 0.f;
+ F32 last_working_ratio = F32_MAX;
+
+ F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
+
+ if (sloppy_ratio > 0)
+ {
+ // Would be better to do a copy of target_model here, but if
+ // we need to use sloppy decimation, model should be cheap
+ // and fast to generate and it won't affect end result
+ last_working_decimator = indices_decimator;
+ last_working_ratio = sloppy_ratio;
+ }
// Sloppy has a tendecy to error into lower side, so a request for 100
// triangles turns into ~70, so check for significant difference from target decimation
F32 sloppy_ratio_drift = 1.4f;
if (lod_mode == LIMIT_TRIANGLES
- && (res_ratio > indices_decimator * sloppy_ratio_drift || res_ratio < 0))
+ && (sloppy_ratio > indices_decimator * sloppy_ratio_drift || sloppy_ratio < 0))
{
// Apply a correction to compensate.
// (indices_decimator / res_ratio) by itself is likely to overshoot to a differend
// side due to overal lack of precision, and we don't need an ideal result, which
// likely does not exist, just a better one, so a partial correction is enough.
- F32 sloppy_decimator = indices_decimator * (indices_decimator / res_ratio + 1) / 2;
- res_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
+ F32 sloppy_decimator = indices_decimator * (indices_decimator / sloppy_ratio + 1) / 2;
+ sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
+ }
+
+ if (last_working_decimator > 0 && sloppy_ratio < last_working_ratio)
+ {
+ // Compensation didn't work, return back to previous decimator
+ sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
}
+ if (sloppy_ratio < 0)
+ {
+ // Sloppy method didn't work, try with smaller decimation values
+ S32 size_vertices = 0;
+
+ for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
+ {
+ const LLVolumeFace &face = base->getVolumeFace(face_idx);
+ size_vertices += face.mNumVertices;
+ }
+
+ // Complex models aren't supposed to get here, they are supposed
+ // to work on a first try of sloppy due to having more viggle room.
+ // If they didn't, something is likely wrong, no point locking the
+ // thread in a long calculation that will fail.
+ const U32 too_many_vertices = 27000;
+ if (size_vertices > too_many_vertices)
+ {
+ LL_WARNS() << "Sloppy optimization method failed for a complex model " << target_model->getName() << LL_ENDL;
+ }
+ else
+ {
+ // Find a decimator that does work
+ F32 sloppy_decimation_step = sqrt((F32)decimation); // example: 27->15->9->5->3
+ F32 sloppy_decimator = indices_decimator / sloppy_decimation_step;
+
+ while (sloppy_ratio < 0
+ && sloppy_decimator > precise_ratio
+ && sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case
+ {
+ sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
+ sloppy_decimator = sloppy_decimator / sloppy_decimation_step;
+ }
+ }
+ }
- if (res_ratio < 0)
+ if (sloppy_ratio < 0 || sloppy_ratio < precise_ratio)
{
- // Sloppy variant failed to generate triangles.
+ // Sloppy variant failed to generate triangles or is worse.
// Can happen with models that are too simple as is.
- // Fallback to normal method or use lower decimator.
- genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+ // Fallback to normal method
+
+ precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
LL_INFOS() << "Model " << target_model->getName()
<< " lod " << which_lod
+ << " resulting ratio " << precise_ratio
<< " simplified using per model method." << LL_ENDL;
}
else
{
LL_INFOS() << "Model " << target_model->getName()
<< " lod " << which_lod
+ << " resulting ratio " << sloppy_ratio
<< " sloppily simplified using per model method." << LL_ENDL;
}
}
@@ -1758,6 +1836,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
{
LL_INFOS() << "Model " << target_model->getName()
<< " lod " << which_lod
+ << " resulting ratio " << precise_ratio
<< " simplified using per model method." << LL_ENDL;
}
}
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 937f36b6fc..1240ce7c0f 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -147,6 +147,10 @@ void LLNetMap::setScale( F32 scale )
void LLNetMap::draw()
{
+ if (!LLWorld::instanceExists())
+ {
+ return;
+ }
LL_PROFILE_ZONE_SCOPED;
static LLFrameTimer map_timer;
static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white);
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index eaf6186dae..5c648c11e1 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -4022,6 +4022,7 @@ LLCullResult::LLCullResult()
{
mVisibleGroupsAllocated = 0;
mAlphaGroupsAllocated = 0;
+ mRiggedAlphaGroupsAllocated = 0;
mOcclusionGroupsAllocated = 0;
mDrawableGroupsAllocated = 0;
mVisibleListAllocated = 0;
@@ -4033,6 +4034,9 @@ LLCullResult::LLCullResult()
mAlphaGroups.clear();
mAlphaGroups.push_back(NULL);
mAlphaGroupsEnd = &mAlphaGroups[0];
+ mRiggedAlphaGroups.clear();
+ mRiggedAlphaGroups.push_back(NULL);
+ mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[0];
mOcclusionGroups.clear();
mOcclusionGroups.push_back(NULL);
mOcclusionGroupsEnd = &mOcclusionGroups[0];
@@ -4073,6 +4077,9 @@ void LLCullResult::clear()
mAlphaGroupsSize = 0;
mAlphaGroupsEnd = &mAlphaGroups[0];
+ mRiggedAlphaGroupsSize = 0;
+ mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[0];
+
mOcclusionGroupsSize = 0;
mOcclusionGroupsEnd = &mOcclusionGroups[0];
@@ -4117,6 +4124,16 @@ LLCullResult::sg_iterator LLCullResult::endAlphaGroups()
return mAlphaGroupsEnd;
}
+LLCullResult::sg_iterator LLCullResult::beginRiggedAlphaGroups()
+{
+ return &mRiggedAlphaGroups[0];
+}
+
+LLCullResult::sg_iterator LLCullResult::endRiggedAlphaGroups()
+{
+ return mRiggedAlphaGroupsEnd;
+}
+
LLCullResult::sg_iterator LLCullResult::beginOcclusionGroups()
{
return &mOcclusionGroups[0];
@@ -4195,6 +4212,20 @@ void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
mAlphaGroupsEnd = &mAlphaGroups[mAlphaGroupsSize];
}
+void LLCullResult::pushRiggedAlphaGroup(LLSpatialGroup* group)
+{
+ if (mRiggedAlphaGroupsSize < mRiggedAlphaGroupsAllocated)
+ {
+ mRiggedAlphaGroups[mRiggedAlphaGroupsSize] = group;
+ }
+ else
+ {
+ pushBack(mRiggedAlphaGroups, mRiggedAlphaGroupsAllocated, group);
+ }
+ ++mRiggedAlphaGroupsSize;
+ mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[mRiggedAlphaGroupsSize];
+}
+
void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
{
if (mOcclusionGroupsSize < mOcclusionGroupsAllocated)
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index afe24d7d1f..acfcd63686 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -40,6 +40,8 @@
#include "llface.h"
#include "llviewercamera.h"
#include "llvector4a.h"
+#include "llvoavatar.h"
+
#include <queue>
#include <unordered_map>
@@ -125,7 +127,7 @@ public:
F32 mAlphaMaskCutoff;
U8 mDiffuseAlphaMode;
bool mSelected;
- LLVOAvatar* mAvatar = nullptr;
+ LLPointer<LLVOAvatar> mAvatar = nullptr;
LLMeshSkinInfo* mSkinInfo = nullptr;
@@ -470,6 +472,9 @@ public:
sg_iterator beginAlphaGroups();
sg_iterator endAlphaGroups();
+ sg_iterator beginRiggedAlphaGroups();
+ sg_iterator endRiggedAlphaGroups();
+
bool hasOcclusionGroups() { return mOcclusionGroupsSize > 0; }
sg_iterator beginOcclusionGroups();
sg_iterator endOcclusionGroups();
@@ -488,6 +493,7 @@ public:
void pushVisibleGroup(LLSpatialGroup* group);
void pushAlphaGroup(LLSpatialGroup* group);
+ void pushRiggedAlphaGroup(LLSpatialGroup* group);
void pushOcclusionGroup(LLSpatialGroup* group);
void pushDrawableGroup(LLSpatialGroup* group);
void pushDrawable(LLDrawable* drawable);
@@ -496,6 +502,7 @@ public:
U32 getVisibleGroupsSize() { return mVisibleGroupsSize; }
U32 getAlphaGroupsSize() { return mAlphaGroupsSize; }
+ U32 getRiggedAlphaGroupsSize() { return mRiggedAlphaGroupsSize; }
U32 getDrawableGroupsSize() { return mDrawableGroupsSize; }
U32 getVisibleListSize() { return mVisibleListSize; }
U32 getVisibleBridgeSize() { return mVisibleBridgeSize; }
@@ -509,6 +516,7 @@ private:
U32 mVisibleGroupsSize;
U32 mAlphaGroupsSize;
+ U32 mRiggedAlphaGroupsSize;
U32 mOcclusionGroupsSize;
U32 mDrawableGroupsSize;
U32 mVisibleListSize;
@@ -516,6 +524,7 @@ private:
U32 mVisibleGroupsAllocated;
U32 mAlphaGroupsAllocated;
+ U32 mRiggedAlphaGroupsAllocated;
U32 mOcclusionGroupsAllocated;
U32 mDrawableGroupsAllocated;
U32 mVisibleListAllocated;
@@ -527,6 +536,8 @@ private:
sg_iterator mVisibleGroupsEnd;
sg_list_t mAlphaGroups;
sg_iterator mAlphaGroupsEnd;
+ sg_list_t mRiggedAlphaGroups;
+ sg_iterator mRiggedAlphaGroupsEnd;
sg_list_t mOcclusionGroups;
sg_iterator mOcclusionGroupsEnd;
sg_list_t mDrawableGroups;
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index b2e8348ffd..b5eb2880ae 100644
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -239,17 +239,8 @@ BOOL LLVisualParamHint::render()
LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE);
- if (gAgentAvatarp->mDrawable.notNull() &&
- gAgentAvatarp->mDrawable->getFace(0))
- {
- LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)gAgentAvatarp->mDrawable->getFace(0)->getPool();
- LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
- gGL.flush();
- gGL.setSceneBlendType(LLRender::BT_REPLACE);
- avatarPoolp->renderAvatars(gAgentAvatarp); // renders only one avatar
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- gGL.flush();
- }
+ gPipeline.previewAvatar(gAgentAvatarp);
+
gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr;
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index 728d0c9417..ab4ad5817b 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -109,7 +109,16 @@ void LLTracker::stopTracking(bool clear_ui)
// static virtual
void LLTracker::drawHUDArrow()
{
- if (!gSavedSettings.getBOOL("RenderTrackerBeacon")) return;
+ if (!LLWorld::instanceExists())
+ {
+ return;
+ }
+
+ static LLCachedControl<bool> render_beacon(gSavedSettings, "RenderTrackerBeacon", true);
+ if (!render_beacon)
+ {
+ return;
+ }
if (gViewerWindow->getProgressView()->getVisible()) return;
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 4d86da5f78..40a7f0a941 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -266,9 +266,8 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)
static bool handleVSyncChanged(const LLSD& newvalue)
{
-#if LL_WINDOWS
gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean());
-#endif
+
return true;
}
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index a26331251c..bc8171b2fc 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -649,9 +649,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
}
- //upkeep gl name pools
- LLGLNamePool::upkeepPools();
-
stop_glerror();
display_update_camera();
stop_glerror();
@@ -791,6 +788,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
LLViewerTexture::updateClass();
}
+ LLImageGLThread::updateClass();
+
{
LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_BUMP);
gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first.
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 2bc0eeed92..27d8df28c3 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -39,6 +39,7 @@
#include "llfilepicker.h"
#include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows.
#include "llfocusmgr.h"
+#include "llimagegl.h"
#include "llkeyboard.h"
#include "lllogininstance.h"
#include "llmarketplacefunctions.h"
@@ -606,6 +607,7 @@ static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMedi
static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE("Update Media");
static LLTrace::BlockTimerStatHandle FTM_MEDIA_SPARE_IDLE("Spare Idle");
static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_INTEREST("Update/Interest");
+static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_VOLUME("Update/Volume");
static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT("Media Sort");
static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT2("Media Sort 2");
static LLTrace::BlockTimerStatHandle FTM_MEDIA_MISC("Misc");
@@ -625,6 +627,13 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
// Enable/disable the plugin read thread
LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));
+ // SL-16418 We can't call LLViewerMediaImpl->update() if we are in the state of shutting down.
+ if(LLApp::isExiting())
+ {
+ setAllMediaEnabled(false);
+ return;
+ }
+
// HACK: we always try to keep a spare running webkit plugin around to improve launch times.
// 2017-04-19 Removed CP - this doesn't appear to buy us much and consumes a lot of resources so
// removing it for now.
@@ -1561,6 +1570,8 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id,
media_tex->setMediaImpl();
}
+ mMainQueue = LL::WorkQueue::getInstance("mainloop");
+ mTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader.
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -1647,11 +1658,13 @@ void LLViewerMediaImpl::destroyMediaSource()
cancelMimeTypeProbe();
+ mLock.lock(); // Delay tear-down while bg thread is updating
if(mMediaSource)
{
mMediaSource->setDeleteOK(true) ;
mMediaSource = NULL; // shared pointer
}
+ mLock.unlock();
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -2060,6 +2073,7 @@ void LLViewerMediaImpl::setMute(bool mute)
//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::updateVolume()
{
+ LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_VOLUME);
if(mMediaSource)
{
// always scale the volume by the global media volume
@@ -2772,199 +2786,271 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_SET_SUBIMAGE("Set Subimage");
void LLViewerMediaImpl::update()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
- if(mMediaSource == NULL)
- {
- if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
- {
- // This media source should not be loaded.
- }
- else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW)
- {
- // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state.
- }
+ if(mMediaSource == NULL)
+ {
+ if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
+ {
+ // This media source should not be loaded.
+ }
+ else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW)
+ {
+ // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state.
+ }
else if (!mMimeProbe.expired())
- {
- // this media source is doing a MIME type probe -- don't try loading it again.
- }
- else
- {
- // This media may need to be loaded.
- if(sMediaCreateTimer.hasExpired())
- {
- LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL;
- createMediaSource();
- sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY);
- }
- else
- {
- LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL;
- }
- }
- }
- else
- {
- updateVolume();
+ {
+ // this media source is doing a MIME type probe -- don't try loading it again.
+ }
+ else
+ {
+ // This media may need to be loaded.
+ if(sMediaCreateTimer.hasExpired())
+ {
+ LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL;
+ createMediaSource();
+ sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY);
+ }
+ else
+ {
+ LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL;
+ }
+ }
+ }
+ else
+ {
+ updateVolume();
- // TODO: this is updated every frame - is this bad?
- // Removing this as part of the post viewer64 media update
- // Removed as not implemented in CEF embedded browser
- // See MAINT-8194 for a more fuller description
- // updateJavascriptObject();
- }
+ // TODO: this is updated every frame - is this bad?
+ // Removing this as part of the post viewer64 media update
+ // Removed as not implemented in CEF embedded browser
+ // See MAINT-8194 for a more fuller description
+ // updateJavascriptObject();
+ }
- if(mMediaSource == NULL)
- {
- return;
- }
+ if(mMediaSource == NULL)
+ {
+ return;
+ }
- // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash.
- setNavigateSuspended(true);
+ // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash.
+ setNavigateSuspended(true);
- mMediaSource->idle();
+ mMediaSource->idle();
- setNavigateSuspended(false);
+ setNavigateSuspended(false);
- if(mMediaSource == NULL)
- {
- return;
- }
+ if(mMediaSource == NULL)
+ {
+ return;
+ }
- if(mMediaSource->isPluginExited())
- {
- resetPreviousMediaState();
- destroyMediaSource();
- return;
- }
+ if(mMediaSource->isPluginExited())
+ {
+ resetPreviousMediaState();
+ destroyMediaSource();
+ return;
+ }
- if(!mMediaSource->textureValid())
- {
- return;
- }
+ if(!mMediaSource->textureValid())
+ {
+ return;
+ }
- if(mSuspendUpdates || !mVisible)
- {
- return;
- }
+ if(mSuspendUpdates || !mVisible)
+ {
+ return;
+ }
- LLViewerMediaTexture* placeholder_image = updatePlaceholderImage();
+
+ LLViewerMediaTexture* media_tex;
+ U8* data;
+ S32 data_width;
+ S32 data_height;
+ S32 x_pos;
+ S32 y_pos;
+ S32 width;
+ S32 height;
+
+ if (preMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height))
+ {
+ // Push update to worker thread
+ auto main_queue = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;
+ if (main_queue)
+ {
+ mTextureUpdatePending = true;
+ ref(); // protect texture from deletion while active on bg queue
+ media_tex->ref();
+ main_queue->postTo(
+ mTexUpdateQueue, // Worker thread queue
+ [=]() // work done on update worker thread
+ {
+#if LL_IMAGEGL_THREAD_CHECK
+ media_tex->getGLTexture()->mActiveThread = LLThread::currentID();
+#endif
+ doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, true);
+ },
+ [=]() // callback to main thread
+ {
+#if LL_IMAGEGL_THREAD_CHECK
+ media_tex->getGLTexture()->mActiveThread = LLThread::currentID();
+#endif
+ mTextureUpdatePending = false;
+ media_tex->unref();
+ unref();
+ });
+ }
+ else
+ {
+ doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, false); // otherwise, update on main thread
+ }
+ }
+}
- if(placeholder_image)
- {
- LLRect dirty_rect;
+bool LLViewerMediaImpl::preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& data, S32& data_width, S32& data_height, S32& x_pos, S32& y_pos, S32& width, S32& height)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
- // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered.
- placeholder_image->setPlaying(TRUE);
+ bool retval = false;
- if(mMediaSource->getDirty(&dirty_rect))
- {
- // Constrain the dirty rect to be inside the texture
- S32 x_pos = llmax(dirty_rect.mLeft, 0);
- S32 y_pos = llmax(dirty_rect.mBottom, 0);
- S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos;
- S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos;
+ if (!mTextureUpdatePending)
+ {
+ media_tex = updateMediaImage();
- if(width > 0 && height > 0)
- {
+ if (media_tex && mMediaSource)
+ {
+ LLRect dirty_rect;
+ S32 media_width = mMediaSource->getTextureWidth();
+ S32 media_height = mMediaSource->getTextureHeight();
+ //S32 media_depth = mMediaSource->getTextureDepth();
- U8* data = NULL;
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media get data"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA);
- data = mMediaSource->getBitsData();
- }
+ // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered.
+ media_tex->setPlaying(TRUE);
- if(data != NULL)
- {
- // Offset the pixels pointer to match x_pos and y_pos
- data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() );
- data += ( y_pos * mMediaSource->getTextureDepth() );
+ if (mMediaSource->getDirty(&dirty_rect))
+ {
+ // Constrain the dirty rect to be inside the texture
+ x_pos = llmax(dirty_rect.mLeft, 0);
+ y_pos = llmax(dirty_rect.mBottom, 0);
+ width = llmin(dirty_rect.mRight, media_width) - x_pos;
+ height = llmin(dirty_rect.mTop, media_height) - y_pos;
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media set subimage"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
- placeholder_image->setSubImage(
- data,
- mMediaSource->getBitsWidth(),
- mMediaSource->getBitsHeight(),
- x_pos,
- y_pos,
- width,
- height);
- }
- }
+ if (width > 0 && height > 0)
+ {
+ data = mMediaSource->getBitsData();
+ data_width = mMediaSource->getWidth();
+ data_height = mMediaSource->getHeight();
+
+ if (data != NULL)
+ {
+ // data is ready to be copied to GL
+ retval = true;
+ }
+ }
- }
+ mMediaSource->resetDirty();
+ }
+ }
+ }
- mMediaSource->resetDirty();
- }
- }
+ return retval;
}
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
+ mLock.lock(); // don't allow media source tear-down during update
+
+ // wrap "data" in an LLImageRaw but do NOT make a copy
+ LLPointer<LLImageRaw> raw = new LLImageRaw(data, media_tex->getWidth(), media_tex->getHeight(), media_tex->getComponents(), true);
+
+ // Allocate GL texture based on LLImageRaw but do NOT copy to GL
+ LLGLuint tex_name = 0;
+ media_tex->createGLTexture(0, raw, 0, TRUE, LLGLTexture::OTHER, true, &tex_name);
+
+ // copy just the subimage covered by the image raw to GL
+ media_tex->setSubImage(data, data_width, data_height, x_pos, y_pos, width, height, tex_name);
+
+ if (sync)
+ {
+ media_tex->getGLTexture()->syncToMainThread(tex_name);
+ }
+ else
+ {
+ media_tex->getGLTexture()->syncTexName(tex_name);
+ }
+
+ // release the data pointer before freeing raw so LLImageRaw destructor doesn't
+ // free memory at data pointer
+ raw->releaseData();
+
+ mLock.unlock();
+}
//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::updateImagesMediaStreams()
{
}
-
//////////////////////////////////////////////////////////////////////////////////////////
-LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
+LLViewerMediaTexture* LLViewerMediaImpl::updateMediaImage()
{
- if(mTextureId.isNull())
- {
- // The code that created this instance will read from the plugin's bits.
- return NULL;
- }
-
- LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId );
-
- if (mNeedsNewTexture
- || placeholder_image->getUseMipMaps()
- || (placeholder_image->getWidth() != mMediaSource->getTextureWidth())
- || (placeholder_image->getHeight() != mMediaSource->getTextureHeight())
- || (mTextureUsedWidth != mMediaSource->getWidth())
- || (mTextureUsedHeight != mMediaSource->getHeight())
- )
- {
- LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL;
- LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL;
-
- int texture_width = mMediaSource->getTextureWidth();
- int texture_height = mMediaSource->getTextureHeight();
- int texture_depth = mMediaSource->getTextureDepth();
-
- // MEDIAOPT: check to see if size actually changed before doing work
- placeholder_image->destroyGLTexture();
- // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work?
- placeholder_image->reinit(FALSE); // probably not needed
-
- // MEDIAOPT: seems insane that we actually have to make an imageraw then
- // immediately discard it
- LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth);
- // Clear the texture to the background color, ignoring alpha.
- // convert background color channels from [0.0, 1.0] to [0, 255];
- raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff);
- int discard_level = 0;
-
- // ask media source for correct GL image format constants
- placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
- mMediaSource->getTextureFormatPrimary(),
- mMediaSource->getTextureFormatType(),
- mMediaSource->getTextureFormatSwapBytes());
-
- placeholder_image->createGLTexture(discard_level, raw);
-
- // MEDIAOPT: set this dynamically on play/stop
- // FIXME
-// placeholder_image->mIsMediaTexture = true;
- mNeedsNewTexture = false;
-
- // If the amount of the texture being drawn by the media goes down in either width or height,
- // recreate the texture to avoid leaving parts of the old image behind.
- mTextureUsedWidth = mMediaSource->getWidth();
- mTextureUsedHeight = mMediaSource->getHeight();
- }
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
+ if (!mMediaSource)
+ {
+ return nullptr; // not ready for updating
+ }
- return placeholder_image;
+ llassert(!mTextureId.isNull());
+ LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture( mTextureId );
+
+ if ( mNeedsNewTexture
+ || media_tex->getUseMipMaps()
+ || (media_tex->getWidth() != mMediaSource->getTextureWidth())
+ || (media_tex->getHeight() != mMediaSource->getTextureHeight())
+ || (mTextureUsedWidth != mMediaSource->getWidth())
+ || (mTextureUsedHeight != mMediaSource->getHeight())
+ )
+ {
+ LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL;
+ LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL;
+
+ int texture_width = mMediaSource->getTextureWidth();
+ int texture_height = mMediaSource->getTextureHeight();
+ int texture_depth = mMediaSource->getTextureDepth();
+
+ // MEDIAOPT: check to see if size actually changed before doing work
+ media_tex->destroyGLTexture();
+ // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work?
+ media_tex->reinit(FALSE); // probably not needed
+
+ // MEDIAOPT: seems insane that we actually have to make an imageraw then
+ // immediately discard it
+ LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth);
+ // Clear the texture to the background color, ignoring alpha.
+ // convert background color channels from [0.0, 1.0] to [0, 255];
+ raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff);
+
+ // ask media source for correct GL image format constants
+ media_tex->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
+ mMediaSource->getTextureFormatPrimary(),
+ mMediaSource->getTextureFormatType(),
+ mMediaSource->getTextureFormatSwapBytes());
+
+ int discard_level = 0;
+ media_tex->createGLTexture(discard_level, raw);
+
+ // MEDIAOPT: set this dynamically on play/stop
+ // FIXME
+// media_tex->mIsMediaTexture = true;
+ mNeedsNewTexture = false;
+
+ // If the amount of the texture being drawn by the media goes down in either width or height,
+ // recreate the texture to avoid leaving parts of the old image behind.
+ mTextureUsedWidth = mMediaSource->getWidth();
+ mTextureUsedHeight = mMediaSource->getHeight();
+ }
+ return media_tex;
}
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 71cec5125d..806692929a 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -197,7 +197,7 @@ public:
U8 media_loop);
~LLViewerMediaImpl();
-
+
// Override inherited version from LLViewerMediaEventEmitter
virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event);
@@ -266,6 +266,8 @@ public:
void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y);
void update();
+ bool preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& data, S32& data_width, S32& data_height, S32& x_pos, S32& y_pos, S32& width, S32& height);
+ void doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync);
void updateImagesMediaStreams();
LLUUID getMediaTextureID() const;
@@ -427,6 +429,7 @@ private:
private:
// a single media url with some data and an impl.
boost::shared_ptr<LLPluginClassMedia> mMediaSource;
+ LLMutex mLock;
F64 mZoomFactor;
LLUUID mTextureId;
bool mMovieImageHasMips;
@@ -446,6 +449,7 @@ private:
S32 mTextureUsedWidth;
S32 mTextureUsedHeight;
bool mSuspendUpdates;
+ bool mTextureUpdatePending = false;
bool mVisible;
ECursorType mLastSetCursor;
EMediaNavState mMediaNavState;
@@ -479,7 +483,7 @@ private:
LLNotificationPtr mNotification;
bool mCleanBrowser; // force the creation of a clean browsing target with full options enabled
static std::vector<std::string> sMimeTypesFailed;
-
+ LLPointer<LLImageRaw> mRawImage; //backing buffer for texture updates
private:
BOOL mIsUpdated ;
std::list< LLVOVolume* > mObjectList ;
@@ -489,7 +493,10 @@ private:
bool mCanceling;
private:
- LLViewerMediaTexture *updatePlaceholderImage();
+ LLViewerMediaTexture *updateMediaImage();
+ LL::WorkQueue::weak_t mMainQueue;
+ LL::WorkQueue::weak_t mTexUpdateQueue;
+
};
#endif // LLVIEWERMEDIA_H
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 3cdef0ebff..5eda75753e 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -787,42 +787,39 @@ void LLViewerOctreeGroup::checkStates()
//occulsion culling functions and classes
//-------------------------------------------------------------------------------------------
std::set<U32> LLOcclusionCullingGroup::sPendingQueries;
-class LLOcclusionQueryPool : public LLGLNamePool
-{
-public:
- LLOcclusionQueryPool()
- {
- }
-
-protected:
- virtual GLuint allocateName()
- {
- GLuint ret = 0;
+static std::queue<GLuint> sFreeQueries;
- glGenQueriesARB(1, &ret);
-
- return ret;
- }
+#define QUERY_POOL_SIZE 1024
- virtual void releaseName(GLuint name)
- {
-#if LL_TRACK_PENDING_OCCLUSION_QUERIES
- LLOcclusionCullingGroup::sPendingQueries.erase(name);
-#endif
- glDeleteQueriesARB(1, &name);
- }
-};
-
-static LLOcclusionQueryPool sQueryPool;
U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName()
{
- return sQueryPool.allocate();
+ LL_PROFILE_ZONE_SCOPED;
+
+ if (sFreeQueries.empty())
+ {
+ //seed 1024 query names into the free query pool
+ GLuint queries[1024];
+ glGenQueriesARB(1024, queries);
+ for (int i = 0; i < 1024; ++i)
+ {
+ sFreeQueries.push(queries[i]);
+ }
+ }
+
+ // pull from pool
+ GLuint ret = sFreeQueries.front();
+ sFreeQueries.pop();
+ return ret;
}
void LLOcclusionCullingGroup::releaseOcclusionQueryObjectName(GLuint name)
{
- sQueryPool.release(name);
+ if (name != 0)
+ {
+ LL_PROFILE_ZONE_SCOPED;
+ sFreeQueries.push(name);
+ }
}
//=====================================
@@ -1243,7 +1240,14 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
//store which frame this query was issued on
mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount;
- glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ {
+ LL_PROFILE_ZONE_NAMED("glBeginQuery");
+
+ //get an occlusion query that hasn't been used in awhile
+ releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = getNewOcclusionQueryObjectName();
+ glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ }
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
llassert(shader);
@@ -1282,7 +1286,10 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
}
}
- glEndQueryARB(mode);
+ {
+ LL_PROFILE_ZONE_NAMED("glEndQuery");
+ glEndQueryARB(mode);
+ }
}
}
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 56370df751..e69b0347f8 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -878,7 +878,7 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const
void LLViewerParcelMgr::render()
{
- if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection"))
+ if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection") && !gDisconnected)
{
// Rendering is done in agent-coordinates, so need to supply
// an appropriate offset to the render code.
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 5fed46f437..e3ac56d0d3 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -515,9 +515,10 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
static LLFrameTimer timer;
+
static S32Megabytes gpu_res = S32Megabytes(S32_MAX);
static S32Megabytes physical_res = S32Megabytes(S32_MAX);
-
+
if (timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second.
{
gpu = gpu_res;
@@ -527,22 +528,11 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p
timer.reset();
{
- if (gGLManager.mHasATIMemInfo)
- {
- S32 meminfo[4];
- glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
- gpu_res = (S32Megabytes)meminfo[0];
-
- //check main memory, only works for windows.
- LLMemory::updateMemoryInfo();
- physical_res = LLMemory::getAvailableMemKB();
- }
- else if (gGLManager.mHasNVXMemInfo)
- {
- S32 free_memory;
- glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
- gpu_res = (S32Megabytes)(free_memory / 1024);
- }
+ gpu_res = (S32Megabytes) LLImageGLThread::getFreeVRAMMegabytes();
+
+ //check main memory, only works for windows.
+ LLMemory::updateMemoryInfo();
+ physical_res = LLMemory::getAvailableMemKB();
gpu = gpu_res;
physical = physical_res;
@@ -1629,7 +1619,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
mNeedsCreateTexture = TRUE;
if (preCreateTexture())
{
- ref();
#if LL_IMAGEGL_THREAD_CHECK
//grab a copy of the raw image data to make sure it isn't modified pending texture creation
U8* data = mRawImage->getData();
@@ -1645,6 +1634,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;
if (mainq)
{
+ ref();
mainq->postTo(
mImageQueue,
// work to be done on LLImageGL worker thread
@@ -1691,7 +1681,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
else
{
gTextureList.mCreateTextureList.insert(this);
- unref();
}
}
}
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 5487f0851e..a54c29a404 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2024,12 +2024,12 @@ LLViewerWindow::LLViewerWindow(const Params& p)
// Init the image list. Must happen after GL is initialized and before the images that
// LLViewerWindow needs are requested.
- LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreaded"));
+ LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreaded"));
gTextureList.init();
LLViewerTextureManager::init() ;
gBumpImageList.init();
- // Create container for all sub-views
+ // Create container for all sub-views
LLView::Params rvp;
rvp.name("root");
rvp.rect(mWindowRectScaled);
@@ -2417,7 +2417,7 @@ void LLViewerWindow::shutdownGL()
LLViewerTextureManager::cleanup() ;
SUBSYSTEM_CLEANUP(LLImageGL) ;
-
+
LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ;
LL_INFOS() << "Cleaning up select manager" << LL_ENDL;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 548dadddb4..6a5cd6eabc 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -127,6 +127,9 @@ const F32 MIN_HOVER_Z = -2.0;
const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f;
const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f;
+// Unlike with 'self' avatar, server doesn't inform viewer about
+// expected attachments so viewer has to wait to see if anything
+// else will arrive
const F32 FIRST_APPEARANCE_CLOUD_MIN_DELAY = 3.f; // seconds
const F32 FIRST_APPEARANCE_CLOUD_MAX_DELAY = 45.f;
@@ -616,6 +619,7 @@ F32 LLVOAvatar::sUnbakedTime = 0.f;
F32 LLVOAvatar::sUnbakedUpdateTime = 0.f;
F32 LLVOAvatar::sGreyTime = 0.f;
F32 LLVOAvatar::sGreyUpdateTime = 0.f;
+LLPointer<LLViewerTexture> LLVOAvatar::sCloudTexture = NULL;
//-----------------------------------------------------------------------------
// Helper functions
@@ -746,7 +750,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mCurrentGesticulationLevel = 0;
- mFirstSeenTimer.reset();
+ mFirstAppearanceMessageTimer.reset();
mRuthTimer.reset();
mRuthDebugTimer.reset();
mDebugExistenceTimer.reset();
@@ -1133,6 +1137,7 @@ void LLVOAvatar::initClass()
LLControlAvatar::sRegionChangedSlot = gAgent.addRegionChangedCallback(&LLControlAvatar::onRegionChanged);
+ sCloudTexture = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c");
}
@@ -2826,7 +2831,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
//override rigged attachments' octree spatial extents with this avatar's bounding box
LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
bool rigged = false;
- if (bridge)
+ if (bridge && !bridge->isDead())
{
//transform avatar bounding box into attachment's coordinate frame
LLVector4a extents[2];
@@ -2843,13 +2848,21 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
attached_object->mDrawable->makeActive();
attached_object->mDrawable->updateXform(TRUE);
- if (!rigged)
+ if (bridge && !bridge->isDead())
{
- if (bridge)
+ if (!rigged)
{
gPipeline.updateMoveNormalAsync(bridge);
}
+ else
+ {
+ //specialized impl of updateMoveNormalAsync just for rigged attachment SpatialBridge
+ bridge->setState(LLDrawable::MOVE_UNDAMPED);
+ bridge->updateMove();
+ bridge->setState(LLDrawable::EARLY_MOVE);
+ }
}
+
attached_object->updateText();
}
}
@@ -3073,8 +3086,7 @@ void LLVOAvatar::idleUpdateLoadingEffect()
particle_parameters.mPartData.mStartColor = LLColor4(1, 1, 1, 0.5f);
particle_parameters.mPartData.mEndColor = LLColor4(1, 1, 1, 0.0f);
particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f;
- LLViewerTexture* cloud = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c");
- particle_parameters.mPartImageID = cloud->getID();
+ particle_parameters.mPartImageID = sCloudTexture->getID();
particle_parameters.mMaxAge = 0.f;
particle_parameters.mPattern = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE;
particle_parameters.mInnerAngle = F_PI;
@@ -6428,6 +6440,16 @@ void LLVOAvatar::updateAttachmentOverrides()
#endif
}
+void LLVOAvatar::notifyAttachmentMeshLoaded()
+{
+ if (!isFullyLoaded())
+ {
+ // We just received mesh or skin info
+ // Reset timer to wait for more potential meshes or changes
+ mFullyLoadedTimer.reset();
+ }
+}
+
//-----------------------------------------------------------------------------
// addAttachmentOverridesForObject
//-----------------------------------------------------------------------------
@@ -8150,7 +8172,7 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
// Note that textures can causes 60s delay on thier own
// so this delay might end up on top of textures' delay
mFirstUseDelaySeconds = llclamp(
- mFirstSeenTimer.getElapsedTimeF32(),
+ mFirstAppearanceMessageTimer.getElapsedTimeF32(),
FIRST_APPEARANCE_CLOUD_MIN_DELAY,
FIRST_APPEARANCE_CLOUD_MAX_DELAY);
@@ -8920,6 +8942,9 @@ void LLVOAvatar::onFirstTEMessageReceived()
mMeshTexturesDirty = TRUE;
gPipeline.markGLRebuild(this);
+
+ mFirstAppearanceMessageTimer.reset();
+ mFullyLoadedTimer.reset();
}
}
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 282d0f6cdd..acebbc1074 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -206,7 +206,7 @@ public:
inline LLJoint* getSkeletonJoint(S32 joint_num) { return mSkeleton[joint_num]; }
inline size_t getSkeletonJointCount() const { return mSkeleton.size(); }
-
+ void notifyAttachmentMeshLoaded();
void addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen = NULL, bool recursive = true);
void removeAttachmentOverridesForObject(const LLUUID& mesh_id);
void removeAttachmentOverridesForObject(LLViewerObject *vo);
@@ -337,7 +337,8 @@ public:
static F32 sLODFactor; // user-settable LOD factor
static F32 sPhysicsLODFactor; // user-settable physics LOD factor
static BOOL sJointDebug; // output total number of joints being touched for each avatar
- static BOOL sDebugAvatarRotation;
+
+ static LLPointer<LLViewerTexture> sCloudTexture;
//--------------------------------------------------------------------
// Region state
@@ -380,7 +381,7 @@ protected:
private:
BOOL mFirstFullyVisible;
F32 mFirstUseDelaySeconds;
- LLFrameTimer mFirstSeenTimer;
+ LLFrameTimer mFirstAppearanceMessageTimer;
BOOL mFullyLoaded;
BOOL mPreviousFullyLoaded;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 4d72dc8776..1625dd5276 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -225,6 +225,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
mNumFaces = 0;
mLODChanged = FALSE;
mSculptChanged = FALSE;
+ mColorChanged = FALSE;
mSpotLightPriority = 0.f;
mMediaImplList.resize(getNumTEs());
@@ -1170,13 +1171,17 @@ void LLVOVolume::notifyMeshLoaded()
mSculptChanged = TRUE;
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
- if (getAvatar() && !isAnimatedObject())
+ LLVOAvatar *av = getAvatar();
+ if (av && !isAnimatedObject())
{
- getAvatar()->addAttachmentOverridesForObject(this);
+ av->addAttachmentOverridesForObject(this);
+ av->notifyAttachmentMeshLoaded();
}
- if (getControlAvatar() && isAnimatedObject())
+ LLControlAvatar *cav = getControlAvatar();
+ if (cav && isAnimatedObject())
{
- getControlAvatar()->addAttachmentOverridesForObject(this);
+ cav->addAttachmentOverridesForObject(this);
+ cav->notifyAttachmentMeshLoaded();
}
updateVisualComplexity();
}
@@ -2027,7 +2032,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
was_regen_faces = lodOrSculptChanged(drawable, compiled);
drawable->setState(LLDrawable::REBUILD_VOLUME);
}
- else if (mSculptChanged || mLODChanged)
+ else if (mSculptChanged || mLODChanged || mColorChanged)
{
compiled = TRUE;
was_regen_faces = lodOrSculptChanged(drawable, compiled);
@@ -2039,7 +2044,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
genBBoxes(FALSE);
}
- else if (mLODChanged || mSculptChanged)
+ else if (mLODChanged || mSculptChanged || mColorChanged)
{
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
compiled = TRUE;
@@ -2071,6 +2076,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
mLODChanged = FALSE;
mSculptChanged = FALSE;
mFaceMappingChanged = FALSE;
+ mColorChanged = FALSE;
return LLViewerObject::updateGeometry(drawable);
}
@@ -2209,6 +2215,7 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color)
if (mDrawable.notNull() && retval)
{
// These should only happen on updates which are not the initial update.
+ mColorChanged = TRUE;
mDrawable->setState(LLDrawable::REBUILD_COLOR);
dirtyMesh();
}
@@ -5139,7 +5146,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
bool rigged = facep->isState(LLFace::RIGGED);
- if (rigged && type != LLRenderPass::PASS_ALPHA)
+ if (rigged)
{
// hacky, should probably clean up -- if this face is rigged, put it in "type + 1"
// See LLRenderPass PASS_foo enum
@@ -5903,23 +5910,25 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
U32 geometryBytes = 0;
+ // generate render batches for static geometry
U32 extra_mask = LLVertexBuffer::MAP_TEXTURE_INDEX;
- geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[0], simple_count[0], FALSE, batch_textures);
- geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[0], fullbright_count[0], FALSE, batch_textures);
- geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[0], alpha_count[0], TRUE, batch_textures);
- geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[0], bump_count[0], FALSE, FALSE);
- geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[0], norm_count[0], FALSE, FALSE);
- geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[0], spec_count[0], FALSE, FALSE);
- geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[0], normspec_count[0], FALSE, FALSE);
-
- extra_mask |= LLVertexBuffer::MAP_WEIGHT4;
- geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[1], simple_count[1], FALSE, batch_textures, TRUE);
- geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[1], fullbright_count[1], FALSE, batch_textures, TRUE);
- geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[1], alpha_count[1], TRUE, batch_textures, TRUE);
- geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[1], bump_count[1], FALSE, TRUE);
- geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[1], norm_count[1], FALSE, TRUE);
- geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[1], spec_count[1], FALSE, TRUE);
- geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[1], normspec_count[1], FALSE, TRUE);
+ BOOL alpha_sort = TRUE;
+ BOOL rigged = FALSE;
+ for (int i = 0; i < 2; ++i) //two sets, static and rigged)
+ {
+ geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[i], simple_count[i], FALSE, batch_textures, rigged);
+ geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[i], fullbright_count[i], FALSE, batch_textures, rigged);
+ geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[i], alpha_count[i], alpha_sort, batch_textures, rigged);
+ geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[i], bump_count[i], FALSE, FALSE, rigged);
+ geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[i], norm_count[i], FALSE, FALSE, rigged);
+ geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[i], spec_count[i], FALSE, FALSE, rigged);
+ geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[i], normspec_count[i], FALSE, FALSE, rigged);
+
+ // for rigged set, add weights and disable alpha sorting (rigged items use depth buffer)
+ extra_mask |= LLVertexBuffer::MAP_WEIGHT4;
+ alpha_sort = FALSE;
+ rigged = TRUE;
+ }
group->mGeometryBytes = geometryBytes;
@@ -5972,8 +5981,9 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
{
LLVOVolume* vobj = drawablep->getVOVolume();
- if (!vobj) continue;
-
+
+ if (!vobj) continue;
+
if (debugLoggingEnabled("AnimatedObjectsLinkset"))
{
if (vobj->isAnimatedObject() && vobj->isRiggedMesh())
@@ -5993,7 +6003,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
}
LLVolume* volume = vobj->getVolume();
- if (!volume) continue;
+ if (!volume) continue;
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index d158044f5d..4cb7a5481c 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -413,6 +413,7 @@ private:
S32 mLOD;
BOOL mLODChanged;
BOOL mSculptChanged;
+ BOOL mColorChanged;
F32 mSpotLightPriority;
LLMatrix4 mRelativeXform;
LLMatrix3 mRelativeXformInvTrans;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index a6fa58f476..a3c971153c 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3828,6 +3828,16 @@ void LLPipeline::postSort(LLCamera& camera)
sCull->pushAlphaGroup(group);
}
}
+
+ LLSpatialGroup::draw_map_t::iterator rigged_alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA_RIGGED);
+
+ if (rigged_alpha != group->mDrawMap.end())
+ { //store rigged alpha groups for LLDrawPoolAlpha prepass (skip distance update, rigged attachments use depth buffer)
+ if (hasRenderType(LLDrawPool::POOL_ALPHA))
+ {
+ sCull->pushRiggedAlphaGroup(group);
+ }
+ }
}
}
@@ -7264,11 +7274,6 @@ void LLPipeline::doResetVertexBuffers(bool forced)
SUBSYSTEM_CLEANUP(LLVertexBuffer);
- //delete all name pool caches
- LLGLNamePool::cleanupPools();
-
-
-
if (LLVertexBuffer::sGLCount > 0)
{
LL_WARNS() << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << LL_ENDL;
@@ -9332,7 +9337,11 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
LLColor3 col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor();
glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
+ // HACK FIX -- pretend underwater camera is the world camera to fix weird visibility artifacts
+ // during distortion render (doesn't break main render because the camera is the same perspective
+ // as world camera and occlusion culling is disabled for this pass)
+ //LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
mWaterDis.bindTarget();
mWaterDis.getViewport(gGLViewport);
@@ -11125,6 +11134,167 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
LLGLState::checkTextureChannels();
}
+static LLTrace::BlockTimerStatHandle FTM_PREVIEW_AVATAR("Preview Avatar");
+
+void LLPipeline::previewAvatar(LLVOAvatar* avatar)
+{
+ LL_RECORD_BLOCK_TIME(FTM_PREVIEW_AVATAR);
+
+ LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
+ gGL.flush();
+ gGL.setSceneBlendType(LLRender::BT_REPLACE);
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ static LLCullResult result;
+ result.clear();
+ grabReferences(result);
+
+ if (!avatar || !avatar->mDrawable)
+ {
+ LL_WARNS_ONCE("AvatarRenderPipeline") << "Avatar is " << (avatar ? "not drawable" : "null") << LL_ENDL;
+ return;
+ }
+ LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " is drawable" << LL_ENDL;
+
+ assertInitialized();
+
+ pushRenderTypeMask();
+
+ {
+ //hide world geometry
+ clearRenderTypeMask(
+ RENDER_TYPE_SKY,
+ RENDER_TYPE_WL_SKY,
+ RENDER_TYPE_GROUND,
+ RENDER_TYPE_TERRAIN,
+ RENDER_TYPE_GRASS,
+ RENDER_TYPE_CONTROL_AV, // Animesh
+ RENDER_TYPE_TREE,
+ RENDER_TYPE_VOIDWATER,
+ RENDER_TYPE_WATER,
+ RENDER_TYPE_PASS_GRASS,
+ RENDER_TYPE_HUD,
+ RENDER_TYPE_PARTICLES,
+ RENDER_TYPE_CLOUDS,
+ RENDER_TYPE_HUD_PARTICLES,
+ END_RENDER_TYPES
+ );
+ }
+
+ S32 occlusion = sUseOcclusion;
+ sUseOcclusion = 0;
+
+ sReflectionRender = !sRenderDeferred;
+
+ sShadowRender = true;
+ sImpostorRender = true; // Likely not needed for previews
+
+ LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
+
+ {
+ markVisible(avatar->mDrawable, *viewer_camera);
+
+ LLVOAvatar::attachment_map_t::iterator iter;
+ for (iter = avatar->mAttachmentPoints.begin();
+ iter != avatar->mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment *attachment = iter->second;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ if (LLViewerObject* attached_object = attachment_iter->get())
+ {
+ markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
+ }
+ }
+ }
+ }
+
+ stateSort(*LLViewerCamera::getInstance(), result);
+
+ LLCamera camera = *viewer_camera;
+
+ F32 old_alpha = LLDrawPoolAvatar::sMinimumAlpha;
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ renderGeomDeferred(camera);
+
+ renderGeomPostDeferred(camera);
+ }
+ else
+ {
+ renderGeom(camera);
+ }
+
+ LLDrawPoolAvatar::sMinimumAlpha = old_alpha;
+
+ { //create alpha mask based on depth buffer
+ if (LLPipeline::sRenderDeferred)
+ {
+ GLuint buff = GL_COLOR_ATTACHMENT0;
+ LL_PROFILER_GPU_ZONEC("gl.DrawBuffersARB", 0x8000FF);
+ glDrawBuffersARB(1, &buff);
+ }
+
+ LLGLDisable blend(GL_BLEND);
+
+ gGL.setColorMask(false, true);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
+
+ gGL.flush();
+
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ static const F32 clip_plane = 0.99999f;
+
+ gDebugProgram.bind();
+
+ gGL.begin(LLRender::QUADS);
+ gGL.vertex3f(-1, -1, clip_plane);
+ gGL.vertex3f(1, -1, clip_plane);
+ gGL.vertex3f(1, 1, clip_plane);
+ gGL.vertex3f(-1, 1, clip_plane);
+ gGL.end();
+ gGL.flush();
+
+ gDebugProgram.unbind();
+
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+ }
+
+ sUseOcclusion = occlusion;
+ sReflectionRender = false;
+ sImpostorRender = false;
+ sShadowRender = false;
+ popRenderTypeMask();
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ gGL.flush();
+}
+
bool LLPipeline::hasRenderBatches(const U32 type) const
{
return sCull->getRenderMapSize(type) > 0;
@@ -11150,6 +11320,16 @@ LLCullResult::sg_iterator LLPipeline::endAlphaGroups()
return sCull->endAlphaGroups();
}
+LLCullResult::sg_iterator LLPipeline::beginRiggedAlphaGroups()
+{
+ return sCull->beginRiggedAlphaGroups();
+}
+
+LLCullResult::sg_iterator LLPipeline::endRiggedAlphaGroups()
+{
+ return sCull->endRiggedAlphaGroups();
+}
+
bool LLPipeline::hasRenderType(const U32 type) const
{
// STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render"
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index b86b68b09d..4946bac701 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -135,6 +135,7 @@ public:
void resetVertexBuffers(LLDrawable* drawable);
void generateImpostor(LLVOAvatar* avatar);
+ void previewAvatar(LLVOAvatar* avatar);
void bindScreenToTexture();
void renderFinalize();
@@ -338,6 +339,8 @@ public:
LLCullResult::drawinfo_iterator endRenderMap(U32 type);
LLCullResult::sg_iterator beginAlphaGroups();
LLCullResult::sg_iterator endAlphaGroups();
+ LLCullResult::sg_iterator beginRiggedAlphaGroups();
+ LLCullResult::sg_iterator endRiggedAlphaGroups();
void addTrianglesDrawn(S32 index_count, U32 render_type = LLRender::TRIANGLES);
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 7be0e0ad85..98f74d321b 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -8821,13 +8821,6 @@ See SecondLife.log for details
type="alert">
Error while requesting mesh upload permissons.
</notification>
-
- <notification
- name="MeshUploadProfilerError"
- icon="alert.tga"
- type="alert">
-Mesh uploader is incompatible with RenderGLCoreProfile, please turn RenderGLCoreProfile off in debug settings and restart the viewer.
- </notification>
<notification
name="RegionCapabilityRequestError"