From 3400e5fd302c0d9dea6386c4d5bf38876f2cc287 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Mon, 16 May 2022 17:21:08 +0000
Subject: SL-17284 Reflection probe tuning and optimization take 1

---
 indra/llrender/CMakeLists.txt     |   2 +
 indra/llrender/llcubemap.cpp      |  10 +++-
 indra/llrender/llcubemaparray.cpp | 113 ++++++++++++++++++++++++++++++++++++++
 indra/llrender/llcubemaparray.h   |  60 ++++++++++++++++++++
 indra/llrender/llgl.cpp           |  33 ++++++++++-
 indra/llrender/llgl.h             |   1 +
 indra/llrender/llglheaders.h      |   9 +++
 indra/llrender/llglslshader.cpp   |  61 +++++++++++++++++++-
 indra/llrender/llglslshader.h     |   3 +
 indra/llrender/llimagegl.cpp      |  51 ++++++++++-------
 indra/llrender/llrender.cpp       |   4 ++
 indra/llrender/llrender.h         |   3 +-
 indra/llrender/llshadermgr.cpp    |  13 ++++-
 indra/llrender/llshadermgr.h      |   2 +-
 14 files changed, 334 insertions(+), 31 deletions(-)
 create mode 100644 indra/llrender/llcubemaparray.cpp
 create mode 100644 indra/llrender/llcubemaparray.h

(limited to 'indra/llrender')

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"
-- 
cgit v1.2.3