diff options
-rw-r--r-- | indra/llmath/llcamera.h | 1 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 4 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.h | 1 | ||||
-rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl | 4 | ||||
-rw-r--r-- | indra/newview/lldynamictexture.cpp | 27 | ||||
-rw-r--r-- | indra/newview/llfetchedgltfmaterial.cpp | 52 | ||||
-rw-r--r-- | indra/newview/llfetchedgltfmaterial.h | 5 | ||||
-rw-r--r-- | indra/newview/llgltfmaterialpreviewmgr.cpp | 501 | ||||
-rw-r--r-- | indra/newview/llgltfmaterialpreviewmgr.h | 82 | ||||
-rw-r--r-- | indra/newview/llreflectionmapmanager.cpp | 32 | ||||
-rw-r--r-- | indra/newview/llreflectionmapmanager.h | 5 | ||||
-rw-r--r-- | indra/newview/lltexturectrl.cpp | 93 | ||||
-rw-r--r-- | indra/newview/lltexturectrl.h | 3 | ||||
-rw-r--r-- | indra/newview/pipeline.cpp | 15 | ||||
-rw-r--r-- | indra/newview/pipeline.h | 4 |
16 files changed, 728 insertions, 103 deletions
diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index c4d04f5d02..e1d3536f66 100644 --- a/indra/llmath/llcamera.h +++ b/indra/llmath/llcamera.h @@ -65,7 +65,6 @@ class LLCamera : public LLCoordFrame { public: - LLCamera(const LLCamera& rhs) { *this = rhs; diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index de27636c33..4f5f30d7c2 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1319,6 +1319,10 @@ bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, U32 index, { return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count); } +bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector4a>& strider, U32 index, S32 count) +{ + return VertexBufferStrider<LLVector4a, TYPE_NORMAL>::get(*this, strider, index, count); +} bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider, U32 index, S32 count) { return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count); diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 197fdbb189..cc59e322ed 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -180,6 +180,7 @@ public: bool getTexCoord1Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); bool getTexCoord2Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); bool getNormalStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1); + bool getNormalStrider(LLStrider<LLVector4a>& strider, U32 index = 0, S32 count = -1); bool getTangentStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1); bool getTangentStrider(LLStrider<LLVector4a>& strider, U32 index=0, S32 count = -1); bool getColorStrider(LLStrider<LLColor4U>& strider, U32 index=0, S32 count = -1); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7a70d0b6e6..8268fb3d97 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -310,6 +310,7 @@ set(viewer_SOURCE_FILES llgiveinventory.cpp llglsandbox.cpp llgltfmateriallist.cpp + llgltfmaterialpreviewmgr.cpp llgroupactions.cpp llgroupiconctrl.cpp llgrouplist.cpp @@ -963,6 +964,7 @@ set(viewer_HEADER_FILES llgesturemgr.h llgiveinventory.h llgltfmateriallist.h + llgltfmaterialpreviewmgr.h llgroupactions.h llgroupiconctrl.h llgrouplist.h diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl index bace9b8c90..cd4ae8110a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl @@ -37,7 +37,11 @@ void main() { vec4 diff = texture(diffuseRect, vary_fragcoord.xy); +#if 1 frag_color = diff; +#else + frag_color = vec4(1,0,1,1); +#endif gl_FragDepth = texture(depthMap, vary_fragcoord.xy).r; } diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 1a817e4fd9..a66c3876fc 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -189,13 +189,18 @@ BOOL LLViewerDynamicTexture::updateAllInstances() return TRUE; } - bool use_fbo = gPipeline.mBake.isComplete() && !gGLManager.mIsAMD; + LLRenderTarget& bake_target = gPipeline.mAuxillaryRT.deferredScreen; - if (use_fbo) - { - gPipeline.mBake.bindTarget(); - gPipeline.mBake.clear(); - } + if (!bake_target.isComplete()) + { + llassert(false); + return FALSE; + } + llassert(bake_target.getWidth() >= LLPipeline::MAX_BAKE_WIDTH); + llassert(bake_target.getHeight() >= LLPipeline::MAX_BAKE_WIDTH); + + bake_target.bindTarget(); + bake_target.clear(); LLGLSLShader::unbind(); LLVertexBuffer::unbind(); @@ -210,11 +215,14 @@ BOOL LLViewerDynamicTexture::updateAllInstances() LLViewerDynamicTexture *dynamicTexture = *iter; if (dynamicTexture->needsRender()) { + llassert(dynamicTexture->getFullWidth() <= LLPipeline::MAX_BAKE_WIDTH); + llassert(dynamicTexture->getFullHeight() <= LLPipeline::MAX_BAKE_WIDTH); + glClear(GL_DEPTH_BUFFER_BIT); gDepthDirty = TRUE; gGL.color4f(1,1,1,1); - dynamicTexture->setBoundTarget(use_fbo ? &gPipeline.mBake : nullptr); + dynamicTexture->setBoundTarget(&bake_target); dynamicTexture->preRender(); // Must be called outside of startRender() result = FALSE; if (dynamicTexture->render()) @@ -231,10 +239,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances() } } - if (use_fbo) - { - gPipeline.mBake.flush(); - } + bake_target.flush(); gGL.flush(); diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp index 46b9dffae9..90ec08391d 100644 --- a/indra/newview/llfetchedgltfmaterial.cpp +++ b/indra/newview/llfetchedgltfmaterial.cpp @@ -254,55 +254,3 @@ void LLFetchedGLTFMaterial::materialComplete() materialCompleteCallbacks.clear(); materialCompleteCallbacks.shrink_to_fit(); } - -LLPointer<LLViewerFetchedTexture> LLFetchedGLTFMaterial::getUITexture() -{ - if (mFetching) - { - return nullptr; - } - - auto fetch_texture_for_ui = [](LLPointer<LLViewerFetchedTexture>& img, const LLUUID& id) - { - if (id.notNull()) - { - if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(id)) - { - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - if (obj) - { - LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(id); - img = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL; - } - - } - else - { - img = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - } - } - if (img) - { - img->setBoostLevel(LLGLTexture::BOOST_PREVIEW); - img->forceToSaveRawImage(0); - } - }; - - fetch_texture_for_ui(mBaseColorTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]); - fetch_texture_for_ui(mNormalTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]); - fetch_texture_for_ui(mMetallicRoughnessTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]); - fetch_texture_for_ui(mEmissiveTexture, mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]); - - if ((mBaseColorTexture && (mBaseColorTexture->getRawImageLevel() != 0)) || - (mNormalTexture && (mNormalTexture->getRawImageLevel() != 0)) || - (mMetallicRoughnessTexture && (mMetallicRoughnessTexture->getRawImageLevel() != 0)) || - (mEmissiveTexture && (mEmissiveTexture->getRawImageLevel() != 0))) - { - return nullptr; - } - - // *HACK: Use one of the PBR texture components as the preview texture for now - mPreviewTexture = mBaseColorTexture; - - return mPreviewTexture; -} diff --git a/indra/newview/llfetchedgltfmaterial.h b/indra/newview/llfetchedgltfmaterial.h index a9e539633d..2559aa46cc 100644 --- a/indra/newview/llfetchedgltfmaterial.h +++ b/indra/newview/llfetchedgltfmaterial.h @@ -50,8 +50,6 @@ public: bool isFetching() const { return mFetching; } - LLPointer<LLViewerFetchedTexture> getUITexture(); - void addTextureEntry(LLTextureEntry* te) override; void removeTextureEntry(LLTextureEntry* te) override; virtual bool replaceLocalTexture(const LLUUID& tracking_id, const LLUUID& old_id, const LLUUID& new_id) override; @@ -65,9 +63,6 @@ public: std::set<LLTextureEntry*> mTextureEntires; - // Texture used for previewing the material in the UI - LLPointer<LLViewerFetchedTexture> mPreviewTexture; - protected: // Lifetime management diff --git a/indra/newview/llgltfmaterialpreviewmgr.cpp b/indra/newview/llgltfmaterialpreviewmgr.cpp new file mode 100644 index 0000000000..9ef1bbf884 --- /dev/null +++ b/indra/newview/llgltfmaterialpreviewmgr.cpp @@ -0,0 +1,501 @@ +/** + * @file llgltfmaterialpreviewmgr.cpp + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, 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 "llviewerprecompiledheaders.h" + +#include "llgltfmaterialpreviewmgr.h" + +#include <vector> + +#include "llavatarappearancedefines.h" +#include "llenvironment.h" +#include "llselectmgr.h" +#include "llviewercamera.h" +#include "llviewerobject.h" +#include "llviewershadermgr.h" +#include "llviewertexturelist.h" +#include "llviewerwindow.h" +#include "llvolumemgr.h" +#include "pipeline.h" + +LLGLTFMaterialPreviewMgr gGLTFMaterialPreviewMgr; + +namespace +{ + constexpr S32 FULLY_LOADED = 0; + constexpr S32 NOT_LOADED = 99; +}; + +LLGLTFPreviewTexture::MaterialLoadLevels::MaterialLoadLevels() +{ + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + levels[i] = NOT_LOADED; + } +} + +S32& LLGLTFPreviewTexture::MaterialLoadLevels::operator[](size_t i) +{ + llassert(i >= 0 && i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT); + return levels[i]; +} + +const S32& LLGLTFPreviewTexture::MaterialLoadLevels::operator[](size_t i) const +{ + llassert(i >= 0 && i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT); + return levels[i]; +} + +bool LLGLTFPreviewTexture::MaterialLoadLevels::operator<(const MaterialLoadLevels& other) const +{ + bool less = false; + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + if (((*this)[i] > other[i])) { return false; } + less = less || ((*this)[i] < other[i]); + } + return less; +} + +bool LLGLTFPreviewTexture::MaterialLoadLevels::operator>(const MaterialLoadLevels& other) const +{ + bool great = false; + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + if (((*this)[i] < other[i])) { return false; } + great = great || ((*this)[i] > other[i]); + } + return great; +} + +namespace +{ + void fetch_texture_for_ui(LLPointer<LLViewerFetchedTexture>& img, const LLUUID& id) + { + if (id.notNull()) + { + if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(id)) + { + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + if (obj) + { + LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(id); + img = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL; + } + } + else + { + img = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + } + } + if (img) + { + img->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + img->forceToSaveRawImage(0); + } + }; + + // *NOTE: Does not use the same conventions as texture discard level. Lower is better. + S32 get_texture_load_level(const LLPointer<LLViewerFetchedTexture>& texture) + { + if (!texture) { return FULLY_LOADED; } + const S32 raw_level = texture->getDiscardLevel(); + if (raw_level < 0) { return NOT_LOADED; } + return raw_level; + } + + LLGLTFPreviewTexture::MaterialLoadLevels get_material_load_levels(LLFetchedGLTFMaterial& material) + { + using MaterialTextures = LLPointer<LLViewerFetchedTexture>*[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT]; + + MaterialTextures textures; + + textures[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] = &material.mBaseColorTexture; + textures[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] = &material.mNormalTexture; + textures[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] = &material.mMetallicRoughnessTexture; + textures[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] = &material.mEmissiveTexture; + + LLGLTFPreviewTexture::MaterialLoadLevels levels; + + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + fetch_texture_for_ui(*textures[i], material.mTextureId[i]); + levels[i] = get_texture_load_level(*textures[i]); + } + + return levels; + } + + // Is the material loaded enough to start rendering a preview? + bool is_material_loaded_enough_for_ui(LLFetchedGLTFMaterial& material) + { + if (material.isFetching()) + { + return false; + } + + LLGLTFPreviewTexture::MaterialLoadLevels levels = get_material_load_levels(material); + + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + if (levels[i] == NOT_LOADED) + { + return false; + } + } + + return true; + } + +}; // namespace + +LLGLTFPreviewTexture::LLGLTFPreviewTexture(LLPointer<LLFetchedGLTFMaterial> material, S32 width) + : LLViewerDynamicTexture(width, width, 4, EOrder::ORDER_MIDDLE, FALSE) + , mGLTFMaterial(material) +{ +} + +// static +LLPointer<LLGLTFPreviewTexture> LLGLTFPreviewTexture::create(LLPointer<LLFetchedGLTFMaterial> material) +{ + return new LLGLTFPreviewTexture(material, LLPipeline::MAX_BAKE_WIDTH); +} + +void LLGLTFPreviewTexture::preRender(BOOL clear_depth) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + MaterialLoadLevels current_load = get_material_load_levels(*mGLTFMaterial.get()); + if (current_load < mBestLoad) + { + mShouldRender = true; + mBestLoad = current_load; + } + + if (!mShouldRender) { return; } + + LLViewerDynamicTexture::preRender(clear_depth); +} + + +namespace { + +struct GLTFPreviewModel +{ + GLTFPreviewModel(LLPointer<LLDrawInfo>& info, const LLMatrix4& mat) + : mDrawInfo(info) + , mModelMatrix(mat) + { + mDrawInfo->mModelMatrix = &mModelMatrix; + } + LLPointer<LLDrawInfo> mDrawInfo; + LLMatrix4 mModelMatrix; // Referenced by mDrawInfo +}; + +// Like LLVolumeGeometryManager::registerFace but without batching or too-many-indices/vertices checking. +std::vector<GLTFPreviewModel> create_preview_sphere(LLPointer<LLFetchedGLTFMaterial>& material, const LLMatrix4& model_matrix) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + const LLColor4U vertex_color(material->mBaseColor); + + LLPrimitive prim; + prim.init_primitive(LL_PCODE_VOLUME); + LLVolumeParams params; + params.setType(LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE); + params.setBeginAndEndS(0.f, 1.f); + params.setBeginAndEndT(0.f, 1.f); + params.setRatio(1, 1); + params.setShear(0, 0); + constexpr auto MAX_LOD = LLVolumeLODGroup::NUM_LODS - 1; + prim.setVolume(params, MAX_LOD); + + LLVolume* volume = prim.getVolume(); + llassert(volume); + for (LLVolumeFace& face : volume->getVolumeFaces()) + { + face.createTangents(); + } + + std::vector<GLTFPreviewModel> preview_sphere; + preview_sphere.reserve(volume->getNumFaces()); + + LLPointer<LLVertexBuffer> buf = new LLVertexBuffer( + LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_TANGENT + ); + U32 nv = 0; + U32 ni = 0; + for (LLVolumeFace& face : volume->getVolumeFaces()) + { + nv += face.mNumVertices; + ni += face.mNumIndices; + } + buf->allocateBuffer(nv, ni); + + // UV hacks + // Higher factor helps to see more details on the preview sphere + const LLVector2 uv_factor(2.0f, 2.0f); + // Offset places center of material in center of view + const LLVector2 uv_offset(-0.5f, -0.5f); + + LLStrider<U16> indices; + LLStrider<LLVector4a> positions; + LLStrider<LLVector4a> normals; + LLStrider<LLVector2> texcoords; + LLStrider<LLColor4U> colors; + LLStrider<LLVector4a> tangents; + buf->getIndexStrider(indices); + buf->getVertexStrider(positions); + buf->getNormalStrider(normals); + buf->getTexCoord0Strider(texcoords); + buf->getColorStrider(colors); + buf->getTangentStrider(tangents); + U32 index_offset = 0; + U32 vertex_offset = 0; + for (const LLVolumeFace& face : volume->getVolumeFaces()) + { + for (S32 i = 0; i < face.mNumIndices; ++i) + { + *indices++ = face.mIndices[i] + vertex_offset; + } + for (S32 v = 0; v < face.mNumVertices; ++v) + { + *positions++ = face.mPositions[v]; + *normals++ = face.mNormals[v]; + LLVector2 uv(face.mTexCoords[v]); + uv.scaleVec(uv_factor); + uv += uv_offset; + *texcoords++ = uv; + *colors++ = vertex_color; + *tangents++ = face.mTangents[v]; + } + + constexpr LLViewerTexture* no_media = nullptr; + LLPointer<LLDrawInfo> info = new LLDrawInfo(U16(vertex_offset), U16(vertex_offset + face.mNumVertices - 1), face.mNumIndices, index_offset, no_media, buf.get()); + info->mGLTFMaterial = material; + preview_sphere.emplace_back(info, model_matrix); + index_offset += face.mNumIndices; + vertex_offset += face.mNumVertices; + } + + buf->unmapBuffer(); + + return preview_sphere; +} + +// Final, direct modifications to shader constants, just before render +void fixup_shader_constants(LLGLSLShader& shader) +{ + // Sunlight intensity of 0 no matter what + shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, 1); + shader.uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, LLColor3::white.mV); + shader.uniform1f(LLShaderMgr::DENSITY_MULTIPLIER, 0.0f); + + // Ignore sun shadow (if enabled) + for (U32 i = 0; i < 6; i++) + { + const S32 channel = shader.getTextureChannel(LLShaderMgr::DEFERRED_SHADOW0+i); + if (channel != -1) + { + gGL.getTexUnit(channel)->bind(LLViewerFetchedTexture::sWhiteImagep, TRUE); + } + } +} + +// Set a variable to a value temporarily, and restor the variable's old value +// when this object leaves scope. +template<typename T> +struct SetTemporarily +{ + T* mRef; + T mOldVal; + SetTemporarily(T* var, T temp_val) + { + mRef = var; + mOldVal = *mRef; + *mRef = temp_val; + } + ~SetTemporarily() + { + *mRef = mOldVal; + } +}; + +}; // namespace + +BOOL LLGLTFPreviewTexture::render() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + if (!mShouldRender) { return FALSE; } + + LLGLDepthTest(GL_FALSE); + LLGLDisable stencil(GL_STENCIL_TEST); + LLGLDisable scissor(GL_SCISSOR_TEST); + SetTemporarily<bool> no_glow(&LLPipeline::sRenderGlow, false); + SetTemporarily<bool> no_ssr(&LLPipeline::RenderScreenSpaceReflections, false); + SetTemporarily<U32> no_fxaa(&LLPipeline::RenderFSAASamples, U32(0)); + SetTemporarily<LLPipeline::RenderTargetPack*> use_auxiliary_render_target(&gPipeline.mRT, &gPipeline.mAuxillaryRT); + + LLVector3 light_dir3(1.0f, 1.0f, 1.0f); + light_dir3.normalize(); + const LLVector4 light_dir = LLVector4(light_dir3, 0); + SetTemporarily<S32> sun_light_only(&LLPipeline::RenderLocalLightCount, 0); + + gPipeline.mReflectionMapManager.forceDefaultProbeAndUpdateUniforms(); + + LLViewerCamera camera; + + // Calculate the object distance at which the object of a given radius will + // span the partial width of the screen given by fill_ratio. + // Assume the primitive has a scale of 1 (this is the default). + constexpr F32 fill_ratio = 0.8f; + constexpr F32 object_radius = 0.5f; + const F32 object_distance = (object_radius / fill_ratio) * tan(camera.getDefaultFOV()); + // Negative coordinate shows the textures on the sphere right-side up, when + // combined with the UV hacks in create_preview_sphere + const LLVector3 object_position(0.0, -object_distance, 0.0); + LLMatrix4 object_transform; + object_transform.translate(object_position); + + // Set up camera and viewport + const LLVector3 origin(0.0, 0.0, 0.0); + camera.lookAt(origin, object_position); + camera.setAspect(mFullHeight / mFullWidth); + const LLRect texture_rect(0, mFullHeight, mFullWidth, 0); + camera.setPerspective(NOT_FOR_SELECTION, texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight(), FALSE, camera.getNear(), MAX_FAR_CLIP*2.f); + + // Generate sphere object on-the-fly. Discard afterwards. (Vertex buffer is + // discarded, but the sphere should be cached in LLVolumeMgr.) + std::vector<GLTFPreviewModel> preview_sphere = create_preview_sphere(mGLTFMaterial, object_transform); + + glClearColor(0, 0, 0, 0); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + gPipeline.setupHWLights(); + glh::matrix4f mat = copy_matrix(gGLModelView); + glh::vec4f transformed_light_dir(light_dir.mV); + mat.mult_matrix_vec(transformed_light_dir); + SetTemporarily<LLVector4> force_sun_direction_high_graphics(&gPipeline.mTransformedSunDir, LLVector4(transformed_light_dir.v)); + // Override lights to ensure the sun is always shining from a certain direction (low graphics) + // See also force_sun_direction_high_graphics and fixup_shader_constants + { + LLLightState* light = gGL.getLight(0); + light->setPosition(light_dir); + constexpr bool sun_up = true; + light->setSunPrimary(sun_up); + } + + LLRenderTarget& screen = gPipeline.mAuxillaryRT.screen; + +#if 0 + if (mGLTFMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_OPAQUE || mGLTFMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK) + { + // *TODO: Opaque/alpha mask rendering (gDeferredPBROpaqueProgram) + } + else +#endif + { + // Alpha blend rendering + + screen.bindTarget(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + LLGLSLShader& shader = gDeferredPBRAlphaProgram; + + gPipeline.bindDeferredShader(shader); + fixup_shader_constants(shader); + + for (GLTFPreviewModel& part : preview_sphere) + { + LLRenderPass::pushGLTFBatch(*part.mDrawInfo); + } + + gPipeline.unbindDeferredShader(shader); + + screen.flush(); + } + + gPipeline.copyScreenSpaceReflections(&screen, &gPipeline.mSceneMap); + gPipeline.generateLuminance(&screen, &gPipeline.mLuminanceMap); + gPipeline.generateExposure(&gPipeline.mLuminanceMap, &gPipeline.mExposureMap); + gPipeline.gammaCorrect(&screen, &gPipeline.mPostMap); + LLVertexBuffer::unbind(); + gPipeline.generateGlow(&gPipeline.mPostMap); + gPipeline.combineGlow(&gPipeline.mPostMap, &screen); + gPipeline.renderDoF(&screen, &gPipeline.mPostMap); + gPipeline.applyFXAA(&gPipeline.mPostMap, &screen); + + gDeferredPostNoDoFProgram.bind(); + + // From LLPipeline::renderFinalize: "Whatever is last in the above post processing chain should _always_ be rendered directly here. If not, expect problems." + gDeferredPostNoDoFProgram.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, &screen); + gDeferredPostNoDoFProgram.bindTexture(LLShaderMgr::DEFERRED_DEPTH, mBoundTarget, true); + + { + LLGLDepthTest depth_test(GL_TRUE, GL_TRUE, GL_ALWAYS); + gPipeline.mScreenTriangleVB->setBuffer(); + gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + } + + gDeferredPostNoDoFProgram.unbind(); + + // Clean up + gPipeline.setupHWLights(); + gPipeline.mReflectionMapManager.forceDefaultProbeAndUpdateUniforms(false); + + return TRUE; +} + +void LLGLTFPreviewTexture::postRender(BOOL success) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + if (!mShouldRender) { return; } + mShouldRender = false; + + LLViewerDynamicTexture::postRender(success); +} + +// static +LLPointer<LLViewerTexture> LLGLTFMaterialPreviewMgr::getPreview(LLPointer<LLFetchedGLTFMaterial> &material) +{ + if (!material) + { + return nullptr; + } + + if (!is_material_loaded_enough_for_ui(*material)) + { + return nullptr; + } + + return LLGLTFPreviewTexture::create(material); +} diff --git a/indra/newview/llgltfmaterialpreviewmgr.h b/indra/newview/llgltfmaterialpreviewmgr.h new file mode 100644 index 0000000000..cc40a6f2e2 --- /dev/null +++ b/indra/newview/llgltfmaterialpreviewmgr.h @@ -0,0 +1,82 @@ +/** + * @file llgltfmaterialpreviewmgr.h + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, 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 "lldrawpool.h" +#include "lldynamictexture.h" +#include "llfetchedgltfmaterial.h" +#include "llsingleton.h" +#include "lltexture.h" + +class LLGLTFPreviewTexture : public LLViewerDynamicTexture +{ +protected: + LLGLTFPreviewTexture(LLPointer<LLFetchedGLTFMaterial> material, S32 width); + +public: + // Width scales with size of material's textures + static LLPointer<LLGLTFPreviewTexture> create(LLPointer<LLFetchedGLTFMaterial> material); + + BOOL needsRender() override { return mNeedsRender; } + void preRender(BOOL clear_depth = TRUE) override; + BOOL render() override; + void postRender(BOOL success) override; + + struct MaterialLoadLevels + { + S32 levels[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT]; + + MaterialLoadLevels(); + + S32& operator[](size_t i); + + const S32& operator[](size_t i) const; + + // Less is better + // Returns false if lhs is not strictly less or equal for all levels + bool operator<(const MaterialLoadLevels& other) const; + + // Less is better + // Returns false if lhs is not strictly greater or equal for all levels + bool operator>(const MaterialLoadLevels& other) const; + }; + +private: + LLPointer<LLFetchedGLTFMaterial> mGLTFMaterial; + bool mNeedsRender = true; + bool mShouldRender = true; + MaterialLoadLevels mBestLoad; +}; + +class LLGLTFMaterialPreviewMgr +{ + public: + // Returns null if the material is not loaded yet. + // *NOTE: User should cache the texture if the same material is being previewed + LLPointer<LLViewerTexture> getPreview(LLPointer<LLFetchedGLTFMaterial> &material); +}; + +extern LLGLTFMaterialPreviewMgr gGLTFMaterialPreviewMgr; diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 69674417c1..84f6dd7a4f 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -27,6 +27,9 @@ #include "llviewerprecompiledheaders.h" #include "llreflectionmapmanager.h" + +#include <bitset> + #include "llviewercamera.h" #include "llspatialpartition.h" #include "llviewerregion.h" @@ -1383,3 +1386,32 @@ void LLReflectionMapManager::doOcclusion() } } } + +void LLReflectionMapManager::forceDefaultProbeAndUpdateUniforms(bool force) +{ + static std::bitset<LL_MAX_REFLECTION_PROBE_COUNT> mProbeWasOccluded; + + if (force) + { + for (size_t i = 0; i < mProbes.size(); ++i) + { + auto& probe = mProbes[i]; + mProbeWasOccluded[i] = probe->mOccluded; + if (probe != nullptr && probe != mDefaultProbe) + { + probe->mOccluded = true; + } + } + + updateUniforms(); + } + else + { + for (size_t i = 0; i < mProbes.size(); ++i) + { + auto& probe = mProbes[i]; + llassert(probe->mOccluded == (probe != mDefaultProbe)); + probe->mOccluded = mProbeWasOccluded[i]; + } + } +} diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h index b77a33da89..dd641452ae 100644 --- a/indra/newview/llreflectionmapmanager.h +++ b/indra/newview/llreflectionmapmanager.h @@ -106,6 +106,11 @@ public: // perform occlusion culling on all active reflection probes void doOcclusion(); + // *HACK: "cull" all reflection probes except the default one. Only call + // this if you don't intend to call updateUniforms directly. Call again + // with false when done. + void forceDefaultProbeAndUpdateUniforms(bool force = true); + private: friend class LLPipeline; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 233b864fba..b9cb00b561 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -72,6 +72,7 @@ #include "llradiogroup.h" #include "llfloaterreg.h" +#include "llgltfmaterialpreviewmgr.h" #include "lllocalbitmaps.h" #include "lllocalgltfmaterials.h" #include "llerror.h" @@ -657,6 +658,7 @@ void LLFloaterTexturePicker::draw() if( mOwner ) { mTexturep = NULL; + LLPointer<LLFetchedGLTFMaterial> old_material = mGLTFMaterial; mGLTFMaterial = NULL; if (mImageAssetID.notNull()) { @@ -664,10 +666,23 @@ void LLFloaterTexturePicker::draw() { mGLTFMaterial = (LLFetchedGLTFMaterial*) gGLTFMaterialList.getMaterial(mImageAssetID); llassert(mGLTFMaterial == nullptr || dynamic_cast<LLFetchedGLTFMaterial*>(gGLTFMaterialList.getMaterial(mImageAssetID)) != nullptr); + if (mGLTFPreview.isNull() || mGLTFMaterial.isNull() || (old_material.notNull() && (*old_material.get() != *mGLTFMaterial.get()))) + { + // Only update the preview if needed, since gGLTFMaterialPreviewMgr does not cache the preview. + if (mGLTFMaterial.isNull()) + { + mGLTFPreview = nullptr; + } + else + { + mGLTFPreview = gGLTFMaterialPreviewMgr.getPreview(mGLTFMaterial); + } + } } else { LLPointer<LLViewerFetchedTexture> texture = NULL; + mGLTFPreview = nullptr; if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID)) { @@ -677,7 +692,7 @@ void LLFloaterTexturePicker::draw() if (obj) { LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(mImageAssetID); - texture = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL; + texture = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL; } } @@ -718,27 +733,29 @@ void LLFloaterTexturePicker::draw() // If the floater is focused, don't apply its alpha to the texture (STORM-677). const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); - LLViewerTexture* texture = nullptr; + LLViewerTexture* preview = nullptr; if (mGLTFMaterial) { - texture = mGLTFMaterial->getUITexture(); + preview = mGLTFPreview.get(); } else { - texture = mTexturep.get(); + preview = mTexturep.get(); + if (mTexturep) + { + // Pump the priority + mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); + } } - if( texture ) + if( preview ) { - if( texture->getComponents() == 4 ) + if( preview->getComponents() == 4 ) { gl_rect_2d_checkerboard( interior, alpha ); } - gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), texture, UI_VERTEX_COLOR % alpha ); - - // Pump the priority - texture->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); + gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), preview, UI_VERTEX_COLOR % alpha ); } else if (!mFallbackImage.isNull()) { @@ -2156,48 +2173,69 @@ void LLTextureCtrl::draw() { mBorder->setKeyboardFocusHighlight(hasFocus()); + LLPointer<LLViewerTexture> preview = NULL; + if (!mValid) { mTexturep = NULL; + mGLTFMaterial = NULL; + mGLTFPreview = NULL; } else if (!mImageAssetID.isNull()) { - LLPointer<LLViewerFetchedTexture> texture = NULL; - if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID)) { LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); if (obj) { LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(mImageAssetID); - texture = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL; + mTexturep = viewerTexture ? dynamic_cast<LLViewerFetchedTexture*>(viewerTexture) : NULL; + mGLTFMaterial = NULL; + mGLTFPreview = NULL; + + preview = mTexturep; } } - if (texture.isNull()) + if (preview.isNull()) { + LLPointer<LLFetchedGLTFMaterial> old_material = mGLTFMaterial; + mGLTFMaterial = NULL; + mTexturep = NULL; if (mInventoryPickType == PICK_MATERIAL) { - LLPointer<LLFetchedGLTFMaterial> material = gGLTFMaterialList.getMaterial(mImageAssetID); - if (material) + mGLTFMaterial = gGLTFMaterialList.getMaterial(mImageAssetID); + if (mGLTFPreview.isNull() || mGLTFMaterial.isNull() || (old_material.notNull() && (*old_material.get() != *mGLTFMaterial.get()))) { - texture = material->getUITexture(); + // Only update the preview if needed, since gGLTFMaterialPreviewMgr does not cache the preview. + if (mGLTFMaterial.isNull()) + { + mGLTFPreview = nullptr; + } + else + { + mGLTFPreview = gGLTFMaterialPreviewMgr.getPreview(mGLTFMaterial); + } } + + preview = mGLTFPreview; } else { - texture = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - texture->setBoostLevel(LLGLTexture::BOOST_PREVIEW); - texture->forceToSaveRawImage(0); + mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + mTexturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + mTexturep->forceToSaveRawImage(0); + + preview = mTexturep; } } - - mTexturep = texture; } else//mImageAssetID == LLUUID::null { mTexturep = NULL; + mGLTFMaterial = NULL; + mGLTFPreview = NULL; } // Border @@ -2210,15 +2248,18 @@ void LLTextureCtrl::draw() // If we're in a focused floater, don't apply the floater's alpha to the texture (STORM-677). const F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); - if( mTexturep ) + if( preview ) { - if( mTexturep->getComponents() == 4 ) + if( preview->getComponents() == 4 ) { gl_rect_2d_checkerboard( interior, alpha ); } - gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha); - mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); + gl_draw_scaled_image( interior.mLeft, interior.mBottom, interior.getWidth(), interior.getHeight(), preview, UI_VERTEX_COLOR % alpha); + if (mTexturep) + { + mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); + } } else if (!mFallbackImage.isNull()) { diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index cb6ce636e0..77919637ac 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -250,6 +250,8 @@ private: commit_callback_t mOnCloseCallback; texture_selected_callback mOnTextureSelectedCallback; LLPointer<LLViewerFetchedTexture> mTexturep; + LLPointer<LLFetchedGLTFMaterial> mGLTFMaterial; + LLPointer<LLViewerTexture> mGLTFPreview; LLUIColor mBorderColor; LLUUID mImageItemID; LLUUID mImageAssetID; @@ -382,6 +384,7 @@ protected: LLPointer<LLViewerTexture> mTexturep; LLPointer<LLFetchedGLTFMaterial> mGLTFMaterial; + LLPointer<LLViewerTexture> mGLTFPreview; LLView* mOwner; LLUUID mImageAssetID; // Currently selected texture diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 3882472b49..f34d5360e2 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -163,6 +163,7 @@ F32 LLPipeline::CameraFocusTransitionTime; F32 LLPipeline::CameraFNumber; F32 LLPipeline::CameraFocalLength; F32 LLPipeline::CameraFieldOfView; +S32 LLPipeline::RenderLocalLightCount; F32 LLPipeline::RenderShadowNoise; F32 LLPipeline::RenderShadowBlurSize; F32 LLPipeline::RenderSSAOScale; @@ -200,6 +201,8 @@ S32 LLPipeline::RenderScreenSpaceReflectionGlossySamples; S32 LLPipeline::RenderBufferVisualization; LLTrace::EventStatHandle<S64> LLPipeline::sStatBatchSize("renderbatchsize"); +const U32 LLPipeline::MAX_BAKE_WIDTH = 512; + const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f; const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f; const F32 ALPHA_BLEND_CUTOFF = 0.598f; @@ -521,6 +524,7 @@ void LLPipeline::init() connectRefreshCachedSettingsSafe("CameraFNumber"); connectRefreshCachedSettingsSafe("CameraFocalLength"); connectRefreshCachedSettingsSafe("CameraFieldOfView"); + connectRefreshCachedSettingsSafe("RenderLocalLightCount"); connectRefreshCachedSettingsSafe("RenderShadowNoise"); connectRefreshCachedSettingsSafe("RenderShadowBlurSize"); connectRefreshCachedSettingsSafe("RenderSSAOScale"); @@ -1009,6 +1013,7 @@ void LLPipeline::refreshCachedSettings() CameraFNumber = gSavedSettings.getF32("CameraFNumber"); CameraFocalLength = gSavedSettings.getF32("CameraFocalLength"); CameraFieldOfView = gSavedSettings.getF32("CameraFieldOfView"); + RenderLocalLightCount = gSavedSettings.getS32("RenderLocalLightCount"); RenderShadowNoise = gSavedSettings.getF32("RenderShadowNoise"); RenderShadowBlurSize = gSavedSettings.getF32("RenderShadowBlurSize"); RenderSSAOScale = gSavedSettings.getF32("RenderSSAOScale"); @@ -1072,7 +1077,6 @@ void LLPipeline::releaseGLBuffers() releaseLUTBuffers(); mWaterDis.release(); - mBake.release(); mSceneMap.release(); @@ -1151,9 +1155,6 @@ void LLPipeline::createGLBuffers() stop_glerror(); assertInitialized(); - // Use FBO for bake tex - mBake.allocate(512, 512, GL_RGBA, true); // SL-12781 Build > Upload > Model; 3D Preview - stop_glerror(); GLuint resX = gViewerWindow->getWorldViewWidthRaw(); @@ -5227,7 +5228,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) return; } - static LLCachedControl<S32> local_light_count(gSavedSettings, "RenderLocalLightCount", 256); + const S32 local_light_count = LLPipeline::RenderLocalLightCount; if (local_light_count >= 1) { @@ -5496,7 +5497,7 @@ void LLPipeline::setupHWLights() mLightMovingMask = 0; - static LLCachedControl<S32> local_light_count(gSavedSettings, "RenderLocalLightCount", 256); + const S32 local_light_count = LLPipeline::RenderLocalLightCount; if (local_light_count >= 1) { @@ -7930,7 +7931,7 @@ void LLPipeline::renderDeferredLighting() unbindDeferredShader(gDeferredSoftenProgram); } - static LLCachedControl<S32> local_light_count(gSavedSettings, "RenderLocalLightCount", 256); + const S32 local_light_count = LLPipeline::RenderLocalLightCount; if (local_light_count > 0) { diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 88a7eab813..dd5040f76e 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -694,6 +694,7 @@ public: RenderTargetPack mMainRT; // auxillary 512x512 render target pack + // used by reflection probes and dynamic texture bakes RenderTargetPack mAuxillaryRT; // currently used render target pack @@ -754,7 +755,7 @@ public: //water distortion texture (refraction) LLRenderTarget mWaterDis; - LLRenderTarget mBake; + static const U32 MAX_BAKE_WIDTH; //texture for making the glow LLRenderTarget mGlow[3]; @@ -1012,6 +1013,7 @@ public: static F32 CameraFNumber; static F32 CameraFocalLength; static F32 CameraFieldOfView; + static S32 RenderLocalLightCount; static F32 RenderShadowNoise; static F32 RenderShadowBlurSize; static F32 RenderSSAOScale; |