diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
index 9b42f0df5c94f97577ef9ec4ba5beaa2e93e5709..bc631afd1ded644b498935bffc513785e2551e11 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
@@ -47,7 +47,11 @@ layout (std140) uniform ReflectionProbes
     mat4 refBox[MAX_REFMAP_COUNT];
     // list of bounding spheres for reflection probes sorted by distance to camera (closest first)
     vec4 refSphere[MAX_REFMAP_COUNT];
-    // extra parameters (currently only .x used for probe ambiance)
+    // extra parameters 
+    //  x - irradiance scale
+    //  y - radiance scale
+    //  z - fade in
+    //  w - znear
     vec4 refParams[MAX_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]
@@ -60,6 +64,8 @@ layout (std140) uniform ReflectionProbes
     // neighbor list data (refSphere indices, not cubemap array layer)
     ivec4 refNeighbor[1024];
 
+    ivec4 refBucket[256];
+
     // number of reflection probes present in refSphere
     int refmapCount;
 };
@@ -118,13 +124,26 @@ bool shouldSampleProbe(int i, vec3 pos)
     return true;
 }
 
+int getStartIndex(vec3 pos)
+{
+#if 1
+    int idx = clamp(int(floor(-pos.z)), 0, 255);
+    return clamp(refBucket[idx].x, 1, refmapCount+1);
+#else
+    return 1;
+#endif
+}
+
 // call before sampleRef
 // populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT
 void preProbeSample(vec3 pos)
 {
 #if REFMAP_LEVEL > 0
+
+    int start = getStartIndex(pos);
+
     // TODO: make some sort of structure that reduces the number of distance checks
-    for (int i = 1; i < refmapCount; ++i)
+    for (int i = start; i < refmapCount; ++i)
     {
         // found an influencing probe
         if (shouldSampleProbe(i, pos))
@@ -142,6 +161,7 @@ void preProbeSample(vec3 pos)
                 {
                     // check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index)
 
+                    // sample refNeighbor[neighborIdx].x
                     int idx = refNeighbor[neighborIdx].x;
                     if (shouldSampleProbe(idx, pos))
                     {
@@ -157,6 +177,7 @@ void preProbeSample(vec3 pos)
                         break;
                     }
 
+                    // sample refNeighbor[neighborIdx].y
                     idx = refNeighbor[neighborIdx].y;
                     if (shouldSampleProbe(idx, pos))
                     {
@@ -172,6 +193,7 @@ void preProbeSample(vec3 pos)
                         break;
                     }
 
+                    // sample refNeighbor[neighborIdx].z
                     idx = refNeighbor[neighborIdx].z;
                     if (shouldSampleProbe(idx, pos))
                     {
@@ -187,6 +209,7 @@ void preProbeSample(vec3 pos)
                         break;
                     }
 
+                    // sample refNeighbor[neighborIdx].w
                     idx = refNeighbor[neighborIdx].w;
                     if (shouldSampleProbe(idx, pos))
                     {
@@ -197,11 +220,7 @@ void preProbeSample(vec3 pos)
                         }
                     }
                     count++;
-                    if (count == neighborCount)
-                    {
-                        break;
-                    }
-
+                    
                     ++neighborIdx;
                 }
 
@@ -735,6 +754,14 @@ vec4 sampleReflectionProbesDebug(vec3 pos)
         debugTapRefMap(pos, dir, d, i, col);
     }
 
+#if 0 //debug getStartIndex
+    col.g = float(getStartIndex(pos));
+
+    col.g /= 255.0;
+    col.rb = vec2(0);
+    col.a = 1.0;
+#endif
+
     return col;
 }
 
diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h
index 803f7bdc97dd312666987519de9429784adaf348..7ea0fe6187ca448c9ff2c29ef4d8b5f182d658de 100644
--- a/indra/newview/llreflectionmap.h
+++ b/indra/newview/llreflectionmap.h
@@ -78,8 +78,12 @@ class alignas(16) LLReflectionMap : public LLRefCount
     // point at which environment map was last generated from (in agent space)
     LLVector4a mOrigin;
     
-    // distance from viewer camera
-    F32 mDistance;
+    // distance from main viewer camera
+    F32 mDistance = -1.f;
+
+    // Minimum and maximum depth in current render camera
+    F32 mMinDepth = -1.f;
+    F32 mMaxDepth = -1.f;
 
     // radius of this probe's affected area
     F32 mRadius = 16.f;
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index 88edbc9224348da20742e48e17dce65145a4963f..2235453e470657ed14092ee30f29f96b78d3a04b 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -45,10 +45,13 @@ extern U32 nhpo2(U32 v);
 
 static void touch_default_probe(LLReflectionMap* probe)
 {
-    LLVector3 origin = LLViewerCamera::getInstance()->getOrigin();
-    origin.mV[2] += 64.f;
+    if (LLViewerCamera::getInstance())
+    {
+        LLVector3 origin = LLViewerCamera::getInstance()->getOrigin();
+        origin.mV[2] += 64.f;
 
-    probe->mOrigin.load3(origin.mV);
+        probe->mOrigin.load3(origin.mV);
+    }
 }
 
 LLReflectionMapManager::LLReflectionMapManager()
@@ -58,17 +61,17 @@ LLReflectionMapManager::LLReflectionMapManager()
 
 void LLReflectionMapManager::initCubeFree()
 {
+    // start at 1 because index 0 is reserved for mDefaultProbe
     for (int i = 1; i < LL_MAX_REFLECTION_PROBE_COUNT; ++i)
     {
-        mCubeFree[i] = true;
+        mCubeFree.push_back(i);
     }
-
-    // cube index 0 is reserved for the fallback probe
-    mCubeFree[0] = false;
 }
 
 struct CompareProbeDistance
 {
+    LLReflectionMap* mDefaultProbe;
+
     bool operator()(const LLPointer<LLReflectionMap>& lhs, const LLPointer<LLReflectionMap>& rhs)
     {
         return lhs->mDistance < rhs->mDistance;
@@ -83,7 +86,15 @@ static F32 update_score(LLReflectionMap* p)
 // return true if a is higher priority for an update than b
 static bool check_priority(LLReflectionMap* a, LLReflectionMap* b)
 {
-    if (!a->mComplete && !b->mComplete)
+    if (a->mCubeIndex == -1)
+    { // not a candidate for updating
+        return false;
+    }
+    else if (b->mCubeIndex == -1)
+    { // certainly higher priority than b
+        return true;
+    }
+    else if (!a->mComplete && !b->mComplete)
     { //neither probe is complete, use distance
         return a->mDistance < b->mDistance;
     }
@@ -133,14 +144,7 @@ void LLReflectionMapManager::update()
         }
     }
 
-
-    if (mDefaultProbe.isNull())
-    {
-        mDefaultProbe = addProbe();
-        mDefaultProbe->mDistance = -4096.f; // hack to make sure the default probe is always first in sort order
-        mDefaultProbe->mRadius = 4096.f;
-        touch_default_probe(mDefaultProbe);
-    }
+    llassert(mProbes[0] == mDefaultProbe);
     
     LLVector4a camera_pos;
     camera_pos.load3(LLViewerCamera::instance().getOrigin().mV);
@@ -170,6 +174,7 @@ void LLReflectionMapManager::update()
         return;
     }
 
+
     bool did_update = false;
     
     static LLCachedControl<S32> sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1);
@@ -188,7 +193,46 @@ void LLReflectionMapManager::update()
         doProbeUpdate();
     }
 
-    //LL_INFOS() << mProbes.size() << LL_ENDL;
+    // update distance to camera for all probes
+    std::sort(mProbes.begin()+1, mProbes.end(), CompareProbeDistance());
+    llassert(mProbes[0] == mDefaultProbe);
+    llassert(mProbes[0]->mCubeArray == mTexture);
+    llassert(mProbes[0]->mCubeIndex == 0);
+
+    // make sure we're assigning cube slots to the closest probes
+
+    // first free any cube indices for distant probes
+    for (U32 i = mReflectionProbeCount; i < mProbes.size(); ++i)
+    {
+        LLReflectionMap* probe = mProbes[i];
+        llassert(probe != nullptr);
+
+        if (probe->mCubeIndex != -1 && mUpdatingProbe != probe)
+        { // free this index
+            mCubeFree.push_back(probe->mCubeIndex);
+
+            probe->mCubeArray = nullptr;
+            probe->mCubeIndex = -1;
+            probe->mComplete = false;
+        }
+    }
+
+    // next distribute the free indices
+    U32 count = llmin(mReflectionProbeCount, (U32)mProbes.size());
+
+    for (S32 i = 1; i < count && !mCubeFree.empty(); ++i)
+    {
+        // find the closest probe that needs a cube index
+        LLReflectionMap* probe = mProbes[i];
+
+        if (probe->mCubeIndex == -1)
+        {
+            S32 idx = allocateCubeIndex();
+            llassert(idx > 0); //if we're still in this loop, mCubeFree should not be empty and allocateCubeIndex should be returning good indices
+            probe->mCubeArray = mTexture;
+            probe->mCubeIndex = idx;
+        }
+    }
 
     for (int i = 0; i < mProbes.size(); ++i)
     {
@@ -205,8 +249,6 @@ void LLReflectionMapManager::update()
             continue;
         }
 
-        probe->mProbeIndex = i;
-
         LLVector4a d;
 
         if (probe != mDefaultProbe)
@@ -219,6 +261,10 @@ void LLReflectionMapManager::update()
             // make default probe have a distance of 64m for the purposes of prioritization (if it's already been generated once)
             probe->mDistance = 64.f;
         }
+        else
+        {
+            probe->mDistance = -4096.f; //boost priority of default probe when it's not complete
+        }
 
         if (probe->mComplete)
         {
@@ -288,13 +334,8 @@ void LLReflectionMapManager::update()
     if (!did_update && oldestProbe != nullptr)
     {
         LLReflectionMap* probe = oldestProbe;
-        if (probe->mCubeIndex == -1)
-        {
-            probe->mCubeArray = mTexture;
-
-            probe->mCubeIndex = probe == mDefaultProbe ? 0 : allocateCubeIndex();
-        }
-
+        llassert(probe->mCubeIndex != -1);
+        
         probe->autoAdjustOrigin();
 
         mUpdatingProbe = probe;
@@ -307,10 +348,6 @@ void LLReflectionMapManager::update()
         oldestOccluded->autoAdjustOrigin();
         oldestOccluded->mLastUpdateTime = gFrameTimeSeconds;
     }
-
-    // update distance to camera for all probes
-    mDefaultProbe->mDistance = -4096.f; // make default probe always end up at index 0
-    std::sort(mProbes.begin(), mProbes.end(), CompareProbeDistance());
 }
 
 LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group)
@@ -318,6 +355,14 @@ LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group)
     LLReflectionMap* probe = new LLReflectionMap();
     probe->mGroup = group;
 
+    if (mDefaultProbe.isNull())
+    {  //safety check to make sure default probe is always first probe added
+        mDefaultProbe = new LLReflectionMap();
+        mProbes.push_back(mDefaultProbe);
+    }
+
+    llassert(mProbes[0] == mDefaultProbe);
+
     if (group)
     {
         probe->mOrigin = group->getOctreeNode()->getCenter();
@@ -335,10 +380,22 @@ LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group)
     return probe;
 }
 
+struct CompareProbeDepth
+{
+    bool operator()(const LLReflectionMap* lhs, const LLReflectionMap* rhs)
+    {
+        return lhs->mMinDepth < rhs->mMinDepth;
+    }
+};
+
 void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& maps)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
 
+    LLMatrix4a modelview;
+    modelview.loadu(gGLModelView);
+    LLVector4a oa; // scratch space for transformed origin
+
     U32 count = 0;
     U32 lastIdx = 0;
     for (U32 i = 0; count < maps.size() && i < mProbes.size(); ++i)
@@ -348,8 +405,10 @@ void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& ma
         {
             if (!mProbes[i]->mOccluded && mProbes[i]->mComplete)
             {
-                mProbes[i]->mProbeIndex = count;
                 maps[count++] = mProbes[i];
+                modelview.affineTransform(mProbes[i]->mOrigin, oa);
+                mProbes[i]->mMinDepth = -oa.getF32ptr()[2] - mProbes[i]->mRadius;
+                mProbes[i]->mMaxDepth = -oa.getF32ptr()[2] + mProbes[i]->mRadius;
             }
         }
         else
@@ -365,6 +424,16 @@ void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& ma
         mProbes[i]->mProbeIndex = -1;
     }
 
+    if (count > 1)
+    {
+        std::sort(maps.begin(), maps.begin() + count, CompareProbeDepth());
+    }
+
+    for (U32 i = 0; i < count; ++i)
+    {
+        maps[i]->mProbeIndex = i;
+    }
+
     // null terminate list
     if (count < maps.size())
     {
@@ -407,32 +476,15 @@ LLReflectionMap* LLReflectionMapManager::registerViewerObject(LLViewerObject* vo
     return probe;
 }
 
-
 S32 LLReflectionMapManager::allocateCubeIndex()
 {
-    for (int i = 0; i < mReflectionProbeCount; ++i)
+    if (!mCubeFree.empty())
     {
-        if (mCubeFree[i])
-        {
-            mCubeFree[i] = false;
-            return i;
-        }
+        S32 ret = mCubeFree.front();
+        mCubeFree.pop_front();
+        return ret;
     }
 
-    // no cubemaps free, steal one from the back of the probe list
-    for (int i = mProbes.size() - 1; i >= mReflectionProbeCount; --i)
-    {
-        if (mProbes[i]->mCubeIndex != -1)
-        {
-            S32 ret = mProbes[i]->mCubeIndex;
-            mProbes[i]->mCubeIndex = -1;
-            mProbes[i]->mCubeArray = nullptr;
-            mProbes[i]->mComplete = false;
-            return ret;
-        }
-    }
-
-    llassert(false); // should never fail to allocate, something is probably wrong with mCubeFree
     return -1;
 }
 
@@ -445,7 +497,7 @@ void LLReflectionMapManager::deleteProbe(U32 i)
 
     if (probe->mCubeIndex != -1)
     { // mark the cube index used by this probe as being free
-        mCubeFree[probe->mCubeIndex] = true;
+        mCubeFree.push_back(probe->mCubeIndex);
     }
     if (mUpdatingProbe == probe)
     {
@@ -776,13 +828,14 @@ void LLReflectionMapManager::updateNeighbors(LLReflectionMap* probe)
     }
 
     // search for new neighbors
+    if (probe->isRelevant())
     {
         LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - search");
         for (auto& other : mProbes)
         {
             if (other != mDefaultProbe && other != probe)
             {
-                if (probe->intersects(other))
+                if (other->isRelevant() && probe->intersects(other))
                 {
                     probe->mNeighbors.push_back(other);
                     other->mNeighbors.push_back(probe);
@@ -816,6 +869,7 @@ void LLReflectionMapManager::updateUniforms()
         //  x - irradiance scale
         //  y - radiance scale
         //  z - fade in
+        //  w - znear
         LLVector4 refParams[LL_MAX_REFLECTION_PROBE_COUNT];
 
         // indices used by probe:
@@ -828,6 +882,7 @@ void LLReflectionMapManager::updateUniforms()
         // list of neighbor indices
         GLint refNeighbor[4096]; 
 
+        GLint refBucket[256][4]; //lookup table for which index to start with for the given Z depth
         // numbrer of active refmaps
         GLint refmapCount;  
     };
@@ -837,6 +892,17 @@ void LLReflectionMapManager::updateUniforms()
 
     ReflectionProbeData rpd;
 
+    F32 minDepth[256];
+
+    for (int i = 0; i < 256; ++i)
+    {
+        rpd.refBucket[i][0] = mReflectionProbeCount;
+        rpd.refBucket[i][1] = mReflectionProbeCount;
+        rpd.refBucket[i][2] = mReflectionProbeCount;
+        rpd.refBucket[i][3] = mReflectionProbeCount;
+        minDepth[i] = FLT_MAX;
+    }
+
     // load modelview matrix into matrix 4a
     LLMatrix4a modelview;
     modelview.loadu(gGLModelView);
@@ -861,6 +927,28 @@ void LLReflectionMapManager::updateUniforms()
             break;
         }
 
+        if (refmap != mDefaultProbe)
+        {
+            // bucket search data
+            // theory of operation:
+            //      1. Determine minimum and maximum depth of each influence volume and store in mDepth (done in getReflectionMaps)
+            //      2. Sort by minimum depth
+            //      3. Prepare a bucket for each 1m of depth out to 256m
+            //      4. For each bucket, store the index of the nearest probe that might influence pixels in that bucket
+            //      5. In the shader, lookup the bucket for the pixel depth to get the index of the first probe that could possibly influence
+            //          the current pixel.
+            int depth_min = llclamp(llfloor(refmap->mMinDepth), 0, 255);
+            int depth_max = llclamp(llfloor(refmap->mMaxDepth), 0, 255);
+            for (U32 i = depth_min; i <= depth_max; ++i)
+            {
+                if (refmap->mMinDepth < minDepth[i])
+                {
+                    minDepth[i] = refmap->mMinDepth;
+                    rpd.refBucket[i][0] = refmap->mProbeIndex;
+                }
+            }
+        }
+
         llassert(refmap->mProbeIndex == count);
         llassert(mReflectionMaps[refmap->mProbeIndex] == refmap);
 
@@ -890,7 +978,11 @@ void LLReflectionMapManager::updateUniforms()
             rpd.refIndex[count][3] = -rpd.refIndex[count][3];
         }
 
-        rpd.refParams[count].set(llmax(minimum_ambiance, refmap->getAmbiance())*ambscale, radscale, refmap->mFadeIn, 0.f);
+        rpd.refParams[count].set(
+            llmax(minimum_ambiance, refmap->getAmbiance())*ambscale, // ambiance scale
+            radscale, // radiance scale
+            refmap->mFadeIn, // fade in weight
+            oa.getF32ptr()[2] - refmap->mRadius); // z near
 
         S32 ni = nc; // neighbor ("index") - index into refNeighbor to write indices for current reflection probe's neighbors
         {
@@ -907,7 +999,7 @@ void LLReflectionMapManager::updateUniforms()
                 }
 
                 GLint idx = neighbor->mProbeIndex;
-                if (idx == -1 || neighbor->mOccluded)
+                if (idx == -1 || neighbor->mOccluded || neighbor->mCubeIndex == -1)
                 {
                     continue;
                 }
@@ -944,6 +1036,30 @@ void LLReflectionMapManager::updateUniforms()
         count++;
     }
 
+#if 0
+    {
+        // fill in gaps in refBucket
+        S32 probe_idx = mReflectionProbeCount;
+        
+        for (int i = 0; i < 256; ++i)
+        {
+            if (i < count)
+            { // for debugging, store depth of mReflectionsMaps[i]
+                rpd.refBucket[i][1] = (S32) (mReflectionMaps[i]->mDepth * 10);
+            }
+
+            if (rpd.refBucket[i][0] == mReflectionProbeCount)
+            {
+                rpd.refBucket[i][0] = probe_idx;
+            }
+            else
+            {
+                probe_idx = rpd.refBucket[i][0];
+            }
+        }
+    }
+#endif
+
     rpd.refmapCount = count;
 
     //copy rpd into uniform buffer object
@@ -958,6 +1074,21 @@ void LLReflectionMapManager::updateUniforms()
         glBufferData(GL_UNIFORM_BUFFER, sizeof(ReflectionProbeData), &rpd, GL_STREAM_DRAW);
         glBindBuffer(GL_UNIFORM_BUFFER, 0);
     }
+
+#if 0
+    if (!gCubeSnapshot)
+    {
+        for (auto& probe : mProbes)
+        {
+            LLViewerObject* vobj = probe->mViewerObject;
+            if (vobj)
+            {
+                F32 time = (F32)gFrameTimeSeconds - probe->mLastUpdateTime;
+                vobj->setDebugText(llformat("%d/%d/%d/%.1f - %.1f/%.1f", probe->mCubeIndex, probe->mProbeIndex, (U32) probe->mNeighbors.size(), probe->mMinDepth, probe->mMaxDepth, time), time > 1.f ? LLColor4::white : LLColor4::green);
+            }
+        }
+    }
+#endif
 }
 
 void LLReflectionMapManager::setUniforms()
@@ -977,37 +1108,40 @@ void LLReflectionMapManager::setUniforms()
 
 void renderReflectionProbe(LLReflectionMap* probe)
 {
-    F32* po = probe->mOrigin.getF32ptr();
-
-    //draw orange line from probe to neighbors
-    gGL.flush();
-    gGL.diffuseColor4f(1, 0.5f, 0, 1);
-    gGL.begin(gGL.LINES);
-    for (auto& neighbor : probe->mNeighbors)
+    if (probe->isRelevant())
     {
-        if (probe->mViewerObject && neighbor->mViewerObject)
-        {
-            continue;
-        }
-        
-        gGL.vertex3fv(po);
-        gGL.vertex3fv(neighbor->mOrigin.getF32ptr());
-    }
-    gGL.end();
-    gGL.flush();
+        F32* po = probe->mOrigin.getF32ptr();
 
-    gGL.diffuseColor4f(1, 1, 0, 1);
-    gGL.begin(gGL.LINES);
-    for (auto& neighbor : probe->mNeighbors)
-    {
-        if (probe->mViewerObject && neighbor->mViewerObject)
+        //draw orange line from probe to neighbors
+        gGL.flush();
+        gGL.diffuseColor4f(1, 0.5f, 0, 1);
+        gGL.begin(gGL.LINES);
+        for (auto& neighbor : probe->mNeighbors)
         {
+            if (probe->mViewerObject && neighbor->mViewerObject)
+            {
+                continue;
+            }
+
             gGL.vertex3fv(po);
             gGL.vertex3fv(neighbor->mOrigin.getF32ptr());
         }
+        gGL.end();
+        gGL.flush();
+
+        gGL.diffuseColor4f(1, 1, 0, 1);
+        gGL.begin(gGL.LINES);
+        for (auto& neighbor : probe->mNeighbors)
+        {
+            if (probe->mViewerObject && neighbor->mViewerObject)
+            {
+                gGL.vertex3fv(po);
+                gGL.vertex3fv(neighbor->mOrigin.getF32ptr());
+            }
+        }
+        gGL.end();
+        gGL.flush();
     }
-    gGL.end();
-    gGL.flush();
 
 #if 0
     LLSpatialGroup* group = probe->mGroup;
@@ -1095,7 +1229,6 @@ void LLReflectionMapManager::initReflectionMaps()
         mUpdatingProbe = nullptr;
         mRadiancePass = false;
         mRealtimeRadiancePass = false;
-        mDefaultProbe = nullptr;
 
         for (auto& probe : mProbes)
         {
@@ -1104,14 +1237,28 @@ void LLReflectionMapManager::initReflectionMaps()
             probe->mProbeIndex = -1;
             probe->mCubeArray = nullptr;
             probe->mCubeIndex = -1;
+            probe->mNeighbors.clear();
         }
 
-        for (bool& is_free : mCubeFree)
+        mCubeFree.clear();
+        initCubeFree();
+
+        if (mDefaultProbe.isNull())
         {
-            is_free = true;
+            llassert(mProbes.empty()); // default probe MUST be the first probe created
+            mDefaultProbe = new LLReflectionMap();
+            mProbes.push_back(mDefaultProbe);
         }
 
-        mCubeFree[0] = false;
+        llassert(mProbes[0] == mDefaultProbe);
+
+        mDefaultProbe->mCubeIndex = 0;
+        mDefaultProbe->mCubeArray = mTexture;
+        mDefaultProbe->mDistance = 64.f;
+        mDefaultProbe->mRadius = 4096.f;
+        mDefaultProbe->mProbeIndex = 0;
+        touch_default_probe(mDefaultProbe);
+
     }
 
     if (mVertexBuffer.isNull())
diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h
index 234bde51a81bdb53a9035296dc9eee8b723816ae..c0618de41077cd4f5e1bea34e0609a67128647b2 100644
--- a/indra/newview/llreflectionmapmanager.h
+++ b/indra/newview/llreflectionmapmanager.h
@@ -110,7 +110,7 @@ class alignas(16) LLReflectionMapManager
     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
+    // returns -1 if allocation failed
     S32 allocateCubeIndex();
 
     // update the neighbors of the given probe 
@@ -137,12 +137,9 @@ class alignas(16) LLReflectionMapManager
     // storage for reflection probe irradiance maps
     LLPointer<LLCubeMapArray> mIrradianceMaps;
 
-    // array indicating if a particular cubemap is free
-    bool mCubeFree[LL_MAX_REFLECTION_PROBE_COUNT];
+    // list of free cubemap indices
+    std::list<S32> mCubeFree;
 
-    // start tracking the given spatial group
-    void trackGroup(LLSpatialGroup* group);
-    
     // perform an update on the currently updating Probe
     void doProbeUpdate();
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 100c73377fadf0b0be4f0581baead25f64588a84..2f4274d0d082f444f1901bc36e8c05f577030003 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -5689,7 +5689,7 @@ S32 LLViewerObject::countInventoryContents(LLAssetType::EType type)
 	return count;
 }
 
-void LLViewerObject::setDebugText(const std::string &utf8text)
+void LLViewerObject::setDebugText(const std::string &utf8text, const LLColor4& color)
 {
 	if (utf8text.empty() && !mText)
 	{
@@ -5700,7 +5700,7 @@ void LLViewerObject::setDebugText(const std::string &utf8text)
 	{
 	    initHudText();
 	}
-	mText->setColor(LLColor4::white);
+	mText->setColor(color);
 	mText->setString(utf8text);
 	mText->setZCompare(FALSE);
 	mText->setDoFade(FALSE);
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index e647fdd0450c24cb106c1f503cdc4213036ee0a5..fe27227e6b8d5684f04776efd0f2de974590bc4f 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -441,7 +441,7 @@ class LLViewerObject
 
 	void sendMaterialUpdate() const;
 
-	void setDebugText(const std::string &utf8text);
+	void setDebugText(const std::string &utf8text, const LLColor4& color = LLColor4::white);
 	void appendDebugText(const std::string &utf8text);
 	void initHudText();
 	void restoreHudText();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 126924220cedca63bd9dc56caa44ea6f4031801a..4bb93d675ed5f030fb8f820a8d4416f3462d60d8 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -6912,7 +6912,8 @@ void LLPipeline::bindScreenToTexture()
 
 static LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM("Bloom");
 
-void LLPipeline::visualizeBuffers(LLRenderTarget* src, LLRenderTarget* dst, U32 bufferIndex) {
+void LLPipeline::visualizeBuffers(LLRenderTarget* src, LLRenderTarget* dst, U32 bufferIndex)
+{
 	dst->bindTarget();
 	gDeferredBufferVisualProgram.bind();
 	gDeferredBufferVisualProgram.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, src, false, LLTexUnit::TFO_BILINEAR, bufferIndex);
@@ -6929,7 +6930,8 @@ void LLPipeline::visualizeBuffers(LLRenderTarget* src, LLRenderTarget* dst, U32
 	dst->flush();
 }
 
-void LLPipeline::generateLuminance(LLRenderTarget* src, LLRenderTarget* dst) {
+void LLPipeline::generateLuminance(LLRenderTarget* src, LLRenderTarget* dst)
+{
 	// luminance sample and mipmap generation
 	{
 		LL_PROFILE_GPU_ZONE("luminance sample");
@@ -7054,7 +7056,8 @@ void LLPipeline::gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst) {
 	dst->flush();
 }
 
-void LLPipeline::copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget* dst) {
+void LLPipeline::copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget* dst) 
+{
 
 	if (RenderScreenSpaceReflections && !gCubeSnapshot)
 	{
@@ -7080,7 +7083,8 @@ void LLPipeline::copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget*
 	}
 }
 
-void LLPipeline::generateGlow(LLRenderTarget* src) {
+void LLPipeline::generateGlow(LLRenderTarget* src) 
+{
 	if (sRenderGlow)
 	{
 		LL_PROFILE_GPU_ZONE("glow");
@@ -7177,7 +7181,8 @@ void LLPipeline::generateGlow(LLRenderTarget* src) {
 	}
 }
 
-void LLPipeline::applyFXAA(LLRenderTarget* src, LLRenderTarget* dst) {
+void LLPipeline::applyFXAA(LLRenderTarget* src, LLRenderTarget* dst) 
+{
 	{
 		llassert(!gCubeSnapshot);
 		bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete();
@@ -7257,7 +7262,8 @@ void LLPipeline::applyFXAA(LLRenderTarget* src, LLRenderTarget* dst) {
 	}
 }
 
-void LLPipeline::copyRenderTarget(LLRenderTarget* src, LLRenderTarget* dst) {
+void LLPipeline::copyRenderTarget(LLRenderTarget* src, LLRenderTarget* dst)
+{
 
 	LL_PROFILE_GPU_ZONE("copyRenderTarget");
 	dst->bindTarget();
@@ -7277,7 +7283,8 @@ void LLPipeline::copyRenderTarget(LLRenderTarget* src, LLRenderTarget* dst) {
 	dst->flush();
 }
 
-void LLPipeline::combineGlow(LLRenderTarget* src, LLRenderTarget* dst) {
+void LLPipeline::combineGlow(LLRenderTarget* src, LLRenderTarget* dst)
+{
 	// Go ahead and do our glow combine here in our destination.  We blit this later into the front buffer.
 
 	dst->bindTarget();
@@ -7296,7 +7303,8 @@ void LLPipeline::combineGlow(LLRenderTarget* src, LLRenderTarget* dst) {
 	dst->flush();
 }
 
-void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) {
+void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst)
+{
 	{
 		bool dof_enabled =
 			(RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) &&
@@ -7462,10 +7470,12 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) {
 			{ // combine result based on alpha
 				
 				dst->bindTarget();
-				if (RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete()) {
+				if (RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete())
+                {
 					glViewport(0, 0, dst->getWidth(), dst->getHeight());
 				}
-				else {
+				else
+                {
 					gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
 					gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
 					gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
@@ -7500,6 +7510,7 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) {
 
 void LLPipeline::renderFinalize()
 {
+    llassert(!gCubeSnapshot);
     LLVertexBuffer::unbind();
     LLGLState::checkStates();
 
@@ -7520,22 +7531,20 @@ void LLPipeline::renderFinalize()
     gGL.setColorMask(true, true);
     glClearColor(0, 0, 0, 0);
 
-    if (!gCubeSnapshot)
-    {
-		copyScreenSpaceReflections(&mRT->screen, &mSceneMap);
+    
+    copyScreenSpaceReflections(&mRT->screen, &mSceneMap);
 
-		generateLuminance(&mRT->screen, &mLuminanceMap);
+    generateLuminance(&mRT->screen, &mLuminanceMap);
 
-		generateExposure(&mLuminanceMap, &mExposureMap);
+    generateExposure(&mLuminanceMap, &mExposureMap);
 
-		gammaCorrect(&mRT->screen, &mPostMap);
+    gammaCorrect(&mRT->screen, &mPostMap);
 
-        LLVertexBuffer::unbind();
-    }
+    LLVertexBuffer::unbind();
 
-	generateGlow(&mPostMap);
+    generateGlow(&mPostMap);
 
-	combineGlow(&mPostMap, &mRT->screen);
+    combineGlow(&mPostMap, &mRT->screen);
 
 	gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
 	gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
@@ -7547,7 +7556,8 @@ void LLPipeline::renderFinalize()
 
 	applyFXAA(&mPostMap, &mRT->screen);
 	LLRenderTarget* finalBuffer = &mRT->screen;
-	if (RenderBufferVisualization > -1) {
+	if (RenderBufferVisualization > -1)
+    {
 		finalBuffer = &mPostMap;
 		switch (RenderBufferVisualization)
 		{