summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorCosmic Linden <cosmic@lindenlab.com>2023-09-29 17:19:48 -0700
committerCosmic Linden <cosmic@lindenlab.com>2024-01-31 14:31:36 -0800
commit118996225bb588dcaef415dfe18f5e4aca9c35b8 (patch)
tree8685d290d59a5dddf3bf57ce2a8ab4f9fdcb5d7c /indra/newview
parent00c65b62707f5c30cf2d48c0bd0c975c3bceb513 (diff)
secondlife/viewer-issues#43: Proof-of-concept PBR terrain normal gen feature flag. Final implementation would likely be very different.
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/llsurface.cpp14
-rw-r--r--indra/newview/llsurface.h6
-rw-r--r--indra/newview/llsurfacepatch.cpp197
-rw-r--r--indra/newview/llsurfacepatch.h13
-rw-r--r--indra/newview/llviewermenu.cpp18
-rwxr-xr-xindra/newview/llviewerregion.cpp35
-rw-r--r--indra/newview/llviewerregion.h3
-rw-r--r--indra/newview/llvosurfacepatch.cpp1
-rw-r--r--indra/newview/pipeline.cpp9
-rw-r--r--indra/newview/pipeline.h2
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml7
12 files changed, 292 insertions, 24 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 242e274daf..ff0f4fd8a1 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -10932,6 +10932,17 @@
<key>Value</key>
<real>8.0</real>
</map>
+ <key>RenderTerrainPBRNormalsEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>EXPERIMENTAL: Change normal gen for PBR Terrain.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>RenderTrackerBeacon</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index 1418499f8b..804afe6266 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -643,17 +643,18 @@ void LLSurface::updatePatchVisibilities(LLAgent &agent)
}
}
-BOOL LLSurface::idleUpdate(F32 max_update_time)
+template<bool PBR>
+bool LLSurface::idleUpdate(F32 max_update_time)
{
if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TERRAIN))
{
- return FALSE;
+ return false;
}
// Perform idle time update of non-critical stuff.
// In this case, texture and normal updates.
LLTimer update_timer;
- BOOL did_update = FALSE;
+ bool did_update = false;
// If the Z height data has changed, we need to rebuild our
// property line vertex arrays.
@@ -669,13 +670,13 @@ BOOL LLSurface::idleUpdate(F32 max_update_time)
{
std::set<LLSurfacePatch *>::iterator curiter = iter++;
LLSurfacePatch *patchp = *curiter;
- patchp->updateNormals();
+ patchp->updateNormals<PBR>();
patchp->updateVerticalStats();
if (max_update_time == 0.f || update_timer.getElapsedTimeF32() < max_update_time)
{
if (patchp->updateTexture())
{
- did_update = TRUE;
+ did_update = true;
patchp->clearDirty();
mDirtyPatchList.erase(curiter);
}
@@ -691,6 +692,9 @@ BOOL LLSurface::idleUpdate(F32 max_update_time)
return did_update;
}
+template bool LLSurface::idleUpdate</*PBR=*/false>(F32 max_update_time);
+template bool LLSurface::idleUpdate</*PBR=*/true>(F32 max_update_time);
+
void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL b_large_patch)
{
diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h
index 33a64ae7d5..b7b47d2a1c 100644
--- a/indra/newview/llsurface.h
+++ b/indra/newview/llsurface.h
@@ -112,7 +112,8 @@ public:
LLSurfacePatch *resolvePatchGlobal(const LLVector3d &position_global) const;
// Update methods (called during idle, normally)
- BOOL idleUpdate(F32 max_update_time);
+ template<bool PBR>
+ bool idleUpdate(F32 max_update_time);
BOOL containsPosition(const LLVector3 &position);
@@ -224,6 +225,9 @@ private:
static S32 sTextureSize; // Size of the surface texture
};
+extern template bool LLSurface::idleUpdate</*PBR=*/false>(F32 max_update_time);
+extern template bool LLSurface::idleUpdate</*PBR=*/true>(F32 max_update_time);
+
// . __.
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index a6370e9ec2..92b1273041 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -243,7 +243,8 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3
}
-void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride)
+template<>
+void LLSurfacePatch::calcNormal</*PBR=*/false>(const U32 x, const U32 y, const U32 stride)
{
U32 patch_width = mSurfacep->mPVArray.mPatchWidth;
U32 surface_stride = mSurfacep->getGridsPerEdge();
@@ -356,6 +357,166 @@ void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride)
*(mDataNorm + surface_stride * y + x) = normal;
}
+template<>
+void LLSurfacePatch::calcNormal</*PBR=*/true>(const U32 x, const U32 y, const U32 stride)
+{
+ llassert(mDataNorm);
+ constexpr U32 index = 0;
+
+ const U32 surface_stride = mSurfacep->getGridsPerEdge();
+ LLVector3& normal_out = *(mDataNorm + surface_stride * y + x);
+ calcNormalFlat(normal_out, x, y, index);
+}
+
+// Calculate the flat normal of a triangle whose least coordinate is specified by the given x,y values.
+// If index = 0, calculate the normal of the first triangle, otherwise calculate the normal of the second.
+void LLSurfacePatch::calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index)
+{
+ llassert(index == 0 || index == 1);
+
+ U32 patch_width = mSurfacep->mPVArray.mPatchWidth;
+ U32 surface_stride = mSurfacep->getGridsPerEdge();
+
+ // Vertex stride is always 1 because we want the flat surface of the current triangle face
+ constexpr U32 stride = 1;
+
+ const F32 mpg = mSurfacep->getMetersPerGrid() * stride;
+
+ S32 poffsets[2][2][2];
+ poffsets[0][0][0] = x;
+ poffsets[0][0][1] = y;
+
+ poffsets[0][1][0] = x;
+ poffsets[0][1][1] = y + stride;
+
+ poffsets[1][0][0] = x + stride;
+ poffsets[1][0][1] = y;
+
+ poffsets[1][1][0] = x + stride;
+ poffsets[1][1][1] = y + stride;
+
+ const LLSurfacePatch *ppatches[2][2];
+
+ // LLVector3 p1, p2, p3, p4;
+
+ ppatches[0][0] = this;
+ ppatches[0][1] = this;
+ ppatches[1][0] = this;
+ ppatches[1][1] = this;
+
+ U32 i, j;
+ for (i = 0; i < 2; i++)
+ {
+ for (j = 0; j < 2; j++)
+ {
+ if (poffsets[i][j][0] < 0)
+ {
+ if (!ppatches[i][j]->getNeighborPatch(WEST))
+ {
+ poffsets[i][j][0] = 0;
+ }
+ else
+ {
+ poffsets[i][j][0] += patch_width;
+ ppatches[i][j] = ppatches[i][j]->getNeighborPatch(WEST);
+ }
+ }
+ if (poffsets[i][j][1] < 0)
+ {
+ if (!ppatches[i][j]->getNeighborPatch(SOUTH))
+ {
+ poffsets[i][j][1] = 0;
+ }
+ else
+ {
+ poffsets[i][j][1] += patch_width;
+ ppatches[i][j] = ppatches[i][j]->getNeighborPatch(SOUTH);
+ }
+ }
+ if (poffsets[i][j][0] >= (S32)patch_width)
+ {
+ if (!ppatches[i][j]->getNeighborPatch(EAST))
+ {
+ poffsets[i][j][0] = patch_width - 1;
+ }
+ else
+ {
+ poffsets[i][j][0] -= patch_width;
+ ppatches[i][j] = ppatches[i][j]->getNeighborPatch(EAST);
+ }
+ }
+ if (poffsets[i][j][1] >= (S32)patch_width)
+ {
+ if (!ppatches[i][j]->getNeighborPatch(NORTH))
+ {
+ poffsets[i][j][1] = patch_width - 1;
+ }
+ else
+ {
+ poffsets[i][j][1] -= patch_width;
+ ppatches[i][j] = ppatches[i][j]->getNeighborPatch(NORTH);
+ }
+ }
+ }
+ }
+
+ LLVector3 p00(-mpg,-mpg,
+ *(ppatches[0][0]->mDataZ
+ + poffsets[0][0][0]
+ + poffsets[0][0][1]*surface_stride));
+ LLVector3 p01(-mpg,+mpg,
+ *(ppatches[0][1]->mDataZ
+ + poffsets[0][1][0]
+ + poffsets[0][1][1]*surface_stride));
+ LLVector3 p10(+mpg,-mpg,
+ *(ppatches[1][0]->mDataZ
+ + poffsets[1][0][0]
+ + poffsets[1][0][1]*surface_stride));
+ LLVector3 p11(+mpg,+mpg,
+ *(ppatches[1][1]->mDataZ
+ + poffsets[1][1][0]
+ + poffsets[1][1][1]*surface_stride));
+
+ // Triangle index / coordinate convention
+ // for a single surface patch
+ //
+ // p01 p11
+ //
+ // ^ ._____.
+ // | |\ |
+ // | | \ 1 |
+ // | | \ |
+ // | 0 \ |
+ // y |____\|
+ //
+ // p00 x ---> p10
+ //
+ // (z up / out of the screen due to right-handed coordinate system)
+
+ LLVector3 normal;
+ if (index == 0)
+ {
+ LLVector3 c1 = p10 - p00;
+ LLVector3 c2 = p01 - p00;
+
+ normal = c1;
+ normal %= c2;
+ normal.normVec();
+ }
+ else // index == 1
+ {
+ LLVector3 c1 = p11 - p01;
+ LLVector3 c2 = p11 - p10;
+
+ normal = c1;
+ normal %= c2;
+ normal.normVec();
+ }
+
+ llassert(&normal_out);
+ normal_out = normal;
+}
+
const LLVector3 &LLSurfacePatch::getNormal(const U32 x, const U32 y) const
{
U32 surface_stride = mSurfacep->getGridsPerEdge();
@@ -453,6 +614,7 @@ void LLSurfacePatch::updateVerticalStats()
}
+template<bool PBR>
void LLSurfacePatch::updateNormals()
{
if (mSurfacep->mType == 'w')
@@ -470,9 +632,9 @@ void LLSurfacePatch::updateNormals()
{
for (j = 0; j <= grids_per_patch_edge; j++)
{
- calcNormal(grids_per_patch_edge, j, 2);
- calcNormal(grids_per_patch_edge - 1, j, 2);
- calcNormal(grids_per_patch_edge - 2, j, 2);
+ calcNormal<PBR>(grids_per_patch_edge, j, 2);
+ calcNormal<PBR>(grids_per_patch_edge - 1, j, 2);
+ calcNormal<PBR>(grids_per_patch_edge - 2, j, 2);
}
dirty_patch = TRUE;
@@ -483,9 +645,9 @@ void LLSurfacePatch::updateNormals()
{
for (i = 0; i <= grids_per_patch_edge; i++)
{
- calcNormal(i, grids_per_patch_edge, 2);
- calcNormal(i, grids_per_patch_edge - 1, 2);
- calcNormal(i, grids_per_patch_edge - 2, 2);
+ calcNormal<PBR>(i, grids_per_patch_edge, 2);
+ calcNormal<PBR>(i, grids_per_patch_edge - 1, 2);
+ calcNormal<PBR>(i, grids_per_patch_edge - 2, 2);
}
dirty_patch = TRUE;
@@ -496,8 +658,8 @@ void LLSurfacePatch::updateNormals()
{
for (j = 0; j < grids_per_patch_edge; j++)
{
- calcNormal(0, j, 2);
- calcNormal(1, j, 2);
+ calcNormal<PBR>(0, j, 2);
+ calcNormal<PBR>(1, j, 2);
}
dirty_patch = TRUE;
}
@@ -507,8 +669,8 @@ void LLSurfacePatch::updateNormals()
{
for (i = 0; i < grids_per_patch_edge; i++)
{
- calcNormal(i, 0, 2);
- calcNormal(i, 1, 2);
+ calcNormal<PBR>(i, 0, 2);
+ calcNormal<PBR>(i, 1, 2);
}
dirty_patch = TRUE;
}
@@ -584,10 +746,10 @@ void LLSurfacePatch::updateNormals()
// We've got a northeast patch in the same surface.
// The z and normals will be handled by that patch.
}
- calcNormal(grids_per_patch_edge, grids_per_patch_edge, 2);
- calcNormal(grids_per_patch_edge, grids_per_patch_edge - 1, 2);
- calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge, 2);
- calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2);
+ calcNormal<PBR>(grids_per_patch_edge, grids_per_patch_edge, 2);
+ calcNormal<PBR>(grids_per_patch_edge, grids_per_patch_edge - 1, 2);
+ calcNormal<PBR>(grids_per_patch_edge - 1, grids_per_patch_edge, 2);
+ calcNormal<PBR>(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2);
dirty_patch = TRUE;
}
@@ -598,7 +760,7 @@ void LLSurfacePatch::updateNormals()
{
for (i=2; i < grids_per_patch_edge - 2; i++)
{
- calcNormal(i, j, 2);
+ calcNormal<PBR>(i, j, 2);
}
}
dirty_patch = TRUE;
@@ -615,6 +777,9 @@ void LLSurfacePatch::updateNormals()
}
}
+template void LLSurfacePatch::updateNormals</*PBR=*/false>();
+template void LLSurfacePatch::updateNormals</*PBR=*/true>();
+
void LLSurfacePatch::updateEastEdge()
{
U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();
diff --git a/indra/newview/llsurfacepatch.h b/indra/newview/llsurfacepatch.h
index 8c8f501dce..ec3864ce44 100644
--- a/indra/newview/llsurfacepatch.h
+++ b/indra/newview/llsurfacepatch.h
@@ -77,6 +77,7 @@ public:
void updateVerticalStats();
void updateCompositionStats();
+ template<bool PBR>
void updateNormals();
void updateEastEdge();
@@ -102,9 +103,18 @@ public:
LLVector3 getPointAgent(const U32 x, const U32 y) const; // get the point at the offset.
LLVector2 getTexCoords(const U32 x, const U32 y) const;
+ // Per-vertex normals
+ // *TODO: PBR=true is a test implementation solely for proof-of-concept.
+ // Final implementation would likely be very different and may not even use
+ // this function. If we decide to keep calcNormalFlat, remove index as it
+ // is a debug parameter for testing.
+ template<bool PBR>
void calcNormal(const U32 x, const U32 y, const U32 stride);
const LLVector3 &getNormal(const U32 x, const U32 y) const;
+ // Per-triangle normals for flat edges
+ void calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index /* 0 or 1 */);
+
void eval(const U32 x, const U32 y, const U32 stride,
LLVector3 *vertex, LLVector3 *normal, LLVector2 *tex0, LLVector2 *tex1);
@@ -181,5 +191,8 @@ protected:
LLSurface *mSurfacep; // Pointer to "parent" surface
};
+extern template void LLSurfacePatch::updateNormals</*PBR=*/false>();
+extern template void LLSurfacePatch::updateNormals</*PBR=*/true>();
+
#endif // LL_LLSURFACEPATCH_H
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 9db9d97ddc..da7b1131a3 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -2122,6 +2122,20 @@ class LLAdvancedPurgeShaderCache : public view_listener_t
}
};
+/////////////////////
+// REBUILD TERRAIN //
+/////////////////////
+
+
+class LLAdvancedRebuildTerrain : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gPipeline.rebuildTerrain();
+ return true;
+ }
+};
+
////////////////////
// EVENT Recorder //
///////////////////
@@ -9492,6 +9506,10 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile");
view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark");
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
+ if (gSavedSettings.get<bool>("RenderTerrainPBREnabled"))
+ {
+ view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
+ }
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode");
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index dae476d9d7..d541bb6647 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1105,6 +1105,11 @@ void LLViewerRegion::dirtyHeights()
}
}
+void LLViewerRegion::dirtyAllPatches()
+{
+ getLand().dirtyAllPatches();
+}
+
//physically delete the cache entry
void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry, bool for_rendering)
{
@@ -1605,7 +1610,19 @@ void LLViewerRegion::idleUpdate(F32 max_update_time)
mLastUpdate = LLViewerOctreeEntryData::getCurrentFrame();
- mImpl->mLandp->idleUpdate(max_update_time);
+ static bool pbr_terrain_enabled = gSavedSettings.get<bool>("RenderTerrainPBREnabled");
+ static LLCachedControl<bool> pbr_terrain_experimental_normals(gSavedSettings, "RenderTerrainPBRNormalsEnabled", FALSE);
+ bool pbr_material = mImpl->mCompositionp && (mImpl->mCompositionp->getMaterialType() == LLTerrainMaterials::Type::PBR);
+ bool pbr_land = pbr_material && pbr_terrain_enabled && pbr_terrain_experimental_normals;
+
+ if (!pbr_land)
+ {
+ mImpl->mLandp->idleUpdate</*PBR=*/false>(max_update_time);
+ }
+ else
+ {
+ mImpl->mLandp->idleUpdate</*PBR=*/true>(max_update_time);
+ }
if (mParcelOverlay)
{
@@ -1906,7 +1923,21 @@ LLViewerObject* LLViewerRegion::updateCacheEntry(U32 local_id, LLViewerObject* o
// As above, but forcibly do the update.
void LLViewerRegion::forceUpdate()
{
- mImpl->mLandp->idleUpdate(0.f);
+ constexpr F32 max_update_time = 0.f;
+
+ static bool pbr_terrain_enabled = gSavedSettings.get<BOOL>("RenderTerrainPBREnabled");
+ static LLCachedControl<BOOL> pbr_terrain_experimental_normals(gSavedSettings, "RenderTerrainPBRNormalsEnabled", FALSE);
+ bool pbr_material = mImpl->mCompositionp && (mImpl->mCompositionp->getMaterialType() == LLTerrainMaterials::Type::PBR);
+ bool pbr_land = pbr_material && pbr_terrain_enabled && pbr_terrain_experimental_normals;
+
+ if (!pbr_land)
+ {
+ mImpl->mLandp->idleUpdate</*PBR=*/false>(max_update_time);
+ }
+ else
+ {
+ mImpl->mLandp->idleUpdate</*PBR=*/true>(max_update_time);
+ }
if (mParcelOverlay)
{
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 622490c881..1c2ff9bc97 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -163,6 +163,9 @@ public:
// Call this whenever you change the height data in the region.
// (Automatically called by LLSurfacePatch's update routine)
void dirtyHeights();
+ // Call this whenever you want to force all terrain to rebuild.
+ // (For example, if a global terrain config option has changed)
+ void dirtyAllPatches();
LLViewerParcelOverlay *getParcelOverlay() const
{ return mParcelOverlay; }
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 9544450a69..69b9476d38 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -214,6 +214,7 @@ BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable)
void LLVOSurfacePatch::updateFaceSize(S32 idx)
{
+ LL_PROFILE_ZONE_SCOPED;
if (idx != 0)
{
LL_WARNS() << "Terrain partition requested invalid face!!!" << LL_ENDL;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index fb57042110..d63b9d317e 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -10870,3 +10870,12 @@ void LLPipeline::rebuildDrawInfo()
}
}
+void LLPipeline::rebuildTerrain()
+{
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ region->dirtyAllPatches();
+ }
+}
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 5ace90b000..fb28a0e41c 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -134,6 +134,8 @@ public:
// rebuild all LLVOVolume render batches
void rebuildDrawInfo();
+ // Rebuild all terrain
+ void rebuildTerrain();
// Clear LLFace mVertexBuffer pointers
void resetVertexBuffers(LLDrawable* drawable);
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 660f4b62c7..9b238693e0 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -3297,6 +3297,13 @@ function="World.EnvPreset"
<menu_item_call.on_click
function="Advanced.ClearShaderCache" />
</menu_item_call>
+ <menu_item_call
+ enabled="true"
+ label="Rebuild Terrain"
+ name="Rebuild Terrain">
+ <menu_item_call.on_click
+ function="Advanced.RebuildTerrain" />
+ </menu_item_call>
<menu_item_separator />
<menu_item_call
enabled="true"