diff options
41 files changed, 2062 insertions, 468 deletions
| diff --git a/autobuild.xml b/autobuild.xml index 9185b8af22..fa3f7b2743 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1010,9 +1010,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>1bd3214ac23474ea4c869e386970a1be</string> +              <string>c5e9a59c7cf03c88a5cb4ab0a9c21091</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54835/510029/glext-68-darwin64-538965.tar.bz2</string> +              <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/99835/880141/glext-68-darwin64-571812.tar.bz2</string>              </map>              <key>name</key>              <string>darwin64</string> diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index baab09a104..a30f47f1d9 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -31,6 +31,7 @@ include_directories(SYSTEM  set(llrender_SOURCE_FILES      llatmosphere.cpp      llcubemap.cpp +    llcubemaparray.cpp      llfontbitmapcache.cpp      llfontfreetype.cpp      llfontgl.cpp @@ -58,6 +59,7 @@ set(llrender_HEADER_FILES      llatmosphere.h      llcubemap.h +    llcubemaparray.h      llfontgl.h      llfontfreetype.h      llfontbitmapcache.h diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 6d872d0763..473447ad72 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -219,13 +219,17 @@ void LLCubeMap::initEnvironmentMap(const std::vector<LLPointer<LLImageRaw> >& ra  void LLCubeMap::generateMipMaps()  { +    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; +      mImages[0]->setUseMipMaps(TRUE);      mImages[0]->setHasMipMaps(TRUE);      enableTexture(0);      bind(); -    mImages[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); -    glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); -    glGenerateMipmap(GL_TEXTURE_CUBE_MAP); +    mImages[0]->setFilteringOption(LLTexUnit::TFO_BILINEAR); +    { +        LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("cmgmm - glGenerateMipmap"); +        glGenerateMipmap(GL_TEXTURE_CUBE_MAP); +    }      gGL.getTexUnit(0)->disable();      disable();  } diff --git a/indra/llrender/llcubemaparray.cpp b/indra/llrender/llcubemaparray.cpp new file mode 100644 index 0000000000..e4081c1154 --- /dev/null +++ b/indra/llrender/llcubemaparray.cpp @@ -0,0 +1,113 @@ +/**  + * @file llcubemaparray.cpp + * @brief LLCubeMap class implementation + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ +#include "linden_common.h" + +#include "llworkerthread.h" + +#include "llcubemaparray.h" + +#include "v4coloru.h" +#include "v3math.h" +#include "v3dmath.h" +#include "m3math.h" +#include "m4math.h" + +#include "llrender.h" +#include "llglslshader.h" + +#include "llglheaders.h" + +//#pragma optimize("", off) + +// MUST match order of OpenGL face-layers +GLenum LLCubeMapArray::sTargets[6] = +{ +    GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, +    GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, +    GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, +    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, +    GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, +    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB +}; + +LLCubeMapArray::LLCubeMapArray() +	: mTextureStage(0) +{ +	 +} + +LLCubeMapArray::~LLCubeMapArray() +{ +} + +void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count) +{ +    U32 texname = 0; + +    LLImageGL::generateTextures(1, &texname); + +    mImage = new LLImageGL(resolution, resolution, components, TRUE); +    mImage->setTexName(texname); +    mImage->setTarget(sTargets[0], LLTexUnit::TT_CUBE_MAP_ARRAY); + +    mImage->setUseMipMaps(TRUE); +    mImage->setHasMipMaps(TRUE); + +    bind(0); + +    glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY_ARB, 0, GL_RGB, resolution, resolution, count*6, 0, +        GL_RGB, GL_UNSIGNED_BYTE, nullptr); + +    mImage->setAddressMode(LLTexUnit::TAM_CLAMP); + +    mImage->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); + +    glGenerateMipmap(GL_TEXTURE_CUBE_MAP_ARRAY_ARB); + +    unbind(); +} + +void LLCubeMapArray::bind(S32 stage) +{ +    mTextureStage = stage; +    gGL.getTexUnit(stage)->bindManual(LLTexUnit::TT_CUBE_MAP_ARRAY, getGLName(), TRUE); +} + +void LLCubeMapArray::unbind() +{ +    gGL.getTexUnit(mTextureStage)->unbind(LLTexUnit::TT_CUBE_MAP_ARRAY); +    mTextureStage = -1; +} + +GLuint LLCubeMapArray::getGLName() +{ +	return mImage->getTexName(); +} + +void LLCubeMapArray::destroyGL() +{ +    mImage = NULL; +} diff --git a/indra/llrender/llcubemaparray.h b/indra/llrender/llcubemaparray.h new file mode 100644 index 0000000000..52e21f1dda --- /dev/null +++ b/indra/llrender/llcubemaparray.h @@ -0,0 +1,60 @@ +/**  + * @file llcubemaparray.h + * @brief LLCubeMap class definition + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#pragma once + +#include "llgl.h" + +#include <vector> + +class LLVector3; + +// Environment map hack! +class LLCubeMapArray : public LLRefCount +{ +public: +	LLCubeMapArray(); + +    static GLenum sTargets[6]; + +    // allocate a cube map array  +    // res - resolution of each cube face +    // components - number of components per pixel +    // count - number of cube maps in the array +    void allocate(U32 res, U32 components, U32 count); +	void bind(S32 stage); +    void unbind(); +	 +	GLuint getGLName(); + +	void destroyGL(); + +protected: +	friend class LLTexUnit; +	~LLCubeMapArray(); +	LLPointer<LLImageGL> mImage; +	S32 mTextureStage; +}; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 639d1fba32..6023796f7c 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -89,9 +89,10 @@ void APIENTRY gl_debug_callback(GLenum source,  	if (gGLDebugLoggingEnabled)  	{ -        if (severity != GL_DEBUG_SEVERITY_HIGH_ARB && -            severity != GL_DEBUG_SEVERITY_MEDIUM_ARB && -            severity != GL_DEBUG_SEVERITY_LOW_ARB) +        if (severity != GL_DEBUG_SEVERITY_HIGH_ARB // && +            //severity != GL_DEBUG_SEVERITY_MEDIUM_ARB && +            //severity != GL_DEBUG_SEVERITY_LOW_ARB +            )          { //suppress out-of-spec messages sent by nvidia driver (mostly vertexbuffer hints)              return;          } @@ -316,6 +317,15 @@ PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL;  PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL;  PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer = NULL; +// GL_ARB_uniform_buffer_object +PFNGLGETUNIFORMINDICESPROC glGetUniformIndices = NULL; +PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv = NULL; +PFNGLGETACTIVEUNIFORMNAMEPROC glGetActiveUniformName = NULL; +PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex = NULL; +PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv = NULL; +PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glGetActiveUniformBlockName = NULL; +PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding = NULL; +  #if LL_WINDOWS  PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;  #endif @@ -436,6 +446,7 @@ LLGLManager::LLGLManager() :  	mHasTextureRectangle(FALSE),  	mHasTextureMultisample(FALSE),  	mHasTransformFeedback(FALSE), +    mHasUniformBufferObject(FALSE),  	mMaxSampleMaskWords(0),  	mMaxColorTextureSamples(0),  	mMaxDepthTextureSamples(0), @@ -1054,6 +1065,7 @@ void LLGLManager::initExtensions()  	mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts);  	mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);  	mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE; +    mHasUniformBufferObject = ExtensionExists("GL_ARB_uniform_buffer_object", gGLHExts.mSysExts);  #if !LL_DARWIN  	mHasPointParameters = ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);  #endif @@ -1286,6 +1298,10 @@ void LLGLManager::initExtensions()  		mGLMaxVertexRange = 0;  		mGLMaxIndexRange = 0;  	} + +    // same with glTexImage3D et al +    glTexImage3D = (PFNGLTEXIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3D"); +    glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyTexSubImage3D");  #endif // !LL_LINUX || LL_LINUX_NV_GL_HEADERS  #if LL_LINUX_NV_GL_HEADERS  	// nvidia headers are critically different from mesa-esque @@ -1319,6 +1335,17 @@ void LLGLManager::initExtensions()  		glPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvARB");  	} +    if (mHasUniformBufferObject) +    { +       glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)GLH_EXT_GET_PROC_ADDRESS("glGetUniformIndices"); +       glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetUniformIndices"); +       glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformName"); +       glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)GLH_EXT_GET_PROC_ADDRESS("glGetUniformBlockIndex"); +       glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformBlockiv"); +       glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformBlockName"); +       glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)GLH_EXT_GET_PROC_ADDRESS("glUniformBlockBinding"); +    } +      // Assume shader capabilities      glDeleteObjectARB         = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteObjectARB");      glGetHandleARB            = (PFNGLGETHANDLEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetHandleARB"); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 52338364e6..eea53ed01e 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -104,6 +104,7 @@ public:  	BOOL mHasTextureRectangle;  	BOOL mHasTextureMultisample;  	BOOL mHasTransformFeedback; +    BOOL mHasUniformBufferObject;  	S32 mMaxSampleMaskWords;  	S32 mMaxColorTextureSamples;  	S32 mMaxDepthTextureSamples; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 3d93cc0762..aa429505c1 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -564,6 +564,15 @@ extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;  extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;  extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB; +// GL_ARB_uniform_buffer_object +extern PFNGLGETUNIFORMINDICESPROC glGetUniformIndices; +extern PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv; +extern PFNGLGETACTIVEUNIFORMNAMEPROC glGetActiveUniformName; +extern PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex; +extern PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv; +extern PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glGetActiveUniformBlockName; +extern PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding; +  #elif LL_DARWIN  //----------------------------------------------------------------------------  // LL_DARWIN diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index a52dcd5aa1..0212c605c3 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -780,7 +780,8 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type, GLint      LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;      if ((type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) || -        type == GL_SAMPLER_2D_MULTISAMPLE) +        type == GL_SAMPLER_2D_MULTISAMPLE || +        type == GL_SAMPLER_CUBE_MAP_ARRAY_ARB)      {   //this here is a texture          GLint ret = mActiveTextureChannels;          if (size == 1) @@ -1289,6 +1290,30 @@ void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v)      }  } +void LLGLSLShader::uniform4iv(U32 index, U32 count, const GLint* v) +{ +    if (mProgramObject) +    { +        if (mUniform.size() <= index) +        { +            LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL; +            return; +        } + +        if (mUniform[index] >= 0) +        { +            const auto& iter = mValue.find(mUniform[index]); +            LLVector4 vec(v[0], v[1], v[2], v[3]); +            if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) +            { +                glUniform1ivARB(mUniform[index], count, v); +                mValue[mUniform[index]] = vec; +            } +        } +    } +} + +  void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v)  {      if (mProgramObject) @@ -1526,6 +1551,40 @@ void LLGLSLShader::uniform1i(const LLStaticHashedString& uniform, GLint v)      }  } +void LLGLSLShader::uniform1iv(const LLStaticHashedString& uniform, U32 count, const GLint* v) +{ +    GLint location = getUniformLocation(uniform); + +    if (location >= 0) +    { +        LLVector4 vec(v[0], 0, 0, 0); +        const auto& iter = mValue.find(location); +        if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) +        { +            LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; +            glUniform1ivARB(location, count, v); +            mValue[location] = vec; +        } +    } +} + +void LLGLSLShader::uniform4iv(const LLStaticHashedString& uniform, U32 count, const GLint* v) +{ +    GLint location = getUniformLocation(uniform); + +    if (location >= 0) +    { +        LLVector4 vec(v[0], v[1], v[2], v[3]); +        const auto& iter = mValue.find(location); +        if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1) +        { +            LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; +            glUniform4ivARB(location, count, v); +            mValue[location] = vec; +        } +    } +} +  void LLGLSLShader::uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j)  {      GLint location = getUniformLocation(uniform); diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 7d6b341d3d..fe0aaae467 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -178,6 +178,7 @@ public:  	void uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z);  	void uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);  	void uniform1iv(U32 index, U32 count, const GLint* i); +    void uniform4iv(U32 index, U32 count, const GLint* i);  	void uniform1fv(U32 index, U32 count, const GLfloat* v);  	void uniform2fv(U32 index, U32 count, const GLfloat* v);  	void uniform3fv(U32 index, U32 count, const GLfloat* v); @@ -188,6 +189,8 @@ public:  	void uniformMatrix3x4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v);  	void uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v);  	void uniform1i(const LLStaticHashedString& uniform, GLint i); +    void uniform1iv(const LLStaticHashedString& uniform, U32 count, const GLint* v); +    void uniform4iv(const LLStaticHashedString& uniform, U32 count, const GLint* v);  	void uniform1f(const LLStaticHashedString& uniform, GLfloat v);  	void uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y);  	void uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 9bd3a0a6b0..f2da859e23 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1688,26 +1688,38 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name)          LL_PROFILE_ZONE_NAMED("cglt - sync");          if (gGLManager.mHasSync)          { -            // post a sync to the main thread (will execute before tex name swap lambda below) -            // glFlush calls here are partly superstitious and partly backed by observation -            // on AMD hardware -            glFlush(); -            auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -            glFlush(); -            LL::WorkQueue::postMaybe( -                mMainQueue, -                [=]() -                { -                    LL_PROFILE_ZONE_NAMED("cglt - wait sync"); -                    { -                        LL_PROFILE_ZONE_NAMED("glWaitSync"); -                        glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); -                    } +            if (gGLManager.mIsNVIDIA) +            { +                // wait for texture upload to finish before notifying main thread +                // upload is complete +                auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +                glFlush(); +                glClientWaitSync(sync, 0, GL_TIMEOUT_IGNORED); +                glDeleteSync(sync); +            } +            else +            { +                // post a sync to the main thread (will execute before tex name swap lambda below) +                // glFlush calls here are partly superstitious and partly backed by observation +                // on AMD hardware +                glFlush(); +                auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +                glFlush(); +                LL::WorkQueue::postMaybe( +                    mMainQueue, +                    [=]()                      { -                        LL_PROFILE_ZONE_NAMED("glDeleteSync"); -                        glDeleteSync(sync); -                    } -                }); +                        LL_PROFILE_ZONE_NAMED("cglt - wait sync"); +                        { +                            LL_PROFILE_ZONE_NAMED("glWaitSync"); +                            glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); +                        } +                        { +                            LL_PROFILE_ZONE_NAMED("glDeleteSync"); +                            glDeleteSync(sync); +                        } +                    }); +            }          }          else          { @@ -1726,6 +1738,7 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name)          });  } +  void LLImageGL::syncTexName(LLGLuint texname)  {      if (texname != 0) diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index a03a27cf94..3adb47f493 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -71,6 +71,7 @@ static const GLenum sGLTextureType[] =  	GL_TEXTURE_2D,  	GL_TEXTURE_RECTANGLE_ARB,  	GL_TEXTURE_CUBE_MAP_ARB, +    GL_TEXTURE_CUBE_MAP_ARRAY_ARB,  	GL_TEXTURE_2D_MULTISAMPLE,      GL_TEXTURE_3D  }; @@ -888,6 +889,9 @@ void LLRender::init()      glCullFace(GL_BACK); +    // necessary for reflection maps +    glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); +  	if (sGLCoreProfile && !LLVertexBuffer::sUseVAO)  	{ //bind a dummy vertex array object so we're core profile compliant  #ifdef GL_ARB_vertex_array_object diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index e2489876e4..095ed400f4 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -52,7 +52,7 @@ class LLTexture ;  #define LL_MATRIX_STACK_DEPTH 32 -class LLTexUnit +class LLTexUnit   {  	friend class LLRender;  public: @@ -63,6 +63,7 @@ public:  		TT_TEXTURE = 0,			// Standard 2D Texture  		TT_RECT_TEXTURE,	    // Non power of 2 texture  		TT_CUBE_MAP,		    // 6-sided cube map texture +        TT_CUBE_MAP_ARRAY,	    // Array of cube maps  		TT_MULTISAMPLE_TEXTURE, // see GL_ARB_texture_multisample          TT_TEXTURE_3D,          // standard 3D Texture  		TT_NONE, 		        // No texture type is currently enabled         diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index cd7ec478bb..8e8f44e99b 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -712,8 +712,15 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade  	{            if (major_version >= 4)          { -            //set version to 400 -			shader_code_text[shader_code_count++] = strdup("#version 400\n"); +            //set version to 400 or 420 +            if (minor_version >= 20) +            { +                shader_code_text[shader_code_count++] = strdup("#version 420\n"); +            } +            else +            { +                shader_code_text[shader_code_count++] = strdup("#version 400\n"); +            }          }          else if (major_version == 3)          { @@ -1155,7 +1162,7 @@ void LLShaderMgr::initAttribsAndUniforms()  	mReservedUniforms.push_back("bumpMap");      mReservedUniforms.push_back("bumpMap2");  	mReservedUniforms.push_back("environmentMap"); -    mReservedUniforms.push_back("reflectionMap"); +    mReservedUniforms.push_back("reflectionProbes");  	mReservedUniforms.push_back("cloud_noise_texture");      mReservedUniforms.push_back("cloud_noise_texture_next");  	mReservedUniforms.push_back("fullbright"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 7ca4862ed9..663ba28b6d 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -80,7 +80,7 @@ public:          BUMP_MAP,                           //  "bumpMap"          BUMP_MAP2,                          //  "bumpMap2"          ENVIRONMENT_MAP,                    //  "environmentMap" -        REFLECTION_MAP,                     //  "reflectionMap" +        REFLECTION_PROBES,                     //  "reflectionProbes"          CLOUD_NOISE_MAP,                    //  "cloud_noise_texture"          CLOUD_NOISE_MAP_NEXT,               //  "cloud_noise_texture_next"          FULLBRIGHT,                         //  "fullbright" diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 20b708fe99..284b779be3 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10269,6 +10269,17 @@        <integer>2</integer>      </map> +  <key>RenderReflectionProbeDrawDistance</key> +  <map> +    <key>Comment</key> +    <string>Camera far clip to use when updating reflection probes.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>F32</string> +    <key>Value</key> +    <real>64</real> +  </map>      <key>RenderReflectionRes</key>      <map>        <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl index 23adbded5e..73c125bbdc 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl @@ -29,8 +29,6 @@ uniform sampler2DRect   depthMap;  uniform float ssao_radius;  uniform float ssao_max_radius; -uniform float ssao_factor; -uniform float ssao_factor_inv;  uniform mat4 inv_proj;  uniform vec2 screen_res; @@ -83,14 +81,14 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen)  {      float ret = 1.0;      vec3 pos_world = pos.xyz; -    vec2 noise_reflect = texture2D(noiseMap, pos_screen.xy/128.0).xy; +          float angle_hidden = 0.0;      float points = 0; -    float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); -          // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) +    float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); +    vec2 noise_reflect = texture2D(noiseMap, pos_screen.xy/128.0).xy;      for (int i = 0; i < 8; i++)      {          vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect); @@ -105,14 +103,14 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen)          //(k should vary inversely with # of samples, but this is taken care of later)          float funky_val = (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) ? 1.0 : 0.0; -        angle_hidden = angle_hidden + funky_val * min(1.0/dist2, ssao_factor_inv); +        angle_hidden = angle_hidden + funky_val * min(1.0/dist2, 1.0);          // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion"           float diffz_val = (diff.z > -1.0) ? 1.0 : 0.0;          points = points + diffz_val;      } -         -    angle_hidden = min(ssao_factor*angle_hidden/points, 1.0); + +    angle_hidden = min(angle_hidden/points, 1.0);      float points_val = (points > 0.0) ? 1.0 : 0.0;      ret = (1.0 - (points_val * angle_hidden)); diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 596d0274af..fa3634f3b6 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -69,36 +69,47 @@ void main()      tc_mod *= 2.0;      tc += ( (tc_mod - 0.5) * kern[1].z * dlt * 0.5 ); -    for (int i = 1; i < 4; i++) +    // TODO: move this to kern instead of building kernel per pixel +    vec3 k[7]; +    k[0] = kern[0]; +    k[2] = kern[1]; +    k[4] = kern[2]; +    k[6] = kern[3]; + +    k[1] = (k[0]+k[2])*0.5f; +    k[3] = (k[2]+k[4])*0.5f; +    k[5] = (k[4]+k[6])*0.5f; +     +    for (int i = 1; i < 7; i++)      { -        vec2 samptc = tc + kern[i].z*dlt; +        vec2 samptc = tc + k[i].z*dlt*2.0;          vec3 samppos = getPosition(samptc).xyz;           float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane          if (d*d <= pointplanedist_tolerance_pow2)          { -            col += texture2DRect(lightMap, samptc)*kern[i].xyxx; -            defined_weight += kern[i].xy; +            col += texture2DRect(lightMap, samptc)*k[i].xyxx; +            defined_weight += k[i].xy;          }      } -    for (int i = 1; i < 4; i++) +    for (int i = 1; i < 7; i++)      { -        vec2 samptc = tc - kern[i].z*dlt; +        vec2 samptc = tc - k[i].z*dlt*2.0;          vec3 samppos = getPosition(samptc).xyz;           float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane          if (d*d <= pointplanedist_tolerance_pow2)          { -            col += texture2DRect(lightMap, samptc)*kern[i].xyxx; -            defined_weight += kern[i].xy; +            col += texture2DRect(lightMap, samptc)*k[i].xyxx; +            defined_weight += k[i].xy;          }      }      col /= defined_weight.xyxx; -    col.y *= col.y; +    //col.y *= max(col.y, 0.75);      frag_color = col; diff --git a/indra/newview/app_settings/shaders/class1/interface/reflectionmipF.glsl b/indra/newview/app_settings/shaders/class1/interface/reflectionmipF.glsl new file mode 100644 index 0000000000..ea687aab4f --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/reflectionmipF.glsl @@ -0,0 +1,75 @@ +/**  + * @file reflectionmipF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ +  +#extension GL_ARB_texture_rectangle : enable + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2DRect screenMap; + +VARYING vec2 vary_texcoord0; + +void main()  +{ +    float w[9]; + +    float c = 1.0/16.0;  //corner weight +    float e = 1.0/8.0; //edge weight +    float m = 1.0/4.0; //middle weight + +    //float wsum = c*4+e*4+m; + +    w[0] = c;   w[1] = e;    w[2] = c; +    w[3] = e;    w[4] = m;     w[5] = e; +    w[6] = c;   w[7] = e;    w[8] = c; +     +    vec2 tc[9]; + +    float ed = 1; +    float cd = 1; + + +    tc[0] = vec2(-cd, cd);    tc[1] = vec2(0, ed);    tc[2] = vec2(cd, cd); +    tc[3] = vec2(-ed, 0);    tc[4] = vec2(0, 0);    tc[5] = vec2(ed, 0); +    tc[6] = vec2(-cd, -cd);    tc[7] = vec2(0, -ed);   tc[8] = vec2(cd, -1); + +    vec3 color = vec3(0,0,0); + +    for (int i = 0; i < 9; ++i) +    { +        color += texture2DRect(screenMap, vary_texcoord0.xy+tc[i]).rgb * w[i]; +        //color += texture2DRect(screenMap, vary_texcoord0.xy+tc[i]*2.0).rgb * w[i]*0.5; +    } + +    //color /= wsum; + +    frag_color = vec4(color, 1.0); +} diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl index 5bb64e18a7..3a1287e910 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl @@ -26,9 +26,10 @@  #extension GL_ARB_texture_rectangle : enable  #extension GL_ARB_shader_texture_lod : enable -/*[EXTRA_CODE_HERE]*/ +#define FLT_MAX 3.402823466e+38 -#define REFMAP_COUNT 8 +#define REFMAP_COUNT 256 +#define REF_SAMPLE_COUNT 64 //maximum number of samples to consider  #ifdef DEFINE_GL_FRAGCOLOR  out vec4 frag_color; @@ -42,12 +43,26 @@ uniform sampler2DRect normalMap;  uniform sampler2DRect lightMap;  uniform sampler2DRect depthMap;  uniform samplerCube   environmentMap; -uniform samplerCube   reflectionMap[REFMAP_COUNT]; +uniform samplerCubeArray   reflectionProbes;  uniform sampler2D     lightFunc; -uniform int refmapCount; - -uniform vec3 refOrigin[REFMAP_COUNT]; +layout (std140, binding = 1) uniform ReflectionProbes +{ +    // list of sphere based reflection probes sorted by distance to camera (closest first) +    vec4 refSphere[REFMAP_COUNT]; +    // index  of cube map in reflectionProbes for a corresponding reflection probe +    // e.g. cube map channel of refSphere[2] is stored in refIndex[2] +    // refIndex.x - cubemap channel in reflectionProbes +    // refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index) +    // refIndex.z - number of neighbors +    ivec4 refIndex[REFMAP_COUNT]; + +    // neighbor list data (refSphere indices, not cubemap array layer) +    ivec4 refNeighbor[1024]; + +    // number of reflection probes present in refSphere +    int refmapCount; +};  uniform float blur_size;  uniform float blur_fidelity; @@ -80,7 +95,116 @@ vec3 srgb_to_linear(vec3 c);  vec4 applyWaterFogView(vec3 pos, vec4 color);  #endif +// list of probeIndexes shader will actually use after "getRefIndex" is called +// (stores refIndex/refSphere indices, NOT rerflectionProbes layer) +int probeIndex[REF_SAMPLE_COUNT]; + +// number of probes stored in probeIndex +int probeInfluences = 0; + + +// return true if probe at index i influences position pos +bool shouldSampleProbe(int i, vec3 pos) +{ +    vec3 delta = pos.xyz - refSphere[i].xyz; +    float d = dot(delta, delta); +    float r2 = refSphere[i].w; +    r2 *= r2; +    return d < r2; +} + +// populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT +// overall algorithm --  +void getRefIndex(vec3 pos) +{ +    // TODO: make some sort of structure that reduces the number of distance checks +    for (int i = 0; i < refmapCount; ++i) +    { +        // found an influencing probe +        if (shouldSampleProbe(i, pos)) +        { +            probeIndex[probeInfluences] = i; +            ++probeInfluences; + +            int neighborIdx = refIndex[i].y; +            if (neighborIdx != -1) +            { +                int neighborCount = min(refIndex[i].z, REF_SAMPLE_COUNT-1); + +                int count = 0; +                while (count < neighborCount) +                { +                    // check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index) + +                    int idx = refNeighbor[neighborIdx].x; +                    if (shouldSampleProbe(idx, pos)) +                    { +                        probeIndex[probeInfluences++] = idx; +                        if (probeInfluences == REF_SAMPLE_COUNT) +                        { +                            return; +                        } +                    } +                    count++; +                    if (count == neighborCount) +                    { +                        return; +                    } + +                    idx = refNeighbor[neighborIdx].y; +                    if (shouldSampleProbe(idx, pos)) +                    { +                        probeIndex[probeInfluences++] = idx; +                        if (probeInfluences == REF_SAMPLE_COUNT) +                        { +                            return; +                        } +                    } +                    count++; +                    if (count == neighborCount) +                    { +                        return; +                    } + +                    idx = refNeighbor[neighborIdx].z; +                    if (shouldSampleProbe(idx, pos)) +                    { +                        probeIndex[probeInfluences++] = idx; +                        if (probeInfluences == REF_SAMPLE_COUNT) +                        { +                            return; +                        } +                    } +                    count++; +                    if (count == neighborCount) +                    { +                        return; +                    } + +                    idx = refNeighbor[neighborIdx].w; +                    if (shouldSampleProbe(idx, pos)) +                    { +                        probeIndex[probeInfluences++] = idx; +                        if (probeInfluences == REF_SAMPLE_COUNT) +                        { +                            return; +                        } +                    } +                    count++; +                    if (count == neighborCount) +                    { +                        return; +                    } + +                    ++neighborIdx; +                } + +                return; +            } +        } +    } +}  // from https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection @@ -120,13 +244,10 @@ bool intersect(const Ray &ray) const  } */  // adapted -- assume that origin is inside sphere, return distance from origin to edge of sphere -float sphereIntersect(vec3 origin, vec3 dir, vec4 sph ) +float sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)  {           float t0, t1; // solutions for t if the ray intersects  -        vec3 center = sph.xyz; -        float radius2 = sph.w * sph.w; -          vec3 L = center - origin;           float tca = dot(L,dir); @@ -139,33 +260,78 @@ float sphereIntersect(vec3 origin, vec3 dir, vec4 sph )          return t1;   }  +// Tap a sphere based reflection probe +// pos - position of pixel +// dir - pixel normal +// lod - which mip to bias towards (lower is higher res, sharper reflections) +// c - center of probe +// r2 - radius of probe squared +// i - index of probe  +// vi - point at which reflection vector struck the influence volume, in clip space +vec3 tapRefMap(vec3 pos, vec3 dir, float lod, vec3 c, float r2, int i, out vec3 vi) +{ +    //lod = max(lod, 1); +// parallax adjustment +    float d = sphereIntersect(pos, dir, c, r2); + +    { +        vec3 v = pos + dir * d; +        vi = v; +        v -= c.xyz; +        v = env_mat * v; + +        float min_lod = textureQueryLod(reflectionProbes,v).y; // lower is higher res +        return textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), max(min_lod, lod)).rgb; +        //return texture(reflectionProbes, vec4(v.xyz, refIndex[i].x)).rgb; +    } +} +  vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)  {      float wsum = 0.0; -      vec3 col = vec3(0,0,0); +    float vd2 = dot(pos,pos); // view distance squared -    for (int i = 0; i < refmapCount; ++i) -    //int i = 0; +    for (int idx = 0; idx < probeInfluences; ++idx)      { -        float r = 16.0; -        vec3 delta = pos.xyz-refOrigin[i].xyz; -        if (length(delta) < r) +        int i = probeIndex[idx]; +        float r = refSphere[i].w; // radius of sphere volume +        float rr = r*r; // radius squred +        float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down) +        vec3 delta = pos.xyz-refSphere[i].xyz; +        float d2 = dot(delta,delta); +        float r2 = r1*r1;  +                  { -            float w = 1.0/max(dot(delta, delta), r); -            w *= w; -            w *= w; +            vec3 vi; +            vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i, vi); +             +            float w = 1.0/d2; -            // parallax adjustment -            float d = sphereIntersect(pos, dir, vec4(refOrigin[i].xyz, r)); +            float atten = 1.0-max(d2-r2, 0.0)/(rr-r2); +            w *= atten; -            { -                vec3 v = pos + dir * d; -                v -= refOrigin[i].xyz; -                v = env_mat * v; +            col += refcol*w; +             +            wsum += w; +        } +    } -                float min_lod = textureQueryLod(reflectionMap[i],v).y; // lower is higher res -                col += textureLod(reflectionMap[i], v, max(min_lod, lod)).rgb*w; +    if (probeInfluences <= 1) +    { //edge-of-scene probe or no probe influence, mix in with embiggened version of probes closest to camera  +        for (int idx = 0; idx < 8; ++idx) +        { +            int i = idx; +            vec3 delta = pos.xyz-refSphere[i].xyz; +            float d2 = dot(delta,delta); +             +            { +                vec3 vi; +                vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i, vi); +                 +                float w = 1.0/d2; +                w *= w; +                col += refcol*w;                  wsum += w;              }          } @@ -175,13 +341,6 @@ vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)      {          col *= 1.0/wsum;      } -    else -    { -        // this pixel not covered by a probe, fallback to "full scene" environment map -        vec3 v = env_mat * dir; -        float min_lod = textureQueryLod(environmentMap, v).y; // lower is higher res -        col = textureLod(environmentMap, v, max(min_lod, lod)).rgb; -    }      return col;  } @@ -202,13 +361,26 @@ vec3 sampleAmbient(vec3 pos, vec3 dir, float lod)      col *= 0.333333; -    return col*0.6; // fudge darker +    return col*0.8; // fudge darker  } +// brighten a color so that at least one component is 1 +vec3 brighten(vec3 c) +{ +    float m = max(max(c.r, c.g), c.b); + +    if (m == 0) +    { +        return vec3(1,1,1); +    } + +    return c * 1.0/m; +} +  void main()  { -    float reflection_lods = 11; // TODO -- base this on resolution of reflection map instead of hard coding +    float reflection_lods = 8; // TODO -- base this on resolution of reflection map instead of hard coding      vec2  tc           = vary_fragcoord.xy;      float depth        = texture2DRect(depthMap, tc.xy).r; @@ -238,14 +410,16 @@ void main()      vec3 amblit;      vec3 additive;      vec3 atten; + +    getRefIndex(pos.xyz); +      calcAtmosphericVars(pos.xyz, light_dir, ambocc, sunlit, amblit, additive, atten, true);      //vec3 amb_vec = env_mat * norm.xyz; -    vec3 ambenv = sampleAmbient(pos.xyz, norm.xyz, reflection_lods-1); -    amblit = mix(ambenv, amblit, amblit); -    color.rgb = amblit; -     +    vec3 ambenv = sampleAmbient(pos.xyz, norm.xyz, reflection_lods); +    amblit = max(ambenv, amblit); +    color.rgb = amblit*ambocc;      //float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);      //ambient *= 0.5; @@ -255,6 +429,7 @@ void main()      vec3 sun_contrib = min(da, scol) * sunlit;      color.rgb += sun_contrib; +    color.rgb = min(color.rgb, vec3(1,1,1));      color.rgb *= diffuse.rgb;      vec3 refnormpersp = reflect(pos.xyz, norm.xyz); @@ -274,26 +449,23 @@ void main()          float lod = (1.0-spec.a)*reflection_lods;          vec3 reflected_color = sampleRefMap(pos.xyz, normalize(refnormpersp), lod); -        reflected_color *= 0.5; // fudge darker, not sure where there's a multiply by two and it's late +        reflected_color *= 0.35; // fudge darker          float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz); -        fresnel += spec.a; -        fresnel *= fresnel; -        //fresnel *= spec.a; +        float minf = spec.a * 0.1; +        fresnel = fresnel * (1.0-minf) + minf;          reflected_color *= spec.rgb*min(fresnel, 1.0); -        //reflected_color = srgb_to_linear(reflected_color); -        vec3 mixer = clamp(color.rgb + vec3(1,1,1) - spec.rgb, vec3(0,0,0), vec3(1,1,1)); -        color.rgb = mix(reflected_color, color, mixer); +        color.rgb += reflected_color;      }      color.rgb = mix(color.rgb, diffuse.rgb, diffuse.a);      if (envIntensity > 0.0)      {  // add environmentmap -        vec3 reflected_color = sampleRefMap(pos.xyz, normalize(refnormpersp), 0.0); +        vec3 reflected_color = sampleRefMap(pos.xyz, normalize(refnormpersp), 0.0)*0.5; //fudge darker          float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz);          fresnel *= fresnel; -        fresnel = fresnel * 0.95 + 0.05; -        reflected_color *= fresnel; +        fresnel = min(fresnel+envIntensity, 1.0); +        reflected_color *= (envIntensity*fresnel)*brighten(spec.rgb);          color = mix(color.rgb, reflected_color, envIntensity);      } @@ -311,5 +483,7 @@ void main()      // convert to linear as fullscreen lights need to sum in linear colorspace      // and will be gamma (re)corrected downstream... +    //color = vec3(ambocc); +    //color = ambenv;          frag_color.rgb = srgb_to_linear(color.rgb);  } diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 84a41113be..8d02bec53e 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -1188,12 +1188,18 @@ void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y)  static LLTrace::BlockTimerStatHandle FTM_UPDATE_CAMERA("Camera"); +extern BOOL gCubeSnapshot; +  //-----------------------------------------------------------------------------  // updateCamera()  //-----------------------------------------------------------------------------  void LLAgentCamera::updateCamera()  {  	LL_RECORD_BLOCK_TIME(FTM_UPDATE_CAMERA); +    if (gCubeSnapshot) +    { +        return; +    }  	// - changed camera_skyward to the new global "mCameraUpVector"  	mCameraUpVector = LLVector3::z_axis; diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index eebd89f77f..47330debd3 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -129,6 +129,8 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d      }  } +extern BOOL gCubeSnapshot; +  void LLDrawPoolAlpha::renderPostDeferred(S32 pass)   {       LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; @@ -155,7 +157,7 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)      forwardRender();      // final pass, render to depth for depth of field effects -    if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField")) +    if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField") && !gCubeSnapshot)      {           //update depth buffer sampler          gPipeline.mScreen.flush(); diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 2892fc6f9f..0df0137b7a 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -735,6 +735,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass)  void LLDrawPoolBump::renderPostDeferred(S32 pass)  { +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL      for (int i = 0; i < 2; ++i)      { // two passes -- static and rigged          mRigged = (i == 1); diff --git a/indra/newview/lldrawpoolpbropaque.cpp b/indra/newview/lldrawpoolpbropaque.cpp index 64850424f4..2478aa0cff 100644 --- a/indra/newview/lldrawpoolpbropaque.cpp +++ b/indra/newview/lldrawpoolpbropaque.cpp @@ -87,6 +87,6 @@ void LLDrawPoolPBROpaque::renderDeferred(S32 pass)      // TODO: handle under water?      // if (LLPipeline::sUnderWaterRender)      // PASS_SIMPLE or PASS_MATERIAL -    pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); +    //pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);  } diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp index b75dba877e..0cf2f22822 100644 --- a/indra/newview/llreflectionmap.cpp +++ b/indra/newview/llreflectionmap.cpp @@ -29,36 +29,183 @@  #include "llreflectionmap.h"  #include "pipeline.h"  #include "llviewerwindow.h" +#include "llviewerregion.h" + +extern F32SecondsImplicit gFrameTimeSeconds;  LLReflectionMap::LLReflectionMap()  { +    mLastUpdateTime = gFrameTimeSeconds;  } -void LLReflectionMap::update(const LLVector3& origin, U32 resolution) +void LLReflectionMap::update(U32 resolution, U32 face)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; +    mLastUpdateTime = gFrameTimeSeconds; +    llassert(mCubeArray.notNull()); +    llassert(mCubeIndex != -1);      llassert(LLPipeline::sRenderDeferred); - -    // make sure resolution is < gPipeline.mDeferredScreen.getWidth() - +     +    // make sure we don't walk off the edge of the render target      while (resolution > gPipeline.mDeferredScreen.getWidth() ||          resolution > gPipeline.mDeferredScreen.getHeight())      {          resolution /= 2;      } +    gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face); +} -    if (resolution == 0) -    { -        return; +bool LLReflectionMap::shouldUpdate() +{ +    const F32 UPDATE_INTERVAL = 10.f; // update no more than this often +    const F32 TIMEOUT_INTERVAL = 30.f; // update no less than this often +    const F32 RENDER_TIMEOUT = 1.f; // don't update if hasn't been used for rendering for this long +     +    if (mLastBindTime > gFrameTimeSeconds - RENDER_TIMEOUT) +    {    +        if (mDirty && mLastUpdateTime < gFrameTimeSeconds - UPDATE_INTERVAL) +        { +            return true; +        } + +        if (mLastUpdateTime < gFrameTimeSeconds - TIMEOUT_INTERVAL) +        { +            return true; +        }      } -    mOrigin.load3(origin.mV); +    return false; +} + +void LLReflectionMap::dirty() +{ +    mDirty = true; +    mLastUpdateTime = gFrameTimeSeconds; +} + +void LLReflectionMap::autoAdjustOrigin() +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + +    if (mGroup) +    { +        const LLVector4a* bounds = mGroup->getBounds(); +        auto* node = mGroup->getOctreeNode(); + +        if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_TERRAIN) +        { +            // for terrain, make probes float a couple meters above the highest point in the surface patch +            mOrigin = bounds[0]; +            mOrigin.getF32ptr()[2] += bounds[1].getF32ptr()[2] + 3.f; + +            // update radius to encompass bounding box +            LLVector4a d; +            d.setAdd(bounds[0], bounds[1]); +            d.sub(mOrigin); +            mRadius = d.getLength3().getF32(); +        } +        else if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME) +        { +            // cast a ray towards 8 corners of bounding box +            // nudge origin towards center of empty space + +            if (node->isLeaf() || node->getChildCount() > 1 || node->getData().size() > 0) +            { // use center of object bounding box for leaf nodes or nodes with multiple child nodes +                mOrigin = bounds[0]; -    mCubeMap = new LLCubeMap(false); -    mCubeMap->initReflectionMap(resolution); +                LLVector4a start; +                LLVector4a end; -    gViewerWindow->cubeSnapshot(origin, mCubeMap); +                LLVector4a size = bounds[1]; -    mCubeMap->generateMipMaps(); +                LLVector4a corners[] = +                { +                    { 1, 1, 1 }, +                    { -1, 1, 1 }, +                    { 1, -1, 1 }, +                    { -1, -1, 1 }, +                    { 1, 1, -1 }, +                    { -1, 1, -1 }, +                    { 1, -1, -1 }, +                    { -1, -1, -1 } +                }; + +                for (int i = 0; i < 8; ++i) +                { +                    corners[i].mul(size); +                    corners[i].add(bounds[0]); +                } + +                LLVector4a extents[2]; +                extents[0].setAdd(bounds[0], bounds[1]); +                extents[1].setSub(bounds[0], bounds[1]); + +                bool hit = false; +                for (int i = 0; i < 8; ++i) +                { +                    int face = -1; +                    LLVector4a intersection; +                    LLDrawable* drawable = mGroup->lineSegmentIntersect(bounds[0], corners[i], true, false, &face, &intersection); +                    if (drawable != nullptr) +                    { +                        hit = true; +                        update_min_max(extents[0], extents[1], intersection); +                    } +                    else +                    { +                        update_min_max(extents[0], extents[1], corners[i]); +                    } +                } + +                if (hit) +                { +                    mOrigin.setAdd(extents[0], extents[1]); +                    mOrigin.mul(0.5f); +                } + +                // make sure radius encompasses all objects +                LLSimdScalar r2 = 0.0; +                for (int i = 0; i < 8; ++i) +                { +                    LLVector4a v; +                    v.setSub(corners[i], mOrigin); + +                    LLSimdScalar d = v.dot3(v); + +                    if (d > r2) +                    { +                        r2 = d; +                    } +                } + +                mRadius = llmax(sqrtf(r2.getF32()), 8.f); +            } +            else +            { +                // use center of octree node volume for nodes that are just branches without data +                mOrigin = node->getCenter(); + +                // update radius to encompass entire octree node volume +                mRadius = node->getSize().getLength3().getF32(); + +                //mOrigin = bounds[0]; +                //mRadius = bounds[1].getLength3().getF32(); + +            } +        } +    }  } +bool LLReflectionMap::intersects(LLReflectionMap* other) +{ +    LLVector4a delta; +    delta.setSub(other->mOrigin, mOrigin); + +    F32 dist = delta.dot3(delta).getF32(); + +    F32 r2 = mRadius + other->mRadius; + +    r2 *= r2; + +    return dist < r2; +} diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h index 7d39e7e562..ed1c2680b6 100644 --- a/indra/newview/llreflectionmap.h +++ b/indra/newview/llreflectionmap.h @@ -26,26 +26,61 @@  #pragma once -#include "llcubemap.h" +#include "llcubemaparray.h" +#include "llmemory.h" -class LLReflectionMap : public LLRefCount +class LLSpatialGroup; + +class alignas(16) LLReflectionMap : public LLRefCount  { +    LL_ALIGN_NEW  public:      // allocate an environment map of the given resolution       LLReflectionMap();      // update this environment map -    // origin - position in agent space to generate environment map from in agent space      // resolution - size of cube map to generate -    void update(const LLVector3& origin, U32 resolution); -     -    // point at which environment map was generated from (in agent space) -    LLVector4a mOrigin; +    void update(U32 resolution, U32 face); + +    // return true if this probe should update *now* +    bool shouldUpdate(); +    // Mark this reflection map as needing an update (resets last update time, so spamming this call will cause a cube map to never update) +    void dirty(); + +    // for volume partition probes, try to place this probe in the best spot +    void autoAdjustOrigin(); + +    // return true if given Reflection Map's influence volume intersect's with this one's +    bool intersects(LLReflectionMap* other); + +    // point at which environment map was last generated from (in agent space) +    LLVector4a mOrigin; +          // distance from viewer camera      F32 mDistance; +    // radius of this probe's affected area +    F32 mRadius = 16.f; + +    // last time this probe was updated (or when its update timer got reset) +    F32 mLastUpdateTime = 0.f; + +    // last time this probe was bound for rendering +    F32 mLastBindTime = 0.f; +      // cube map used to sample this environment map -    LLPointer<LLCubeMap> mCubeMap; +    LLPointer<LLCubeMapArray> mCubeArray; +    S32 mCubeIndex = -1; // index into cube map array or -1 if not currently stored in cube map array + +    // index into array packed by LLReflectionMapManager::getReflectionMaps +    // WARNING -- only valid immediately after call to getReflectionMaps +    S32 mProbeIndex = -1; + +    // set of any LLReflectionMaps that intersect this map (maintained by LLReflectionMapManager +    std::vector<LLReflectionMap*> mNeighbors; + +    LLSpatialGroup* mGroup = nullptr; +    bool mDirty = true;  }; diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 95b72e1d3b..a6b704d57d 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -28,30 +28,84 @@  #include "llreflectionmapmanager.h"  #include "llviewercamera.h" +#include "llspatialpartition.h" +#include "llviewerregion.h" +#include "pipeline.h" +#include "llviewershadermgr.h" + +extern BOOL gCubeSnapshot; +extern BOOL gTeleportDisplay; + +//#pragma optimize("", off)  LLReflectionMapManager::LLReflectionMapManager()  { - +    for (int i = 0; i < LL_REFLECTION_PROBE_COUNT; ++i) +    { +        mCubeFree[i] = true; +    }  }  struct CompareReflectionMapDistance  { -     +  };  struct CompareProbeDistance  { -    bool operator()(const LLReflectionMap& lhs, const LLReflectionMap& rhs) +    bool operator()(const LLPointer<LLReflectionMap>& lhs, const LLPointer<LLReflectionMap>& rhs)      { -        return lhs.mDistance < rhs.mDistance; +        return lhs->mDistance < rhs->mDistance;      }  };  // helper class to seed octree with probes  void LLReflectionMapManager::update()  { +    if (!LLPipeline::sRenderDeferred || gTeleportDisplay) +    { +        return; +    } +      LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; +    llassert(!gCubeSnapshot); // assert a snapshot is not in progress +    if (LLAppViewer::instance()->logoutRequestSent()) +    { +        return; +    } + +    // =============== TODO -- move to an init function  ================= + +    if (mTexture.isNull()) +    { +        mTexture = new LLCubeMapArray(); +        mTexture->allocate(LL_REFLECTION_PROBE_RESOLUTION, 3, LL_REFLECTION_PROBE_COUNT); +    } + +    if (!mRenderTarget.isComplete()) +    { +        U32 color_fmt = GL_RGBA; +        const bool use_depth_buffer = true; +        const bool use_stencil_buffer = true; +        U32 targetRes = LL_REFLECTION_PROBE_RESOLUTION * 4; // super sample +        mRenderTarget.allocate(targetRes, targetRes, color_fmt, use_depth_buffer, use_stencil_buffer, LLTexUnit::TT_RECT_TEXTURE); +    } + +    if (mMipChain.empty()) +    { +        U32 res = LL_REFLECTION_PROBE_RESOLUTION*2; +        U32 count = log2((F32)res) + 0.5f; +         +        mMipChain.resize(count); +        for (int i = 0; i < count; ++i) +        { +            mMipChain[i].allocate(res, res, GL_RGB, false, false, LLTexUnit::TT_RECT_TEXTURE); +            res /= 2; +        } +    } + +    // =============== TODO -- move to an init function  =================      // naively drop probes every 16m as we move the camera around for now      // later, use LLSpatialPartition to manage probes @@ -61,46 +115,462 @@ void LLReflectionMapManager::update()      LLVector4a camera_pos;      camera_pos.load3(LLViewerCamera::instance().getOrigin().mV); -    for (auto& probe : mProbes) +    // process kill list +    for (int i = 0; i < mProbes.size(); )      { -        LLVector4a d; -        d.setSub(camera_pos, probe.mOrigin); -        probe.mDistance = d.getLength3().getF32(); +        auto& iter = std::find(mKillList.begin(), mKillList.end(), mProbes[i]); +        if (iter != mKillList.end()) +        { +            deleteProbe(i); +            mProbes.erase(mProbes.begin() + i); +            mKillList.erase(iter); +        } +        else +        { +            ++i; +        }      } -    if (mProbes.empty() || mProbes[0].mDistance > PROBE_SPACING) +    mKillList.clear(); +     +    // process create list +    for (auto& probe : mCreateList)      { -        addProbe(LLViewerCamera::instance().getOrigin()); +        mProbes.push_back(probe);      } -    // update distance to camera for all probes -    std::sort(mProbes.begin(), mProbes.end(), CompareProbeDistance()); +    mCreateList.clear(); + +    const F32 UPDATE_INTERVAL = 10.f;  //update no more than once every 5 seconds + +    bool did_update = false; + +    if (mUpdatingProbe != nullptr) +    { +        did_update = true; +        doProbeUpdate(); +    } -    if (mProbes.size() > MAX_PROBES) +    for (int i = 0; i < mProbes.size(); ++i)      { -        mProbes.resize(MAX_PROBES); +        LLReflectionMap* probe = mProbes[i]; +        if (probe->getNumRefs() == 1) +        { // no references held outside manager, delete this probe +            deleteProbe(i); +            --i; +            continue; +        } +         +        probe->mProbeIndex = i; + +        LLVector4a d; +         +        if (probe->shouldUpdate() && !did_update && i < LL_REFLECTION_PROBE_COUNT) +        { +            if (probe->mCubeIndex == -1) +            { +                probe->mCubeArray = mTexture; +                probe->mCubeIndex = allocateCubeIndex(); +            } + +            did_update = true; // only update one probe per frame +            probe->autoAdjustOrigin(); + +            mUpdatingProbe = probe; +            doProbeUpdate(); +            probe->mDirty = false; +        } + +        d.setSub(camera_pos, probe->mOrigin); +        probe->mDistance = d.getLength3().getF32()-probe->mRadius;      } + +    // update distance to camera for all probes +    std::sort(mProbes.begin(), mProbes.end(), CompareProbeDistance());  }  void LLReflectionMapManager::addProbe(const LLVector3& pos)  { -    LLReflectionMap probe; -    probe.update(pos, 1024); -    mProbes.push_back(probe); +    //LLReflectionMap* probe = new LLReflectionMap(); +    //probe->update(pos, 1024); +    //mProbes.push_back(probe); +} + +LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group) +{ +    LLReflectionMap* probe = new LLReflectionMap(); +    probe->mGroup = group; +    probe->mOrigin = group->getOctreeNode()->getCenter(); +    probe->mDirty = true; + +    if (gCubeSnapshot) +    { //snapshot is in progress, mProbes is being iterated over, defer insertion until next update +        mCreateList.push_back(probe); +    } +    else +    { +        mProbes.push_back(probe); +    } + +    return probe;  }  void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& maps)  { -    // just null out for now -    U32 i = 0; -    for (i = 0; i < maps.size() && i < mProbes.size(); ++i) +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + +    U32 count = 0; +    U32 lastIdx = 0; +    for (U32 i = 0; count < maps.size() && i < mProbes.size(); ++i) +    { +        mProbes[i]->mLastBindTime = gFrameTimeSeconds; // something wants to use this probe, indicate it's been requested +        if (mProbes[i]->mCubeIndex != -1) +        { +            mProbes[i]->mProbeIndex = count; +            maps[count++] = mProbes[i]; +        } +        else +        { +            mProbes[i]->mProbeIndex = -1; +        } +        lastIdx = i; +    } + +    // set remaining probe indices to -1 +    for (U32 i = lastIdx+1; i < mProbes.size(); ++i) +    { +        mProbes[i]->mProbeIndex = -1; +    } + +    // null terminate list +    if (count < maps.size()) +    { +        maps[count] = nullptr; +    } +} + +LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* group) +{ +    if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME) +    { +        OctreeNode* node = group->getOctreeNode(); +        F32 size = node->getSize().getF32ptr()[0]; +        if (size >= 7.f && size <= 17.f) +        { +            return addProbe(group); +        } +    } +     +    if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_TERRAIN) +    { +        OctreeNode* node = group->getOctreeNode(); +        F32 size = node->getSize().getF32ptr()[0]; +        if (size >= 15.f && size <= 17.f) +        { +            return addProbe(group); +        } +    } + +    return nullptr; +} + +S32 LLReflectionMapManager::allocateCubeIndex() +{ +    for (int i = 0; i < LL_REFLECTION_PROBE_COUNT; ++i) +    { +        if (mCubeFree[i]) +        { +            mCubeFree[i] = false; +            return i; +        } +    } + +    // no cubemaps free, steal one from the back of the probe list +    for (int i = mProbes.size() - 1; i >= LL_REFLECTION_PROBE_COUNT; --i) +    { +        if (mProbes[i]->mCubeIndex != -1) +        { +            S32 ret = mProbes[i]->mCubeIndex; +            mProbes[i]->mCubeIndex = -1; +            return ret; +        } +    } + +    llassert(false); // should never fail to allocate, something is probably wrong with mCubeFree +    return -1; +} + +void LLReflectionMapManager::deleteProbe(U32 i) +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; +    LLReflectionMap* probe = mProbes[i]; + +    if (probe->mCubeIndex != -1) +    { // mark the cube index used by this probe as being free +        mCubeFree[probe->mCubeIndex] = true; +    } +    if (mUpdatingProbe == probe) +    { +        mUpdatingProbe = nullptr; +        mUpdatingFace = 0; +    } + +    // remove from any Neighbors lists +    for (auto& other : probe->mNeighbors) +    { +        auto& iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe); +        llassert(iter != other->mNeighbors.end()); +        other->mNeighbors.erase(iter); +    } + +    mProbes.erase(mProbes.begin() + i); +} + + +void LLReflectionMapManager::doProbeUpdate() +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; +    llassert(mUpdatingProbe != nullptr); + +    mRenderTarget.bindTarget(); +    mUpdatingProbe->update(mRenderTarget.getWidth(), mUpdatingFace); +    mRenderTarget.flush(); + +    // generate mipmaps      { -        maps[i] = &(mProbes[i]); +        LLGLDepthTest depth(GL_FALSE, GL_FALSE); +        LLGLDisable cull(GL_CULL_FACE); + +        gReflectionMipProgram.bind(); +        gGL.matrixMode(gGL.MM_MODELVIEW); +        gGL.pushMatrix(); +        gGL.loadIdentity(); + +        gGL.matrixMode(gGL.MM_PROJECTION); +        gGL.pushMatrix(); +        gGL.loadIdentity(); + +        gGL.flush(); +        U32 res = LL_REFLECTION_PROBE_RESOLUTION*4; + +        S32 mips = log2((F32) LL_REFLECTION_PROBE_RESOLUTION)+0.5f; + +        for (int i = 0; i < mMipChain.size(); ++i) +        { +            mMipChain[i].bindTarget(); + +            if (i == 0) +            { +                gGL.getTexUnit(0)->bind(&mRenderTarget); +            } +            else +            { +                gGL.getTexUnit(0)->bind(&(mMipChain[i - 1])); +            } + +            gGL.begin(gGL.QUADS); +             +            gGL.texCoord2f(0, 0); +            gGL.vertex2f(-1, -1); +             +            gGL.texCoord2f(res, 0); +            gGL.vertex2f(1, -1); + +            gGL.texCoord2f(res, res); +            gGL.vertex2f(1, 1); + +            gGL.texCoord2f(0, res); +            gGL.vertex2f(-1, 1); +            gGL.end(); +            gGL.flush(); + +            res /= 2; + +            S32 mip = i - (mMipChain.size() - mips); + +            if (mip >= 0) +            { +                mTexture->bind(0); +                glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, mUpdatingProbe->mCubeIndex * 6 + mUpdatingFace, 0, 0, res, res); +                mTexture->unbind(); +            } +            mMipChain[i].flush(); +        } + +        gGL.popMatrix(); +        gGL.matrixMode(gGL.MM_MODELVIEW); +        gGL.popMatrix(); + +        gReflectionMipProgram.unbind(); +    } +     +    if (++mUpdatingFace == 6) +    { +        updateNeighbors(mUpdatingProbe); +        mUpdatingProbe = nullptr; +        mUpdatingFace = 0; +    } +} + +void LLReflectionMapManager::rebuild() +{ +    for (auto& probe : mProbes) +    { +        probe->mLastUpdateTime = 0.f;      } +} -    for (++i; i < maps.size(); ++i) +void LLReflectionMapManager::shift(const LLVector4a& offset) +{ +    for (auto& probe : mProbes)      { -        maps[i] = nullptr; +        probe->mOrigin.add(offset);      }  } +void LLReflectionMapManager::updateNeighbors(LLReflectionMap* probe) +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + +    //remove from existing neighbors +    { +        LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - clear"); +     +        for (auto& other : probe->mNeighbors) +        { +            auto& iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe); +            llassert(iter != other->mNeighbors.end()); // <--- bug davep if this ever happens, something broke badly +            other->mNeighbors.erase(iter); +        } + +        probe->mNeighbors.clear(); +    } + +    // search for new neighbors +    { +        LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - search"); +        for (auto& other : mProbes) +        { +            if (other != probe) +            { +                if (probe->intersects(other)) +                { +                    probe->mNeighbors.push_back(other); +                    other->mNeighbors.push_back(probe); +                } +            } +        } +    } +} + +void LLReflectionMapManager::setUniforms() +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + +    // structure for packing uniform buffer object +    // see class2/deferred/softenLightF.glsl +    struct ReflectionProbeData +    { +        LLVector4 refSphere[LL_REFLECTION_PROBE_COUNT]; //origin and radius of refmaps in clip space +        GLint refIndex[LL_REFLECTION_PROBE_COUNT][4]; +        GLint refNeighbor[4096]; +        GLint refmapCount; +    }; + +    mReflectionMaps.resize(LL_REFLECTION_PROBE_COUNT); +    getReflectionMaps(mReflectionMaps); + +    ReflectionProbeData rpd; + +    // load modelview matrix into matrix 4a +    LLMatrix4a modelview; +    modelview.loadu(gGLModelView); +    LLVector4a oa; // scratch space for transformed origin + +    S32 count = 0; +    U32 nc = 0; // neighbor "cursor" - index into refNeighbor to start writing the next probe's list of neighbors + +    for (auto* refmap : mReflectionMaps) +    { +        if (refmap == nullptr) +        { +            break; +        } + +        llassert(refmap->mProbeIndex == count); +        llassert(mReflectionMaps[refmap->mProbeIndex] == refmap); + +        llassert(refmap->mCubeIndex >= 0); // should always be  true, if not, getReflectionMaps is bugged + +        { +            //LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - refSphere"); + +            modelview.affineTransform(refmap->mOrigin, oa); +            rpd.refSphere[count].set(oa.getF32ptr()); +            rpd.refSphere[count].mV[3] = refmap->mRadius; +        } + +        rpd.refIndex[count][0] = refmap->mCubeIndex; +        llassert(nc % 4 == 0); +        rpd.refIndex[count][1] = nc / 4; + +        S32 ni = nc; // neighbor ("index") - index into refNeighbor to write indices for current reflection probe's neighbors +        { +            //LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - refNeighbors"); +            //pack neghbor list +            for (auto& neighbor : refmap->mNeighbors) +            { +                if (ni >= 4096) +                { // out of space +                    break; +                } +                 +                GLint idx = neighbor->mProbeIndex; +                if (idx == -1) +                { +                    continue; +                } + +                // this neighbor may be sampled +                rpd.refNeighbor[ni++] = idx; +            } +        } +         +        if (nc == ni) +        { +            //no neighbors, tag as empty +            rpd.refIndex[count][1] = -1; +        } +        else +        { +            rpd.refIndex[count][2] = ni - nc; + +            // move the cursor forward +            nc = ni; +            if (nc % 4 != 0) +            { // jump to next power of 4 for compatibility with ivec4 +                nc += 4 - (nc % 4); +            } +        } +         +         +        count++; +    } + +    rpd.refmapCount = count; + +    //copy rpd into uniform buffer object +    if (mUBO == 0) +    { +        glGenBuffersARB(1, &mUBO); +    } + +    { +        LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - update buffer"); +        glBindBufferARB(GL_UNIFORM_BUFFER, mUBO); +        glBufferDataARB(GL_UNIFORM_BUFFER, sizeof(ReflectionProbeData), &rpd, GL_STREAM_DRAW); +        glBindBufferARB(GL_UNIFORM_BUFFER, 0); +    } + +    glBindBufferBase(GL_UNIFORM_BUFFER, 1, mUBO); +} diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h index 40e925d916..24ac40b264 100644 --- a/indra/newview/llreflectionmapmanager.h +++ b/indra/newview/llreflectionmapmanager.h @@ -27,9 +27,20 @@  #pragma once  #include "llreflectionmap.h" +#include "llrendertarget.h" +#include "llcubemaparray.h" -class LLReflectionMapManager +class LLSpatialGroup; + +// number of reflection probes to keep in vram +#define LL_REFLECTION_PROBE_COUNT 256 + +// reflection probe resolution +#define LL_REFLECTION_PROBE_RESOLUTION 256 + +class alignas(16) LLReflectionMapManager  { +    LL_ALIGN_NEW  public:      // allocate an environment map of the given resolution       LLReflectionMapManager(); @@ -40,12 +51,74 @@ public:      // drop a reflection probe at the specified position in agent space      void addProbe(const LLVector3& pos); +    // add a probe for the given spatial group +    LLReflectionMap* addProbe(LLSpatialGroup* group); +          // Populate "maps" with the N most relevant Reflection Maps where N is no more than maps.size()      // If less than maps.size() ReflectionMaps are available, will assign trailing elements to nullptr.      //  maps -- presized array of Reflection Map pointers      void getReflectionMaps(std::vector<LLReflectionMap*>& maps); +    // called by LLSpatialGroup constructor +    // If spatial group should receive a Reflection Probe, will create one for the specified spatial group +    LLReflectionMap* registerSpatialGroup(LLSpatialGroup* group); + +    // force an update of all probes +    void rebuild(); + +    // called on region crossing to "shift" probes into new coordinate frame +    void shift(const LLVector4a& offset); + +private: +    friend class LLPipeline; + +    // delete the probe with the given index in mProbes +    void deleteProbe(U32 i); + +    // get a free cube index +    // if no cube indices are free, free one starting from the back of the probe list +    S32 allocateCubeIndex(); + +    // update the neighbors of the given probe  +    void updateNeighbors(LLReflectionMap* probe); + +    void setUniforms(); + +    // render target for cube snapshots +    // used to generate mipmaps without doing a copy-to-texture +    LLRenderTarget mRenderTarget; + +    std::vector<LLRenderTarget> mMipChain; + +    // storage for reflection probes +    LLPointer<LLCubeMapArray> mTexture; + +    // array indicating if a particular cubemap is free +    bool mCubeFree[LL_REFLECTION_PROBE_COUNT]; + +    // start tracking the given spatial group +    void trackGroup(LLSpatialGroup* group); +     +    // perform an update on the currently updating Probe +    void doProbeUpdate(); +          // list of active reflection maps -    std::vector<LLReflectionMap> mProbes; +    std::vector<LLPointer<LLReflectionMap> > mProbes; + +    // list of reflection maps to kill +    std::vector<LLPointer<LLReflectionMap> > mKillList; + +    // list of reflection maps to create +    std::vector<LLPointer<LLReflectionMap> > mCreateList; + +    // handle to UBO +    U32 mUBO = 0; + +    // list of maps being used for rendering +    std::vector<LLReflectionMap*> mReflectionMaps; + +    LLReflectionMap* mUpdatingProbe = nullptr; +    U32 mUpdatingFace = 0; +  }; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 5c648c11e1..5909cd1f4c 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -554,9 +554,12 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLO  	sg_assert(mOctreeNode->getListenerCount() == 0);  	setState(SG_INITIAL_STATE_MASK);  	gPipeline.markRebuild(this, TRUE); +     +    // let the reflection map manager know about this spatial group +    mReflectionProbe = gPipeline.mReflectionMapManager.registerSpatialGroup(this); -	mRadius = 1; -	mPixelArea = 1024.f; +    mRadius = 1; +    mPixelArea = 1024.f;  }  void LLSpatialGroup::updateDistance(LLCamera &camera) @@ -735,8 +738,17 @@ BOOL LLSpatialGroup::changeLOD()  	return FALSE;  } +void LLSpatialGroup::dirtyReflectionProbe() +{ +    if (mReflectionProbe != nullptr) +    { +        mReflectionProbe->dirty(); +    } +} +  void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* entry)  { +    dirtyReflectionProbe();  	addObject((LLDrawable*)entry->getDrawable());  	unbound();  	setState(OBJECT_DIRTY); @@ -744,6 +756,7 @@ void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry*  void LLSpatialGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* entry)  { +    dirtyReflectionProbe();  	removeObject((LLDrawable*)entry->getDrawable(), TRUE);  	LLViewerOctreeGroup::handleRemoval(node, entry);  } @@ -780,6 +793,8 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c  {  	LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL +    dirtyReflectionProbe(); +  	if (child->getListenerCount() == 0)  	{  		new LLSpatialGroup(child, getSpatialPartition()); @@ -794,6 +809,11 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c  	assert_states_valid(this);  } +void LLSpatialGroup::handleChildRemoval(const oct_node* parent, const oct_node* child) +{ +    dirtyReflectionProbe(); +} +  void LLSpatialGroup::destroyGL(bool keep_occlusion)   {  	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY); @@ -1398,7 +1418,9 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result  	return 0;  	} -	 + +extern BOOL gCubeSnapshot; +  S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL; @@ -1417,7 +1439,7 @@ S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)          LLOctreeCullShadow culler(&camera);          culler.traverse(mOctree);      } -    else if (mInfiniteFarClip || !LLPipeline::sUseFarClip) +    else if (mInfiniteFarClip || (!LLPipeline::sUseFarClip && !gCubeSnapshot))      {          LLOctreeCullNoFarClip culler(&camera);          culler.traverse(mOctree); @@ -1737,12 +1759,71 @@ void renderOctree(LLSpatialGroup* group)  			}  		}*/  	} -	 +  //	LLSpatialGroup::OctreeNode* node = group->mOctreeNode;  //	gGL.diffuseColor4f(0,1,0,1);  //	drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize()));  } +void renderReflectionProbes(LLSpatialGroup* group) +{ +    if (group->mReflectionProbe) +    { // draw lines from corners of object aabb to reflection probe + +        const LLVector4a* bounds = group->getBounds(); +        LLVector4a o = bounds[0]; + +        gGL.flush(); +        gGL.diffuseColor4f(0, 0, 1, 1); +        F32* c = o.getF32ptr(); + +        const F32* bc = bounds[0].getF32ptr(); +        const F32* bs = bounds[1].getF32ptr(); + +        // daaw blue lines from corners to center of node +        gGL.begin(gGL.LINES); +        gGL.vertex3fv(c); +        gGL.vertex3f(bc[0] + bs[0], bc[1] + bs[1], bc[2] + bs[2]); +        gGL.vertex3fv(c); +        gGL.vertex3f(bc[0] - bs[0], bc[1] + bs[1], bc[2] + bs[2]); +        gGL.vertex3fv(c); +        gGL.vertex3f(bc[0] + bs[0], bc[1] - bs[1], bc[2] + bs[2]); +        gGL.vertex3fv(c); +        gGL.vertex3f(bc[0] - bs[0], bc[1] - bs[1], bc[2] + bs[2]); + +        gGL.vertex3fv(c); +        gGL.vertex3f(bc[0] + bs[0], bc[1] + bs[1], bc[2] - bs[2]); +        gGL.vertex3fv(c); +        gGL.vertex3f(bc[0] - bs[0], bc[1] + bs[1], bc[2] - bs[2]); +        gGL.vertex3fv(c); +        gGL.vertex3f(bc[0] + bs[0], bc[1] - bs[1], bc[2] - bs[2]); +        gGL.vertex3fv(c); +        gGL.vertex3f(bc[0] - bs[0], bc[1] - bs[1], bc[2] - bs[2]); +        gGL.end(); + +        F32* po = group->mReflectionProbe->mOrigin.getF32ptr(); +        //draw yellow line from center of node to reflection probe origin +        gGL.flush(); +        gGL.diffuseColor4f(1, 1, 0, 1); +        gGL.begin(gGL.LINES); +        gGL.vertex3fv(c); +        gGL.vertex3fv(po); +        gGL.end(); +        gGL.flush(); + +        //draw orange line from probe to neighbors +        gGL.flush(); +        gGL.diffuseColor4f(1, 0.5f, 0, 1); +        gGL.begin(gGL.LINES); +        for (auto& probe : group->mReflectionProbe->mNeighbors) +        { +            gGL.vertex3fv(po); +            gGL.vertex3fv(probe->mOrigin.getF32ptr()); +        } +        gGL.end(); +        gGL.flush(); +    } +}  std::set<LLSpatialGroup*> visible_selected_groups;  void renderVisibility(LLSpatialGroup* group, LLCamera* camera) @@ -3289,6 +3370,12 @@ public:  				stop_glerror();  			} +            //draw reflection probes and links between them +            if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_REFLECTION_PROBES)) +            { +                renderReflectionProbes(group); +            } +  			//render visibility wireframe  			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))  			{ @@ -3703,7 +3790,8 @@ void LLSpatialPartition::renderDebug()  									  //LLPipeline::RENDER_DEBUG_BUILD_QUEUE |  									  LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA |  									  LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY | -									  LLPipeline::RENDER_DEBUG_TEXEL_DENSITY))  +									  LLPipeline::RENDER_DEBUG_TEXEL_DENSITY | +                                      LLPipeline::RENDER_DEBUG_REFLECTION_PROBES))  	{  		return;  	} @@ -3947,6 +4035,23 @@ LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector4a& start, co  	return drawable;  } +LLDrawable* LLSpatialGroup::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, +    BOOL pick_transparent, +    BOOL pick_rigged, +    S32* face_hit,                   // return the face hit +    LLVector4a* intersection,         // return the intersection point +    LLVector2* tex_coord,            // return the texture coordinates of the intersection point +    LLVector4a* normal,               // return the surface normal at the intersection point +    LLVector4a* tangent			// return the surface tangent at the intersection point +) + +{ +    LLOctreeIntersect intersect(start, end, pick_transparent, pick_rigged, face_hit, intersection, tex_coord, normal, tangent); +    LLDrawable* drawable = intersect.check(getOctreeNode()); + +    return drawable; +} +  LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,   					   LLViewerTexture* texture, LLVertexBuffer* buffer,  					   bool selected, diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index acfcd63686..a30660b2de 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -53,6 +53,7 @@ class LLSpatialPartition;  class LLSpatialBridge;  class LLSpatialGroup;  class LLViewerRegion; +class LLReflectionMap;  void pushVerts(LLFace* face, U32 mask); @@ -300,6 +301,17 @@ public:  	void drawObjectBox(LLColor4 col); +    LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, +        BOOL pick_transparent, +        BOOL pick_rigged, +        S32* face_hit,                          // return the face hit +        LLVector4a* intersection = NULL,         // return the intersection point +        LLVector2* tex_coord = NULL,            // return the texture coordinates of the intersection point +        LLVector4a* normal = NULL,               // return the surface normal at the intersection point +        LLVector4a* tangent = NULL             // return the surface tangent at the intersection point +    ); + +  	LLSpatialPartition* getSpatialPartition() {return (LLSpatialPartition*)mSpatialPartition;}  	 //LISTENER FUNCTIONS @@ -307,6 +319,7 @@ public:  	virtual void handleRemoval(const TreeNode* node, LLViewerOctreeEntry* face);  	virtual void handleDestruction(const TreeNode* node);  	virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child); +    virtual void handleChildRemoval(const oct_node* parent, const oct_node* child);  public:  	LL_ALIGN_16(LLVector4a mViewAngle); @@ -314,6 +327,8 @@ public:  	F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3() +    void dirtyReflectionProbe(); +  protected:  	virtual ~LLSpatialGroup(); @@ -338,6 +353,10 @@ public:  	F32 mPixelArea;  	F32 mRadius; + +    // Reflection Probe associated with this node (if any) +    LLPointer<LLReflectionMap> mReflectionProbe = nullptr; +  } LL_ALIGN_POSTFIX(64);  class LLGeometryManager diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 6a2b06d9b5..f375852dfe 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -97,6 +97,7 @@ BOOL gResizeScreenTexture = FALSE;  BOOL gResizeShadowTexture = FALSE;  BOOL gWindowResized = FALSE;  BOOL gSnapshot = FALSE; +BOOL gCubeSnapshot = FALSE;  BOOL gShaderProfileFrame = FALSE;  // This is how long the sim will try to teleport you before giving up. @@ -193,15 +194,23 @@ void display_update_camera()  	// Cut draw distance in half when customizing avatar,  	// but on the viewer only.  	F32 final_far = gAgentCamera.mDrawDistance; -	if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) +    if (gCubeSnapshot) +    { +        final_far = gSavedSettings.getF32("RenderReflectionProbeDrawDistance"); +    } +    else if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) +          	{  		final_far *= 0.5f;  	}  	LLViewerCamera::getInstance()->setFar(final_far);  	gViewerWindow->setup3DRender(); -	// Update land visibility too -	LLWorld::getInstance()->setLandFarClip(final_far); +    if (!gCubeSnapshot) +    { +        // Update land visibility too +        LLWorld::getInstance()->setLandFarClip(final_far); +    }  }  // Write some stats to LL_INFOS() @@ -1048,6 +1057,112 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)  	}  } +// WIP simplified copy of display() that does minimal work +void display_cube_face() +{ +    LL_RECORD_BLOCK_TIME(FTM_RENDER); +    llassert(!gSnapshot); +    llassert(!gTeleportDisplay); +    llassert(LLPipeline::sRenderDeferred); +    llassert(LLStartUp::getStartupState() >= STATE_PRECACHE); +    llassert(!LLAppViewer::instance()->logoutRequestSent()); +    llassert(!gRestoreGL); +    llassert(!gUseWireframe); + +    bool rebuild = false; + +    LLGLSDefault gls_default; +    LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL); + +    LLVertexBuffer::unbind(); + +    gPipeline.disableLights(); + +    gPipeline.mBackfaceCull = TRUE; + +    LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE); +    gViewerWindow->setup3DViewport(); + +    if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) +    { //don't draw hud objects in this frame +        gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); +    } + +    if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES)) +    { //don't draw hud particles in this frame +        gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); +    } + +    display_update_camera(); + +    LLSpatialGroup::sNoDelete = TRUE; +         +    S32 occlusion = LLPipeline::sUseOcclusion; +    LLPipeline::sUseOcclusion = 0; // occlusion data is from main camera point of view, don't read or write it during cube snapshots +    //gDepthDirty = TRUE; //let "real" render pipe know it can't trust the depth buffer for occlusion data + +    static LLCullResult result; +    LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; +    LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater(); +    gPipeline.updateCull(*LLViewerCamera::getInstance(), result); + +    gGL.setColorMask(true, true); +    glClearColor(0, 0, 0, 0); +    gPipeline.generateSunShadow(*LLViewerCamera::getInstance()); +         +    glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + +    { +        LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; +        gPipeline.stateSort(*LLViewerCamera::getInstance(), result); + +        if (rebuild) +        { +            ////////////////////////////////////// +            // +            // rebuildPools +            // +            // +            gPipeline.rebuildPools(); +            stop_glerror(); +        } +    } +     +    LLPipeline::sUseOcclusion = occlusion; + +    LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart"); + +    LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE; + +    gGL.setColorMask(true, true); + +    gPipeline.mDeferredScreen.bindTarget(); +    glClearColor(1, 0, 1, 1); +    gPipeline.mDeferredScreen.clear(); +         +    gGL.setColorMask(true, false); + +    LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + +    gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance()); + +    gGL.setColorMask(true, true); + +    gPipeline.mDeferredScreen.flush(); +        +    gPipeline.renderDeferredLighting(&gPipeline.mScreen); + +    LLPipeline::sUnderWaterRender = FALSE; + +    // Finalize scene +    gPipeline.renderFinalize(); + +    LLSpatialGroup::sNoDelete = FALSE; +    gPipeline.clearReferences(); + +    gPipeline.rebuildGroups(); +} +  void render_hud_attachments()  {  	gGL.matrixMode(LLRender::MM_PROJECTION); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index f5ea060e82..8732bde35c 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1081,6 +1081,10 @@ U64 info_display_from_string(std::string info_display)  	{  		return LLPipeline::RENDER_DEBUG_IMPOSTORS;  	} +    else if ("reflection probes" == info_display) +    { +    return LLPipeline::RENDER_DEBUG_REFLECTION_PROBES; +    }  	else  	{  		LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL; @@ -8304,9 +8308,9 @@ void handle_cache_clear_immediately()  	LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately);  } -void handle_override_environment_map() +void handle_rebuild_reflection_probes()  { -    gPipeline.overrideEnvironmentMap(); +    gPipeline.mReflectionMapManager.rebuild();  } @@ -9409,7 +9413,7 @@ void initialize_menus()  	//Develop (clear cache immediately)  	commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) );      //Develop (override environment map) -    commit.add("Develop.OverrideEnvironmentMap", boost::bind(&handle_override_environment_map)); +    commit.add("Develop.RebuildReflectionProbes", boost::bind(&handle_rebuild_reflection_probes));  	// Admin >Object  	view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 50a0ff07fc..94af320a73 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -82,6 +82,7 @@ LLGLSLShader	gOcclusionCubeProgram;  LLGLSLShader	gCustomAlphaProgram;  LLGLSLShader	gGlowCombineProgram;  LLGLSLShader	gSplatTextureRectProgram; +LLGLSLShader	gReflectionMipProgram;  LLGLSLShader	gGlowCombineFXAAProgram;  LLGLSLShader	gTwoTextureAddProgram;  LLGLSLShader	gTwoTextureCompareProgram; @@ -635,7 +636,6 @@ void LLViewerShaderMgr::setShaders()      }      if (loaded) -      {          loaded = loadTransformShaders();          if (loaded) @@ -746,6 +746,7 @@ void LLViewerShaderMgr::unloadShaders()  	gCustomAlphaProgram.unload();  	gGlowCombineProgram.unload();  	gSplatTextureRectProgram.unload(); +    gReflectionMipProgram.unload();  	gGlowCombineFXAAProgram.unload();  	gTwoTextureAddProgram.unload();  	gTwoTextureCompareProgram.unload(); @@ -3587,7 +3588,6 @@ BOOL LLViewerShaderMgr::loadShadersInterface()  		}  	} -  	if (success)  	{  		gTwoTextureAddProgram.mName = "Two Texture Add Shader"; @@ -3763,6 +3763,22 @@ BOOL LLViewerShaderMgr::loadShadersInterface()  		success = gAlphaMaskProgram.createShader(NULL, NULL);  	} +    if (success) +    { +        gReflectionMipProgram.mName = "Reflection Mip Shader"; +        gReflectionMipProgram.mShaderFiles.clear(); +        gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/splattexturerectV.glsl", GL_VERTEX_SHADER_ARB)); +        gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/reflectionmipF.glsl", GL_FRAGMENT_SHADER_ARB)); +        gReflectionMipProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; +        success = gReflectionMipProgram.createShader(NULL, NULL); +        if (success) +        { +            gReflectionMipProgram.bind(); +            gReflectionMipProgram.uniform1i(sScreenMap, 0); +            gReflectionMipProgram.unbind(); +        } +    } +  	if( !success )  	{  		mShaderLevel[SHADER_INTERFACE] = 0; diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 50a3daebaa..f0187db302 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -161,6 +161,7 @@ extern LLGLSLShader			gOcclusionCubeProgram;  extern LLGLSLShader			gCustomAlphaProgram;  extern LLGLSLShader			gGlowCombineProgram;  extern LLGLSLShader			gSplatTextureRectProgram; +extern LLGLSLShader			gReflectionMipProgram;  extern LLGLSLShader			gGlowCombineFXAAProgram;  extern LLGLSLShader			gDebugProgram;  extern LLGLSLShader			gClipProgram; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index f562a9458b..9bda4bbf92 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -228,6 +228,7 @@ extern BOOL gDebugClicks;  extern BOOL gDisplaySwapBuffers;  extern BOOL gDepthDirty;  extern BOOL gResizeScreenTexture; +extern BOOL gCubeSnapshot;  LLViewerWindow	*gViewerWindow = NULL; @@ -5267,29 +5268,30 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_      return true;  } -BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap) +void display_cube_face(); + +BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face)  {      // NOTE: implementation derived from LLFloater360Capture::capture360Images() and simpleSnapshot      LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;      llassert(LLPipeline::sRenderDeferred); +    llassert(!gCubeSnapshot); //assert a snapshot isn't already in progress -    U32 res = cubemap->getResolution(); +    U32 res = LLRenderTarget::sCurResX;      llassert(res <= gPipeline.mDeferredScreen.getWidth());      llassert(res <= gPipeline.mDeferredScreen.getHeight()); -     -      // save current view/camera settings so we can restore them afterwards      S32 old_occlusion = LLPipeline::sUseOcclusion;      // set new parameters specific to the 360 requirements      LLPipeline::sUseOcclusion = 0;      LLViewerCamera* camera = LLViewerCamera::getInstance(); -    LLVector3 old_origin = camera->getOrigin(); -    F32 old_fov = camera->getView(); -    F32 old_aspect = camera->getAspect(); -    F32 old_yaw = camera->getYaw(); +     +    LLViewerCamera saved_camera = LLViewerCamera::instance(); +    glh::matrix4f saved_proj = get_current_projection(); +    glh::matrix4f saved_mod = get_current_modelview();      // camera constants for the square, cube map capture image      camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV @@ -5297,8 +5299,6 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap)      camera->yaw(0.0);      camera->setOrigin(origin); -    gDisplaySwapBuffers = FALSE; -      glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);      BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE; @@ -5306,55 +5306,38 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap)      {          LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);      } - -    LLPipeline::sShowHUDAttachments = FALSE; -    LLRect window_rect = getWorldViewRectRaw(); - -    LLRenderTarget scratch_space;  // TODO: hold onto "scratch space" render target and allocate oncer per session (allocate takes > 1ms) -    U32 color_fmt = GL_RGBA; -    const bool use_depth_buffer = true; -    const bool use_stencil_buffer = true; -    if (scratch_space.allocate(res, res, color_fmt, use_depth_buffer, use_stencil_buffer)) -    { -        mWorldViewRectRaw.set(0, res, res, 0); -        scratch_space.bindTarget(); -    } -    else +    BOOL prev_draw_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES); +    if (prev_draw_particles)      { -        return FALSE; +        gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES);      } +    LLPipeline::sShowHUDAttachments = FALSE; +    LLRect window_rect = getWorldViewRectRaw(); -    // "target" parameter of glCopyTexImage2D for each side of cubemap -    U32 targets[6] = { -        GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, -        GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, -        GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, -        GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, -        GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, -        GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB -    }; +    mWorldViewRectRaw.set(0, res, res, 0); -    // these are the 6 directions we will point the camera, see LLCubeMap::mTargets +    // these are the 6 directions we will point the camera, see LLCubeMapArray::sTargets      LLVector3 look_dirs[6] = { -        LLVector3(-1, 0, 0),          LLVector3(1, 0, 0), -        LLVector3(0, -1, 0), +        LLVector3(-1, 0, 0),          LLVector3(0, 1, 0), -        LLVector3(0, 0, -1), -        LLVector3(0, 0, 1) +        LLVector3(0, -1, 0), +        LLVector3(0, 0, 1), +        LLVector3(0, 0, -1)      };      LLVector3 look_upvecs[6] = {          LLVector3(0, -1, 0),          LLVector3(0, -1, 0), -        LLVector3(0, 0, -1),          LLVector3(0, 0, 1), +        LLVector3(0, 0, -1),          LLVector3(0, -1, 0),          LLVector3(0, -1, 0)      };      // for each of six sides of cubemap -    for (int i = 0; i < 6; ++i) +    //for (int i = 0; i < 6; ++i) +    int i = face;      {          // set up camera to look in each direction          camera->lookDir(look_dirs[i], look_upvecs[i]); @@ -5368,22 +5351,12 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap)          gDisplaySwapBuffers = FALSE;          // actually render the scene -        const U32 subfield = 0; -        const bool do_rebuild = true; -        const F32 zoom = 1.0; -        const bool for_snapshot = TRUE; -        display(do_rebuild, zoom, subfield, for_snapshot); - -        // copy results to cube map face -        cubemap->enable(0); -        cubemap->bind(); -        glCopyTexImage2D(targets[i], 0, GL_RGB, 0, 0, res, res, 0); -        gGL.getTexUnit(0)->disable(); -        cubemap->disable(); +        gCubeSnapshot = TRUE; +        display_cube_face(); +        gCubeSnapshot = FALSE;      } -    gDisplaySwapBuffers = FALSE; -    gDepthDirty = TRUE; +    gDisplaySwapBuffers = TRUE;      if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))      { @@ -5393,23 +5366,23 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap)          }      } +    if (prev_draw_particles) +    { +        gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); +    } +      LLPipeline::sShowHUDAttachments = TRUE;      gPipeline.resetDrawOrders();      mWorldViewRectRaw = window_rect; -    scratch_space.flush(); -    scratch_space.release();      // restore original view/camera/avatar settings settings -    camera->setAspect(old_aspect); -    camera->setView(old_fov); -    camera->yaw(old_yaw); -    camera->setOrigin(old_origin); - +    *camera = saved_camera; +    set_current_modelview(saved_mod); +    set_current_projection(saved_proj);      LLPipeline::sUseOcclusion = old_occlusion;      // ==================================================== -      return true;  } diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index be4e9a17a5..ac7f8b2e39 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -69,6 +69,7 @@ class LLViewerWindowListener;  class LLVOPartGroup;  class LLPopupView;  class LLCubeMap; +class LLCubeMapArray;  #define PICK_HALF_WIDTH 5  #define PICK_DIAMETER (2 * PICK_HALF_WIDTH + 1) @@ -365,8 +366,9 @@ public:      // take a cubemap snapshot      // origin - vantage point to take the snapshot from -    // cubemap - cubemap to store the results -    BOOL cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap); +    // cubearray - cubemap array for storing the results +    // index - cube index in the array to use (cube index, not face-layer) +    BOOL cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 index, S32 face);      // special implementation of simpleSnapshot for reflection maps diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 17d92fda38..ef6ee4b910 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -106,6 +106,7 @@ LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL;  LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL;  extern BOOL gGLDebugLoggingEnabled; +extern BOOL gCubeSnapshot;  // Implementation class of LLMediaDataClientObject.  See llmediadataclient.h  class LLMediaDataClientObjectImpl : public LLMediaDataClientObject @@ -718,7 +719,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced)      LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;  	// Update the pixel area of all faces -    if (mDrawable.isNull()) +    if (mDrawable.isNull() || gCubeSnapshot)      {          return;      } @@ -3388,6 +3389,11 @@ F32 LLVOVolume::getSpotLightPriority() const  void LLVOVolume::updateSpotLightPriority()  { +    if (gCubeSnapshot) +    { +        return; +    } +      F32 r = getLightRadius();  	LLVector3 pos = mDrawable->getPositionAgent(); @@ -5497,6 +5503,8 @@ static inline void add_face(T*** list, U32* count, T* face)  void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; +    llassert(!gCubeSnapshot); +  	if (group->changeLOD())  	{  		group->mLastUpdateDistance = group->mDistance; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 8abb49fba8..8837038d02 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -820,7 +820,7 @@ void LLWorld::updateNetStats()  void LLWorld::printPacketsLost()  { -	LL_INFOS() << "Simulators:" << LL_ENDL; +	LL_INFOS() << "Simulators:" << LL_ENDL;   	LL_INFOS() << "----------" << LL_ENDL;  	LLCircuitData *cdp = NULL; @@ -855,6 +855,7 @@ F32 LLWorld::getLandFarClip() const  void LLWorld::setLandFarClip(const F32 far_clip)  { +    LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;  	static S32 const rwidth = (S32)REGION_WIDTH_U32;  	S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth;  	S32 const n2 = (llceil(far_clip) - 1) / rwidth; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index ef616f5d83..5eb9817fc4 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -227,6 +227,7 @@ extern S32 gBoxFrame;  //extern BOOL gHideSelectedObjects;  extern BOOL gDisplaySwapBuffers;  extern BOOL gDebugGL; +extern BOOL gCubeSnapshot;  bool	gAvatarBacklight = false; @@ -2006,6 +2007,7 @@ void LLPipeline::updateMove()  //static  F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera)  { +    llassert(!gCubeSnapshot); // shouldn't be doing ANY of this during cube snap shots  	LLVector3 lookAt = center - camera.getOrigin();  	F32 dist = lookAt.length(); @@ -2475,7 +2477,7 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)  	group->setVisible(); -	if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) +	if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot)  	{  		group->updateDistance(camera);  	} @@ -2581,6 +2583,8 @@ void LLPipeline::downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& d  void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space)  { +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; +    llassert(!gCubeSnapshot);  	downsampleDepthBuffer(source, dest, scratch_space);  	dest.bindTarget();  	doOcclusion(camera); @@ -2823,7 +2827,7 @@ void LLPipeline::rebuildPriorityGroups()  void LLPipeline::rebuildGroups()  { -	if (mGroupQ2.empty()) +	if (mGroupQ2.empty() || gCubeSnapshot)  	{  		return;  	} @@ -2873,6 +2877,10 @@ void LLPipeline::updateGeom(F32 max_dtime)  	LLPointer<LLDrawable> drawablep;  	LL_RECORD_BLOCK_TIME(FTM_GEO_UPDATE); +    if (gCubeSnapshot) +    { +        return; +    }  	assertInitialized(); @@ -3112,6 +3120,8 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)  		}  	} +    mReflectionMapManager.shift(offseta); +  	LLHUDText::shiftAll(offset);  	LLHUDNameTag::shiftAll(offset); @@ -3292,7 +3302,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)  		}  	} -	if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) +	if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot)  	{  		LLSpatialGroup* last_group = NULL;  		BOOL fov_changed = LLViewerCamera::getInstance()->isDefaultFOVChanged(); @@ -3374,7 +3384,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)  			stateSort(drawablep, camera);  		} -		if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) +		if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot)  		{ //avoid redundant stateSort calls  			group->mLastUpdateDistance = group->mDistance;  		} @@ -3443,7 +3453,7 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)  		}  	} -	if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) +	if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot)  	{  		//if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here  		{ @@ -3721,21 +3731,26 @@ void LLPipeline::postSort(LLCamera& camera)  	assertInitialized();  	LL_PUSH_CALLSTACKS(); -	//rebuild drawable geometry -	for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) -	{ -		LLSpatialGroup* group = *i; -		if (!sUseOcclusion ||  -			!group->isOcclusionState(LLSpatialGroup::OCCLUDED)) -		{ -			group->rebuildGeom(); -		} -	} -	LL_PUSH_CALLSTACKS(); -	//rebuild groups -	sCull->assertDrawMapsEmpty(); -	rebuildPriorityGroups(); +    if (!gCubeSnapshot) +    { +        //rebuild drawable geometry +        for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) +        { +            LLSpatialGroup* group = *i; +            if (!sUseOcclusion || +                !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) +            { +                group->rebuildGeom(); +            } +        } +        LL_PUSH_CALLSTACKS(); +        //rebuild groups +        sCull->assertDrawMapsEmpty(); + +        rebuildPriorityGroups(); +    } +  	LL_PUSH_CALLSTACKS(); @@ -3751,7 +3766,7 @@ void LLPipeline::postSort(LLCamera& camera)  			continue;  		} -		if (group->hasState(LLSpatialGroup::NEW_DRAWINFO) && group->hasState(LLSpatialGroup::GEOM_DIRTY)) +		if (group->hasState(LLSpatialGroup::NEW_DRAWINFO) && group->hasState(LLSpatialGroup::GEOM_DIRTY) && !gCubeSnapshot)  		{ //no way this group is going to be drawable without a rebuild  			group->rebuildGeom();  		} @@ -3769,7 +3784,7 @@ void LLPipeline::postSort(LLCamera& camera)                  LLDrawInfo* info = *k;  				sCull->pushDrawInfo(j->first, info); -                if (!sShadowRender && !sReflectionRender) +                if (!sShadowRender && !sReflectionRender && !gCubeSnapshot)                  {                      touchTextures(info);                      addTrianglesDrawn(info->mCount, info->mDrawMode); @@ -3784,7 +3799,7 @@ void LLPipeline::postSort(LLCamera& camera)  			if (alpha != group->mDrawMap.end())  			{ //store alpha groups for sorting  				LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); -				if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) +				if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot)  				{  					if (bridge)  					{ @@ -4411,7 +4426,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)  		gGL.loadMatrix(gGLModelView);  		if (occlude) -		{ +		{ // catch uncommon condition where pools at drawpool grass and later are disabled  			occlude = false;  			gGLLastMatrix = NULL;  			gGL.loadMatrix(gGLModelView); @@ -4607,6 +4622,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)  		if (occlude && cur_type >= LLDrawPool::POOL_GRASS)  		{ +            llassert(!gCubeSnapshot); // never do occlusion culling on cube snapshots  			occlude = false;  			gGLLastMatrix = NULL;  			gGL.loadMatrix(gGLModelView); @@ -5925,6 +5941,7 @@ void LLPipeline::setupAvatarLights(bool for_edit)  static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist)  { +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;  	F32 inten = light->getLightIntensity();  	if (inten < .001f)  	{ @@ -5948,9 +5965,10 @@ static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_  void LLPipeline::calcNearbyLights(LLCamera& camera)  { +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;  	assertInitialized(); -	if (LLPipeline::sReflectionRender) +	if (LLPipeline::sReflectionRender || gCubeSnapshot)  	{  		return;  	} @@ -6133,6 +6151,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera)  void LLPipeline::setupHWLights(LLDrawPool* pool)  { +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;  	assertInitialized();      LLEnvironment& environment = LLEnvironment::instance(); @@ -7608,7 +7627,8 @@ void LLPipeline::renderFinalize()          bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() &&                             (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) && -                           RenderDepthOfField; +                           RenderDepthOfField && +                            !gCubeSnapshot;          bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete(); @@ -8196,45 +8216,13 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_  		}  	} -    channel = shader.enableTexture(LLShaderMgr::REFLECTION_MAP, LLTexUnit::TT_CUBE_MAP); -    if (channel > -1) +    channel = shader.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); +    if (channel > -1 && mReflectionMapManager.mTexture.notNull())      { -        mReflectionMaps.resize(8); //TODO -- declare the number of reflection maps the shader knows about somewhere sane -        mReflectionMapManager.getReflectionMaps(mReflectionMaps); -        LLVector3 origin[8]; //origin of refmaps in clip space - -        // load modelview matrix into matrix 4a -        LLMatrix4a modelview; -        modelview.loadu(gGLModelView); -        LLVector4a oa; // scratch space for transformed origin - -        S32 count = 0; -        for (auto* refmap : mReflectionMaps) -        { -            if (refmap) -            { -                LLCubeMap* cubemap = refmap->mCubeMap; -                if (cubemap) -                { -                    cubemap->enable(channel + count); -                    cubemap->bind(); - -                    modelview.affineTransform(refmap->mOrigin, oa); -                    origin[count].set(oa.getF32ptr()); - -                    count++; -                } -            } -        } - -        if (count > 0) -        { -            LLStaticHashedString refmapCount("refmapCount"); -            LLStaticHashedString refOrigin("refOrigin"); -            shader.uniform1i(refmapCount, count); -            shader.uniform3fv(refOrigin, count, (F32*)origin); -            setup_env_mat = true; -        } +        // see comments in class2/deferred/softenLightF.glsl for what these uniforms mean +        mReflectionMapManager.mTexture->bind(channel); +        mReflectionMapManager.setUniforms(); +        setup_env_mat = true;      }      if (setup_env_mat) @@ -8276,7 +8264,14 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_          }      } -	shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV); +    /*if (gCubeSnapshot) +    { // we only really care about the first two values, but the shader needs increasing separation between clip planes +        shader.uniform4f(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1.f, 64.f, 128.f, 256.f); +    } +    else*/ +    { +        shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV); +    }  	shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash);  	shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise);  	shader.uniform1f(LLShaderMgr::DEFERRED_BLUR_SIZE, RenderShadowBlurSize); @@ -8469,66 +8464,78 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)          }          if (RenderDeferredSSAO) -        {  // soften direct lighting lightmap -            LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow"); -            // blur lightmap -            screen_target->bindTarget(); -            glClearColor(1, 1, 1, 1); -            screen_target->clear(GL_COLOR_BUFFER_BIT); -            glClearColor(0, 0, 0, 0); - -            bindDeferredShader(gDeferredBlurLightProgram); -            mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); -            LLVector3 go          = RenderShadowGaussian; -            const U32 kern_length = 4; -            F32       blur_size   = RenderShadowBlurSize; -            F32       dist_factor = RenderShadowBlurDistFactor; - -            // sample symmetrically with the middle sample falling exactly on 0.0 -            F32 x = 0.f; - -            LLVector3 gauss[32];  // xweight, yweight, offset - -            for (U32 i = 0; i < kern_length; i++) -            { -                gauss[i].mV[0] = llgaussian(x, go.mV[0]); -                gauss[i].mV[1] = llgaussian(x, go.mV[1]); -                gauss[i].mV[2] = x; -                x += 1.f; +        { +            /*if (gCubeSnapshot) +            { // SSAO and shadows disabled in reflection maps +                deferred_light_target->bindTarget(); +                glClearColor(1, 1, 1, 1); +                deferred_light_target->clear(); +                glClearColor(0, 0, 0, 0); +                deferred_light_target->flush();              } +            else*/ +            { +                // soften direct lighting lightmap +                LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow"); +                // blur lightmap +                screen_target->bindTarget(); +                glClearColor(1, 1, 1, 1); +                screen_target->clear(GL_COLOR_BUFFER_BIT); +                glClearColor(0, 0, 0, 0); -            gDeferredBlurLightProgram.uniform2f(sDelta, 1.f, 0.f); -            gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor); -            gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV); -            gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f)); +                bindDeferredShader(gDeferredBlurLightProgram); +                mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); +                LLVector3 go = RenderShadowGaussian; +                const U32 kern_length = 4; +                F32       blur_size = RenderShadowBlurSize; +                F32       dist_factor = RenderShadowBlurDistFactor; -            { -                LLGLDisable   blend(GL_BLEND); -                LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); -                stop_glerror(); -                mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); -                stop_glerror(); -            } +                // sample symmetrically with the middle sample falling exactly on 0.0 +                F32 x = 0.f; + +                LLVector3 gauss[32];  // xweight, yweight, offset -            screen_target->flush(); -            unbindDeferredShader(gDeferredBlurLightProgram); +                for (U32 i = 0; i < kern_length; i++) +                { +                    gauss[i].mV[0] = llgaussian(x, go.mV[0]); +                    gauss[i].mV[1] = llgaussian(x, go.mV[1]); +                    gauss[i].mV[2] = x; +                    x += 1.f; +                } -            bindDeferredShader(gDeferredBlurLightProgram, screen_target); +                gDeferredBlurLightProgram.uniform2f(sDelta, 1.f, 0.f); +                gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor); +                gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV); +                gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f)); -            mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); -            deferred_light_target->bindTarget(); +                { +                    LLGLDisable   blend(GL_BLEND); +                    LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); +                    stop_glerror(); +                    mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); +                    stop_glerror(); +                } -            gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f); +                screen_target->flush(); +                unbindDeferredShader(gDeferredBlurLightProgram); -            { -                LLGLDisable   blend(GL_BLEND); -                LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); -                stop_glerror(); -                mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); -                stop_glerror(); +                bindDeferredShader(gDeferredBlurLightProgram, screen_target); + +                mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); +                deferred_light_target->bindTarget(); + +                gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f); + +                { +                    LLGLDisable   blend(GL_BLEND); +                    LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); +                    stop_glerror(); +                    mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); +                    stop_glerror(); +                } +                deferred_light_target->flush(); +                unbindDeferredShader(gDeferredBlurLightProgram);              } -            deferred_light_target->flush(); -            unbindDeferredShader(gDeferredBlurLightProgram);          }          stop_glerror(); @@ -8595,7 +8602,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)              gPipeline.popRenderTypeMask();          } -        bool render_local = RenderLocalLights; +        bool render_local = RenderLocalLights; // && !gCubeSnapshot;          if (render_local)          { @@ -8604,9 +8611,12 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)              LLDrawable::drawable_list_t spot_lights;              LLDrawable::drawable_list_t fullscreen_spot_lights; -            for (U32 i = 0; i < 2; i++) +            if (!gCubeSnapshot)              { -                mTargetShadowSpotLight[i] = NULL; +                for (U32 i = 0; i < 2; i++) +                { +                    mTargetShadowSpotLight[i] = NULL; +                }              }              std::list<LLVector4> light_colors; @@ -8942,6 +8952,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)          popRenderTypeMask();      } +    if (!gCubeSnapshot)      {          // render highlights, etc.          renderHighlights(); @@ -9053,6 +9064,7 @@ void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)  		shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f);  	} +    if (!gCubeSnapshot)  	{  		LLDrawable* potential = drawablep;  		//determine if this is a good light for casting shadows @@ -9146,14 +9158,10 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)  		}  	} -    channel = shader.disableTexture(LLShaderMgr::REFLECTION_MAP, LLTexUnit::TT_CUBE_MAP); -    if (channel > -1) +    channel = shader.disableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP); +    if (channel > -1 && mReflectionMapManager.mTexture.notNull())      { -        for (int i = 0; i < mReflectionMaps.size(); ++i) -        { -            gGL.getTexUnit(channel + i)->disable(); -        } - +        mReflectionMapManager.mTexture->unbind();          if (channel == 0)          {              gGL.getTexUnit(channel)->enable(LLTexUnit::TT_TEXTURE); @@ -9176,7 +9184,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; -    if (!assertInitialized()) +    if (!assertInitialized() || gCubeSnapshot)      {          return;      } @@ -9767,7 +9775,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera      LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID - 1]; -    doOcclusion(shadow_cam, occlusion_source, occlusion_target); +    if (occlude > 1) +    { +        doOcclusion(shadow_cam, occlusion_source, occlusion_target); +    }      if (use_shader)      { @@ -10163,6 +10174,12 @@ void LLPipeline::generateSunShadow(LLCamera& camera)  	clip = RenderShadowOrthoClipPlanes;  	mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]); +    //if (gCubeSnapshot) +    { //always do a single 64m shadow in reflection maps +        mSunClipPlanes.set(64.f, 128.f, 256.f); +        mSunOrthoClipPlanes.set(64.f, 128.f, 256.f); +    } +  	//currently used for amount to extrude frusta corners for constructing shadow frusta  	//LLVector3 n = RenderShadowNearDist;  	//F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] }; @@ -10279,9 +10296,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera)  	// convenience array of 4 near clip plane distances  	F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] }; -  	if (mSunDiffuse == LLColor4::black) -	{ //sun diffuse is totally black, shadows don't matter +	{ //sun diffuse is totally shadows don't matter  		LLGLDepthTest depth(GL_TRUE);  		for (S32 j = 0; j < 4; j++) @@ -10293,7 +10309,21 @@ void LLPipeline::generateSunShadow(LLCamera& camera)  	}  	else  	{ -		for (S32 j = 0; j < 4; j++) +        /*if (gCubeSnapshot) +        { +            // do one shadow split for cube snapshots, clear the rest +            mSunClipPlanes.set(64.f, 64.f, 64.f); +            dist[1] = dist[2] = dist[3] = dist[4] = 64.f; +            for (S32 j = 1; j < 4; j++) +            { +                mShadow[j].bindTarget(); +                mShadow[j].clear(); +                mShadow[j].flush(); +            } +        }*/ + +		//for (S32 j = 0; j < (gCubeSnapshot ? 1 : 4); j++) +        for (S32 j = 0; j < 4; j++)  		{  			if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))  			{ @@ -10672,142 +10702,145 @@ void LLPipeline::generateSunShadow(LLCamera& camera)  	if (gen_shadow)  	{ -		LLTrace::CountStatHandle<>* velocity_stat = LLViewerCamera::getVelocityStat(); -		F32 fade_amt = gFrameIntervalSeconds.value()  -			* llmax(LLTrace::get_frame_recording().getLastRecording().getSum(*velocity_stat) / LLTrace::get_frame_recording().getLastRecording().getDuration().value(), 1.0); - -		//update shadow targets -		for (U32 i = 0; i < 2; i++) -		{ //for each current shadow -			LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW4+i); - -			if (mShadowSpotLight[i].notNull() &&  -				(mShadowSpotLight[i] == mTargetShadowSpotLight[0] || -				mShadowSpotLight[i] == mTargetShadowSpotLight[1])) -			{ //keep this spotlight -				mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f); -			} -			else -			{ //fade out this light -				mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f); +        if (!gCubeSnapshot) //skip updating spot shadow maps during cubemap updates +        { +		    LLTrace::CountStatHandle<>* velocity_stat = LLViewerCamera::getVelocityStat(); +		    F32 fade_amt = gFrameIntervalSeconds.value()  +			    * llmax(LLTrace::get_frame_recording().getLastRecording().getSum(*velocity_stat) / LLTrace::get_frame_recording().getLastRecording().getDuration().value(), 1.0); + +		    //update shadow targets +		    for (U32 i = 0; i < 2; i++) +		    { //for each current shadow +			    LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW4+i); + +			    if (mShadowSpotLight[i].notNull() &&  +				    (mShadowSpotLight[i] == mTargetShadowSpotLight[0] || +				    mShadowSpotLight[i] == mTargetShadowSpotLight[1])) +			    { //keep this spotlight +				    mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f); +			    } +			    else +			    { //fade out this light +				    mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f); -				if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull()) -				{ //faded out, grab one of the pending spots (whichever one isn't already taken) -					if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2]) -					{ -						mShadowSpotLight[i] = mTargetShadowSpotLight[0]; -					} -					else -					{ -						mShadowSpotLight[i] = mTargetShadowSpotLight[1]; -					} -				} -			} -		} +				    if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull()) +				    { //faded out, grab one of the pending spots (whichever one isn't already taken) +					    if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2]) +					    { +						    mShadowSpotLight[i] = mTargetShadowSpotLight[0]; +					    } +					    else +					    { +						    mShadowSpotLight[i] = mTargetShadowSpotLight[1]; +					    } +				    } +			    } +		    } + +            for (S32 i = 0; i < 2; i++) +            { +                set_current_modelview(saved_view); +                set_current_projection(saved_proj); -		for (S32 i = 0; i < 2; i++) -		{ -			set_current_modelview(saved_view); -			set_current_projection(saved_proj); +                if (mShadowSpotLight[i].isNull()) +                { +                    continue; +                } -			if (mShadowSpotLight[i].isNull()) -			{ -				continue; -			} +                LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume(); -			LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume(); +                if (!volume) +                { +                    mShadowSpotLight[i] = NULL; +                    continue; +                } -			if (!volume) -			{ -				mShadowSpotLight[i] = NULL; -				continue; -			} +                LLDrawable* drawable = mShadowSpotLight[i]; -			LLDrawable* drawable = mShadowSpotLight[i]; +                LLVector3 params = volume->getSpotLightParams(); +                F32 fov = params.mV[0]; -			LLVector3 params = volume->getSpotLightParams(); -			F32 fov = params.mV[0]; +                //get agent->light space matrix (modelview) +                LLVector3 center = drawable->getPositionAgent(); +                LLQuaternion quat = volume->getRenderRotation(); -			//get agent->light space matrix (modelview) -			LLVector3 center = drawable->getPositionAgent(); -			LLQuaternion quat = volume->getRenderRotation(); +                //get near clip plane +                LLVector3 scale = volume->getScale(); +                LLVector3 at_axis(0, 0, -scale.mV[2] * 0.5f); +                at_axis *= quat; -			//get near clip plane -			LLVector3 scale = volume->getScale(); -			LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); -			at_axis *= quat; +                LLVector3 np = center + at_axis; +                at_axis.normVec(); -			LLVector3 np = center+at_axis; -			at_axis.normVec(); +                //get origin that has given fov for plane np, at_axis, and given scale +                F32 dist = (scale.mV[1] * 0.5f) / tanf(fov * 0.5f); -			//get origin that has given fov for plane np, at_axis, and given scale -			F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); +                LLVector3 origin = np - at_axis * dist; -			LLVector3 origin = np - at_axis*dist; +                LLMatrix4 mat(quat, LLVector4(origin, 1.f)); -			LLMatrix4 mat(quat, LLVector4(origin, 1.f)); +                view[i + 4] = glh::matrix4f((F32*)mat.mMatrix); -			view[i+4] = glh::matrix4f((F32*) mat.mMatrix); +                view[i + 4] = view[i + 4].inverse(); -			view[i+4] = view[i+4].inverse(); +                //get perspective matrix +                F32 near_clip = dist + 0.01f; +                F32 width = scale.mV[VX]; +                F32 height = scale.mV[VY]; +                F32 far_clip = dist + volume->getLightRadius() * 1.5f; -			//get perspective matrix -			F32 near_clip = dist+0.01f; -			F32 width = scale.mV[VX]; -			F32 height = scale.mV[VY]; -			F32 far_clip = dist+volume->getLightRadius()*1.5f; +                F32 fovy = fov * RAD_TO_DEG; +                F32 aspect = width / height; -			F32 fovy = fov * RAD_TO_DEG; -			F32 aspect = width/height; -			 -			proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip); +                proj[i + 4] = gl_perspective(fovy, aspect, near_clip, far_clip); -			//translate and scale to from [-1, 1] to [0, 1] -			glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, -							0.f, 0.5f, 0.f, 0.5f, -							0.f, 0.f, 0.5f, 0.5f, -							0.f, 0.f, 0.f, 1.f); +                //translate and scale to from [-1, 1] to [0, 1] +                glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, +                    0.f, 0.5f, 0.f, 0.5f, +                    0.f, 0.f, 0.5f, 0.5f, +                    0.f, 0.f, 0.f, 1.f); -			set_current_modelview(view[i+4]); -			set_current_projection(proj[i+4]); +                set_current_modelview(view[i + 4]); +                set_current_projection(proj[i + 4]); -			mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view; -			 -			for (U32 j = 0; j < 16; j++) -			{ -				gGLLastModelView[j] = mShadowModelview[i+4].m[j]; -				gGLLastProjection[j] = mShadowProjection[i+4].m[j]; -			} +                mSunShadowMatrix[i + 4] = trans * proj[i + 4] * view[i + 4] * inv_view; -			mShadowModelview[i+4] = view[i+4]; -			mShadowProjection[i+4] = proj[i+4]; +                for (U32 j = 0; j < 16; j++) +                { +                    gGLLastModelView[j] = mShadowModelview[i + 4].m[j]; +                    gGLLastProjection[j] = mShadowProjection[i + 4].m[j]; +                } -			LLCamera shadow_cam = camera; -			shadow_cam.setFar(far_clip); -			shadow_cam.setOrigin(origin); +                mShadowModelview[i + 4] = view[i + 4]; +                mShadowProjection[i + 4] = proj[i + 4]; -			LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); +                LLCamera shadow_cam = camera; +                shadow_cam.setFar(far_clip); +                shadow_cam.setOrigin(origin); -			stop_glerror(); +                LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); -			mShadow[i+4].bindTarget(); -			mShadow[i+4].getViewport(gGLViewport); -			mShadow[i+4].clear(); +                stop_glerror(); + +                mShadow[i + 4].bindTarget(); +                mShadow[i + 4].getViewport(gGLViewport); +                mShadow[i + 4].clear(); -			U32 target_width = mShadow[i+4].getWidth(); +                U32 target_width = mShadow[i + 4].getWidth(); -			static LLCullResult result[2]; +                static LLCullResult result[2]; -			LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW0 + i + 4); +                LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW0 + i + 4); -            RenderSpotLight = drawable;             +                RenderSpotLight = drawable; -			renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE, target_width); +                renderShadow(view[i + 4], proj[i + 4], shadow_cam, result[i], FALSE, FALSE, target_width); -            RenderSpotLight = nullptr; +                RenderSpotLight = nullptr; -			mShadow[i+4].flush(); - 		} +                mShadow[i + 4].flush(); +            } +        }  	}  	else  	{ //no spotlight shadows @@ -11526,7 +11559,7 @@ void LLPipeline::restoreHiddenObject( const LLUUID& id )  void LLPipeline::overrideEnvironmentMap()  { -    mReflectionMapManager.mProbes.clear(); -    mReflectionMapManager.addProbe(LLViewerCamera::instance().getOrigin()); +    //mReflectionMapManager.mProbes.clear(); +    //mReflectionMapManager.addProbe(LLViewerCamera::instance().getOrigin());  } diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 975380929d..88eaca558a 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -578,7 +578,8 @@ public:  		RENDER_DEBUG_ATTACHMENT_BYTES	=  0x20000000, // not used  		RENDER_DEBUG_TEXEL_DENSITY		=  0x40000000,  		RENDER_DEBUG_TRIANGLE_COUNT		=  0x80000000, -		RENDER_DEBUG_IMPOSTORS			= 0x100000000 +		RENDER_DEBUG_IMPOSTORS			= 0x100000000, +        RENDER_DEBUG_REFLECTION_PROBES  = 0x200000000  	};  public: diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index db4e794ed4..0b0f8e17bc 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2912,6 +2912,16 @@ function="World.EnvPreset"             parameter="lights" />          </menu_item_check>          <menu_item_check +         label="Reflection Probes" +         name="Reflection Probes"> +          <menu_item_check.on_check +           function="Advanced.CheckInfoDisplay" +           parameter="reflection probes" /> +          <menu_item_check.on_click +           function="Advanced.ToggleInfoDisplay" +           parameter="reflection probes" /> +        </menu_item_check> +        <menu_item_check           label="Particles"           name="Particles">            <menu_item_check.on_check @@ -3252,10 +3262,10 @@ function="World.EnvPreset"              </menu_item_check>              <menu_item_call                enabled="true" -              label="Override Environment Map" -              name="Override Environment Map"> +              label="Rebuild Reflection Probes" +              name="Rebuild Reflection Probes">                <menu_item_call.on_click -               function="Develop.OverrideEnvironmentMap" /> +               function="Develop.RebuildReflectionProbes" />              </menu_item_call>            <menu_item_separator /> | 
