diff options
| author | Cosmic Linden <cosmic@lindenlab.com> | 2023-09-29 17:19:48 -0700 | 
|---|---|---|
| committer | Cosmic Linden <cosmic@lindenlab.com> | 2024-01-31 14:31:36 -0800 | 
| commit | 118996225bb588dcaef415dfe18f5e4aca9c35b8 (patch) | |
| tree | 8685d290d59a5dddf3bf57ce2a8ab4f9fdcb5d7c | |
| parent | 00c65b62707f5c30cf2d48c0bd0c975c3bceb513 (diff) | |
secondlife/viewer-issues#43: Proof-of-concept PBR terrain normal gen feature flag. Final implementation would likely be very different.
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 11 | ||||
| -rw-r--r-- | indra/newview/llsurface.cpp | 14 | ||||
| -rw-r--r-- | indra/newview/llsurface.h | 6 | ||||
| -rw-r--r-- | indra/newview/llsurfacepatch.cpp | 197 | ||||
| -rw-r--r-- | indra/newview/llsurfacepatch.h | 13 | ||||
| -rw-r--r-- | indra/newview/llviewermenu.cpp | 18 | ||||
| -rwxr-xr-x | indra/newview/llviewerregion.cpp | 35 | ||||
| -rw-r--r-- | indra/newview/llviewerregion.h | 3 | ||||
| -rw-r--r-- | indra/newview/llvosurfacepatch.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/pipeline.cpp | 9 | ||||
| -rw-r--r-- | indra/newview/pipeline.h | 2 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/menu_viewer.xml | 7 | 
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" | 
