diff --git a/autobuild.xml b/autobuild.xml index 733d2253bb..bb13eb40bd 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3465,6 +3465,36 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors version 0.54.1.555529 + xxhash + + copyright + Copyright 2012-2020 Yann Collet + description + xxHash Extremely fast hash algorithm + license + bsd + license_file + LICENSES/xxhash.txt + name + xxhash + platforms + + common + + archive + + hash + e4f77ba0a9b8ec3cc3fabc51c4da81d2 + url + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/110070/956941/xxhash-0.8.1.578006-windows-578006.tar.bz2 + + name + common + + + version + 0.8.1 + zlib-ng canonical_repo diff --git a/doc/contributions.txt b/doc/contributions.txt index 2f073cdcc9..f1eb342f43 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -588,6 +588,8 @@ Henri Beauchamp VWR-1320 VWR-1406 VWR-4157 + SL-15175 + SL-19110 herina Bode Hikkoshi Sakai VWR-429 diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 7bd4dce8fc..94f1c29493 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -96,6 +96,7 @@ set(cmake_SOURCE_FILES VisualLeakDetector.cmake LibVLCPlugin.cmake XmlRpcEpi.cmake + xxHash.cmake ZLIBNG.cmake ) diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 53871791fd..528b43c3fc 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -4,6 +4,7 @@ include(APR) include(Boost) include(EXPAT) include(Tracy) +include(xxHash) include(ZLIBNG) set(LLCOMMON_INCLUDE_DIRS diff --git a/indra/cmake/xxHash.cmake b/indra/cmake/xxHash.cmake new file mode 100644 index 0000000000..a7c1cba62c --- /dev/null +++ b/indra/cmake/xxHash.cmake @@ -0,0 +1,8 @@ +# -*- cmake -*- +if (XXHASH_CMAKE_INCLUDED) + return() +endif (XXHASH_CMAKE_INCLUDED) +set (XXHASH_CMAKE_INCLUDED TRUE) + +include(Prebuilt) +use_prebuilt_binary(xxhash) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index a1a8ac8c15..527e8e12a3 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -119,6 +119,7 @@ set(llcommon_SOURCE_FILES lluriparser.cpp lluuid.cpp llworkerthread.cpp + hbxxh.cpp u64.cpp threadpool.cpp workqueue.cpp @@ -257,6 +258,7 @@ set(llcommon_HEADER_FILES llwin32headers.h llwin32headerslean.h llworkerthread.h + hbxxh.h lockstatic.h stdtypes.h stringize.h diff --git a/indra/llcommon/hbxxh.cpp b/indra/llcommon/hbxxh.cpp new file mode 100644 index 0000000000..388269d6c8 --- /dev/null +++ b/indra/llcommon/hbxxh.cpp @@ -0,0 +1,377 @@ +/** + * @file hbxxh.cpp + * @brief High performances vectorized hashing based on xxHash. + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (c) 2023, Henri Beauchamp. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +// This define ensures that xxHash will be compiled within this module, with +// vectorized (*) and inlined functions (with no exported API symbol); our +// xxhash "pre-built library" package actually only contains the xxhash.h +// header (no library needed at link time). +// (*) SSE2 is normally used for x86(_64) builds, unless you enabled AVX2 +// in your build, in which case the latter would be used instead. For ARM64 +// builds, this would also automatically enable NEON vectorization. +#define XXH_INLINE_ALL +#include "xxhash/xxhash.h" + +#include "hbxxh.h" + +// How many bytes to grab at a time when hashing files or streams +constexpr size_t BLOCK_LEN = 4096; + +/////////////////////////////////////////////////////////////////////////////// +// HBXXH64 class +/////////////////////////////////////////////////////////////////////////////// + +//static +U64 HBXXH64::digest(const void* buffer, size_t len) +{ + return XXH3_64bits(buffer, len); +} + +//static +U64 HBXXH64::digest(const char* str) +{ + return XXH3_64bits((const void*)str, strlen(str)); +} + +//static +U64 HBXXH64::digest(const std::string& str) +{ + return XXH3_64bits((const void*)str.c_str(), str.size()); +} + +// Must be called by all constructors. +void HBXXH64::init() +{ + mDigest = 0; + mState = (void*)XXH3_createState(); + if (!mState || XXH3_64bits_reset((XXH3_state_t*)mState) != XXH_OK) + { + LL_WARNS() << "Failed to initialize state !" << LL_ENDL; + } +} + +HBXXH64::~HBXXH64() +{ + if (mState) + { + XXH3_freeState((XXH3_state_t*)mState); + } +} + +void HBXXH64::update(const void* buffer, size_t len) +{ + if (mState) + { + XXH3_64bits_update((XXH3_state_t*)mState, buffer, len); + } + else + { + LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL; + } +} + +void HBXXH64::update(const std::string& str) +{ + if (mState) + { + XXH3_64bits_update((XXH3_state_t*)mState, (const void*)str.c_str(), + str.length()); + } + else + { + LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL; + } +} + +void HBXXH64::update(std::istream& stream) +{ + if (!mState) + { + LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL; + return; + } + + char buffer[BLOCK_LEN]; + size_t len; + while (stream.good()) + { + stream.read(buffer, BLOCK_LEN); + len = stream.gcount(); + XXH3_64bits_update((XXH3_state_t*)mState, (const void*)buffer, len); + } +} + +void HBXXH64::update(FILE* file) +{ + if (!mState) + { + LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL; + return; + } + + char buffer[BLOCK_LEN]; + size_t len; + while ((len = fread((void*)buffer, 1, BLOCK_LEN, file))) + { + XXH3_64bits_update((XXH3_state_t*)mState, (const void*)buffer, len); + } + fclose(file); +} + +void HBXXH64::finalize() +{ + if (!mState) + { + LL_WARNS() << "Already finalized !" << LL_ENDL; + return; + } + mDigest = XXH3_64bits_digest((XXH3_state_t*)mState); + XXH3_freeState((XXH3_state_t*)mState); + mState = NULL; +} + +U64 HBXXH64::digest() const +{ + return mState ? XXH3_64bits_digest((XXH3_state_t*)mState) : mDigest; +} + +std::ostream& operator<<(std::ostream& stream, HBXXH64 context) +{ + stream << context.digest(); + return stream; +} + +/////////////////////////////////////////////////////////////////////////////// +// HBXXH128 class +/////////////////////////////////////////////////////////////////////////////// + +//static +LLUUID HBXXH128::digest(const void* buffer, size_t len) +{ + XXH128_hash_t hash = XXH3_128bits(buffer, len); + LLUUID id; + U64* data = (U64*)id.mData; + // Note: we do not check endianness here and we just store in the same + // order as XXH128_hash_t, that is low word "first". + data[0] = hash.low64; + data[1] = hash.high64; + return id; +} + +//static +LLUUID HBXXH128::digest(const char* str) +{ + XXH128_hash_t hash = XXH3_128bits((const void*)str, strlen(str)); + LLUUID id; + U64* data = (U64*)id.mData; + // Note: we do not check endianness here and we just store in the same + // order as XXH128_hash_t, that is low word "first". + data[0] = hash.low64; + data[1] = hash.high64; + return id; +} + +//static +LLUUID HBXXH128::digest(const std::string& str) +{ + XXH128_hash_t hash = XXH3_128bits((const void*)str.c_str(), str.size()); + LLUUID id; + U64* data = (U64*)id.mData; + // Note: we do not check endianness here and we just store in the same + // order as XXH128_hash_t, that is low word "first". + data[0] = hash.low64; + data[1] = hash.high64; + return id; +} + +//static +void HBXXH128::digest(LLUUID& result, const void* buffer, size_t len) +{ + XXH128_hash_t hash = XXH3_128bits(buffer, len); + U64* data = (U64*)result.mData; + // Note: we do not check endianness here and we just store in the same + // order as XXH128_hash_t, that is low word "first". + data[0] = hash.low64; + data[1] = hash.high64; +} + +//static +void HBXXH128::digest(LLUUID& result, const char* str) +{ + XXH128_hash_t hash = XXH3_128bits((const void*)str, strlen(str)); + U64* data = (U64*)result.mData; + // Note: we do not check endianness here and we just store in the same + // order as XXH128_hash_t, that is low word "first". + data[0] = hash.low64; + data[1] = hash.high64; +} + +//static +void HBXXH128::digest(LLUUID& result, const std::string& str) +{ + XXH128_hash_t hash = XXH3_128bits((const void*)str.c_str(), str.size()); + U64* data = (U64*)result.mData; + // Note: we do not check endianness here and we just store in the same + // order as XXH128_hash_t, that is low word "first". + data[0] = hash.low64; + data[1] = hash.high64; +} + +// Must be called by all constructors. +void HBXXH128::init() +{ + mState = (void*)XXH3_createState(); + if (!mState || XXH3_128bits_reset((XXH3_state_t*)mState) != XXH_OK) + { + LL_WARNS() << "Failed to initialize state !" << LL_ENDL; + } +} + +HBXXH128::~HBXXH128() +{ + if (mState) + { + XXH3_freeState((XXH3_state_t*)mState); + } +} + +void HBXXH128::update(const void* buffer, size_t len) +{ + if (mState) + { + XXH3_128bits_update((XXH3_state_t*)mState, buffer, len); + } + else + { + LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL; + } +} + +void HBXXH128::update(const std::string& str) +{ + if (mState) + { + XXH3_128bits_update((XXH3_state_t*)mState, (const void*)str.c_str(), + str.length()); + } + else + { + LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL; + } +} + +void HBXXH128::update(std::istream& stream) +{ + if (!mState) + { + LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL; + return; + } + + char buffer[BLOCK_LEN]; + size_t len; + while (stream.good()) + { + stream.read(buffer, BLOCK_LEN); + len = stream.gcount(); + XXH3_128bits_update((XXH3_state_t*)mState, (const void*)buffer, len); + } +} + +void HBXXH128::update(FILE* file) +{ + if (!mState) + { + LL_WARNS() << "Cannot update a finalized digest !" << LL_ENDL; + return; + } + + char buffer[BLOCK_LEN]; + size_t len; + while ((len = fread((void*)buffer, 1, BLOCK_LEN, file))) + { + XXH3_128bits_update((XXH3_state_t*)mState, (const void*)buffer, len); + } + fclose(file); +} + +void HBXXH128::finalize() +{ + if (!mState) + { + LL_WARNS() << "Already finalized !" << LL_ENDL; + return; + } + XXH128_hash_t hash = XXH3_128bits_digest((XXH3_state_t*)mState); + U64* data = (U64*)mDigest.mData; + // Note: we do not check endianness here and we just store in the same + // order as XXH128_hash_t, that is low word "first". + data[0] = hash.low64; + data[1] = hash.high64; + XXH3_freeState((XXH3_state_t*)mState); + mState = NULL; +} + +const LLUUID& HBXXH128::digest() const +{ + if (mState) + { + XXH128_hash_t hash = XXH3_128bits_digest((XXH3_state_t*)mState); + // We cheat the const-ness of the method here, but this is OK, since + // mDigest is private and cannot be accessed indirectly by other + // methods than digest() ones, that do check for mState to decide + // wether mDigest's current value may be provided as is or not. This + // cheat saves us a temporary LLLUID copy. + U64* data = (U64*)mDigest.mData; + // Note: we do not check endianness here and we just store in the same + // order as XXH128_hash_t, that is low word "first". + data[0] = hash.low64; + data[1] = hash.high64; + } + return mDigest; +} + +void HBXXH128::digest(LLUUID& result) const +{ + if (!mState) + { + result = mDigest; + return; + } + XXH128_hash_t hash = XXH3_128bits_digest((XXH3_state_t*)mState); + U64* data = (U64*)result.mData; + // Note: we do not check endianness here and we just store in the same + // order as XXH128_hash_t, that is low word "first". + data[0] = hash.low64; + data[1] = hash.high64; +} + +std::ostream& operator<<(std::ostream& stream, HBXXH128 context) +{ + stream << context.digest(); + return stream; +} diff --git a/indra/llcommon/hbxxh.h b/indra/llcommon/hbxxh.h new file mode 100644 index 0000000000..236716722a --- /dev/null +++ b/indra/llcommon/hbxxh.h @@ -0,0 +1,259 @@ +/** + * @file hbxxh.h + * @brief High performances vectorized hashing based on xxHash. + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (c) 2023, Henri Beauchamp. + * + * 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$ + */ + +#ifndef LL_HBXXH_H +#define LL_HBXXH_H + +#include "lluuid.h" + +// HBXXH* classes are to be used where speed matters and cryptographic quality +// is not required (no "one-way" guarantee, though they are likely not worst in +// this respect than MD5 which got busted and is now considered too weak). The +// xxHash code they are built upon is vectorized and about 50 times faster than +// MD5. A 64 bits hash class is also provided for when 128 bits of entropy are +// not needed. The hashes collision rate is similar to MD5's. +// See https://github.com/Cyan4973/xxHash#readme for details. + +// 64 bits hashing class + +class HBXXH64 +{ + friend std::ostream& operator<<(std::ostream&, HBXXH64); + +protected: + LOG_CLASS(HBXXH64); + +public: + inline HBXXH64() { init(); } + + // Constructors for special circumstances; they all digest the first passed + // parameter. Set 'do_finalize' to false if you do not want to finalize the + // context, which is useful/needed when you want to update() it afterwards. + // Ideally, the compiler should be smart enough to get our clue and + // optimize out the const bool test during inlining... + + inline HBXXH64(const void* buffer, size_t len, + const bool do_finalize = true) + { + init(); + update(buffer, len); + if (do_finalize) + { + finalize(); + } + } + + inline HBXXH64(const std::string& str, const bool do_finalize = true) + { + init(); + update(str); + if (do_finalize) + { + finalize(); + } + } + + inline HBXXH64(std::istream& s, const bool do_finalize = true) + { + init(); + update(s); + if (do_finalize) + { + finalize(); + } + } + + inline HBXXH64(FILE* file, const bool do_finalize = true) + { + init(); + update(file); + if (do_finalize) + { + finalize(); + } + } + + ~HBXXH64(); + + void update(const void* buffer, size_t len); + void update(const std::string& str); + void update(std::istream& s); + void update(FILE* file); + + // Note that unlike what happens with LLMD5, you do not need to finalize() + // HBXXH64 before using digest(), and you may keep updating() it even after + // you got a first digest() (the next digest would of course change after + // any update). It is still useful to use finalize() when you do not want + // to store a final digest() result in a separate U64; after this method + // has been called, digest() simply returns mDigest value. + void finalize(); + + U64 digest() const; + + // Fast static methods. Use them when hashing just one contiguous block of + // data. + static U64 digest(const void* buffer, size_t len); + static U64 digest(const char* str); // str must be NUL-terminated + static U64 digest(const std::string& str); + +private: + void init(); + +private: + // We use a void pointer to avoid including xxhash.h here for XXH3_state_t + // (which cannot either be trivially forward-declared, due to complex API + // related pre-processor macros in xxhash.h). + void* mState; + U64 mDigest; +}; + +inline bool operator==(const HBXXH64& a, const HBXXH64& b) +{ + return a.digest() == b.digest(); +} + +inline bool operator!=(const HBXXH64& a, const HBXXH64& b) +{ + return a.digest() != b.digest(); +} + +// 128 bits hashing class + +class HBXXH128 +{ + friend std::ostream& operator<<(std::ostream&, HBXXH128); + +protected: + LOG_CLASS(HBXXH128); + +public: + inline HBXXH128() { init(); } + + // Constructors for special circumstances; they all digest the first passed + // parameter. Set 'do_finalize' to false if you do not want to finalize the + // context, which is useful/needed when you want to update() it afterwards. + // Ideally, the compiler should be smart enough to get our clue and + // optimize out the const bool test during inlining... + + inline HBXXH128(const void* buffer, size_t len, + const bool do_finalize = true) + { + init(); + update(buffer, len); + if (do_finalize) + { + finalize(); + } + } + + inline HBXXH128(const std::string& str, const bool do_finalize = true) + { + init(); + update(str); + if (do_finalize) + { + finalize(); + } + } + + inline HBXXH128(std::istream& s, const bool do_finalize = true) + { + init(); + update(s); + if (do_finalize) + { + finalize(); + } + } + + inline HBXXH128(FILE* file, const bool do_finalize = true) + { + init(); + update(file); + if (do_finalize) + { + finalize(); + } + } + + ~HBXXH128(); + + void update(const void* buffer, size_t len); + void update(const std::string& str); + void update(std::istream& s); + void update(FILE* file); + + // Note that unlike what happens with LLMD5, you do not need to finalize() + // HBXXH128 before using digest(), and you may keep updating() it even + // after you got a first digest() (the next digest would of course change + // after any update). It is still useful to use finalize() when you do not + // want to store a final digest() result in a separate LLUUID; after this + // method has been called, digest() simply returns a reference on mDigest. + void finalize(); + + // We use an LLUUID for the digest, since this is a 128 bits wide native + // type available in the viewer code, making it easy to manipulate. It also + // allows to use HBXXH128 efficiently in LLUUID generate() and combine() + // methods. + const LLUUID& digest() const; + + // Here, we avoid an LLUUID copy whenever we already got one to store the + // result *and* we did not yet call finalize(). + void digest(LLUUID& result) const; + + // Fast static methods. Use them when hashing just one contiguous block of + // data. + static LLUUID digest(const void* buffer, size_t len); + static LLUUID digest(const char* str); // str must be NUL-terminated + static LLUUID digest(const std::string& str); + // Same as above, but saves you from an LLUUID copy when you already got + // one for storage use. + static void digest(LLUUID& result, const void* buffer, size_t len); + static void digest(LLUUID& result, const char* str); // str NUL-terminated + static void digest(LLUUID& result, const std::string& str); + +private: + void init(); + +private: + // We use a void pointer to avoid including xxhash.h here for XXH3_state_t + // (which cannot either be trivially forward-declared, due to complex API + // related pre-processor macros in xxhash.h). + void* mState; + LLUUID mDigest; +}; + +inline bool operator==(const HBXXH128& a, const HBXXH128& b) +{ + return a.digest() == b.digest(); +} + +inline bool operator!=(const HBXXH128& a, const HBXXH128& b) +{ + return a.digest() != b.digest(); +} + +#endif // LL_HBXXH_H diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h index 5f2eff26db..3222e662ee 100644 --- a/indra/llcommon/llprofiler.h +++ b/indra/llcommon/llprofiler.h @@ -96,7 +96,7 @@ namespace LLProfiler //// GPU Mutually exclusive with detailed memory tracing // #define LL_PROFILER_ENABLE_TRACY_OPENGL 0 #define LL_PROFILER_ENABLE_TRACY_MEMORY 1 - #define LL_PROFILER_ENABLE_TRACY_OPENGL 1 + #define LL_PROFILER_ENABLE_TRACY_OPENGL 0 // Enable RenderDoc labeling #define LL_PROFILER_ENABLE_RENDER_DOC 0 diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 105ea924cc..51b324199e 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -40,11 +40,12 @@ #include "lluuid.h" #include "llerror.h" #include "llrand.h" -#include "llmd5.h" #include "llstring.h" #include "lltimer.h" #include "llthread.h" #include "llmutex.h" +#include "hbxxh.h" + #include "llprofiler.h" const LLUUID LLUUID::null; const LLTransactionID LLTransactionID::tnull; @@ -405,11 +406,9 @@ LLUUID LLUUID::operator^(const LLUUID& rhs) const void LLUUID::combine(const LLUUID& other, LLUUID& result) const { - LLMD5 md5_uuid; - md5_uuid.update((unsigned char*)mData, 16); - md5_uuid.update((unsigned char*)other.mData, 16); - md5_uuid.finalize(); - md5_uuid.raw_digest(result.mData); + HBXXH128 hash((const void*)mData, 16, false); // false = do not finalize + hash.update((const void*)other.mData, 16); + hash.digest(result); } LLUUID LLUUID::combine(const LLUUID &other) const @@ -860,17 +859,12 @@ void LLUUID::generate() tmp >>= 8; mData[8] = (unsigned char) tmp; - LLMD5 md5_uuid; - - md5_uuid.update(mData,16); - md5_uuid.finalize(); - md5_uuid.raw_digest(mData); + HBXXH128::digest(*this, (const void*)mData, 16); } void LLUUID::generate(const std::string& hash_string) { - LLMD5 md5_uuid((U8*)hash_string.c_str()); - md5_uuid.raw_digest(mData); + HBXXH128::digest(*this, hash_string); } U32 LLUUID::getRandomSeed() @@ -888,13 +882,8 @@ U32 LLUUID::getRandomSeed() seed[7]=(unsigned char)(pid); getSystemTime((uuid_time_t *)(&seed[8])); - LLMD5 md5_seed; - - md5_seed.update(seed,16); - md5_seed.finalize(); - md5_seed.raw_digest(seed); - - return(*(U32 *)seed); + U64 seed64 = HBXXH64((const void*)seed, 16).digest(); + return U32(seed64) ^ U32(seed64 >> 32); } BOOL LLUUID::parseUUID(const std::string& buf, LLUUID* value) diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 2307a77bfc..39b81244be 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -31,7 +31,7 @@ #include "llconvexdecomposition.h" #include "llsdserialize.h" #include "llvector4a.h" -#include "llmd5.h" +#include "hbxxh.h" #include "llcontrol.h" #ifdef LL_USESYSTEMLIBS @@ -1597,7 +1597,7 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_positi void LLMeshSkinInfo::updateHash() { // get hash of data relevant to render batches - LLMD5 hash; + HBXXH64 hash; //mJointNames for (auto& name : mJointNames) @@ -1608,24 +1608,19 @@ void LLMeshSkinInfo::updateHash() } //mJointNums - hash.update((U8*)&(mJointNums[0]), sizeof(S32) * mJointNums.size()); + hash.update((const void*)mJointNums.data(), sizeof(S32) * mJointNums.size()); //mInvBindMatrix F32* src = mInvBindMatrix[0].getF32ptr(); - for (int i = 0; i < mInvBindMatrix.size() * 16; ++i) + for (size_t i = 0, count = mInvBindMatrix.size() * 16; i < count; ++i) { S32 t = llround(src[i] * 10000.f); - hash.update((U8*)&t, sizeof(S32)); + hash.update((const void*)&t, sizeof(S32)); } - //hash.update((U8*)&(mInvBindMatrix[0]), sizeof(LLMatrix4a) * mInvBindMatrix.size()); + //hash.update((const void*)mInvBindMatrix.data(), sizeof(LLMatrix4a) * mInvBindMatrix.size()); - hash.finalize(); - - U64 digest[2]; - hash.raw_digest((U8*) digest); - - mHash = digest[0]; + mHash = hash.digest(); } U32 LLMeshSkinInfo::sizeBytes() const diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 6045c4f0ca..735a624649 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -86,7 +86,7 @@ void APIENTRY gl_debug_callback(GLenum source, const GLchar* message, GLvoid* userParam) { - if (severity != GL_DEBUG_SEVERITY_HIGH // && + if (severity != GL_DEBUG_SEVERITY_HIGH //&& //severity != GL_DEBUG_SEVERITY_MEDIUM && //severity != GL_DEBUG_SEVERITY_LOW ) @@ -112,10 +112,28 @@ void APIENTRY gl_debug_callback(GLenum source, glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vao); GLint vbo = 0; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vbo); + GLint vbo_size = 0; + if (vbo != 0) + { + glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &vbo_size); + } GLint ibo = 0; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &ibo); - - if (severity == GL_DEBUG_SEVERITY_HIGH) + GLint ibo_size = 0; + if (ibo != 0) + { + glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &ibo_size); + } + GLint ubo = 0; + glGetIntegerv(GL_UNIFORM_BUFFER_BINDING, &ubo); + GLint ubo_size = 0; + GLint ubo_immutable = 0; + if (ubo != 0) + { + glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_SIZE, &ubo_size); + glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_IMMUTABLE_STORAGE, &ubo_immutable); + } + //if (severity == GL_DEBUG_SEVERITY_HIGH) { LL_ERRS() << "Halting on GL Error" << LL_ENDL; } @@ -1018,8 +1036,6 @@ bool LLGLManager::initGL() LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL; } - stop_glerror(); - #if 0 && LL_WINDOWS if (!glGetStringi) { @@ -1055,8 +1071,6 @@ bool LLGLManager::initGL() } #endif - stop_glerror(); - // Extract video card strings and convert to upper case to // work around driver-to-driver variation in capitalization. mGLVendor = ll_safe_string((const char *)glGetString(GL_VENDOR)); @@ -1128,10 +1142,8 @@ bool LLGLManager::initGL() mGLVendorShort = "MISC"; } - stop_glerror(); // This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture. initExtensions(); - stop_glerror(); S32 old_vram = mVRAM; mVRAM = 0; @@ -1195,29 +1207,19 @@ bool LLGLManager::initGL() LL_WARNS("RenderInit") << "VRAM detected via MemInfo OpenGL extension most likely broken. Reverting to " << mVRAM << " MB" << LL_ENDL; } - stop_glerror(); - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mNumTextureImageUnits); - stop_glerror(); glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &mMaxColorTextureSamples); - stop_glerror(); glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &mMaxDepthTextureSamples); - stop_glerror(); glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples); - stop_glerror(); glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords); - stop_glerror(); glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples); - stop_glerror(); if (mGLVersion >= 4.59f) { glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &mMaxAnisotropy); - stop_glerror(); } initGLStates(); - stop_glerror(); return true; } @@ -2271,7 +2273,7 @@ void do_assert_glerror() GLenum error; error = glGetError(); BOOL quit = FALSE; - while (LL_UNLIKELY(error)) + if (LL_UNLIKELY(error)) { quit = TRUE; GLubyte const * gl_error_msg = gluErrorString(error); @@ -2296,7 +2298,6 @@ void do_assert_glerror() gFailLog << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << std::endl; } } - error = glGetError(); } if (quit) @@ -2412,12 +2413,13 @@ void LLGLState::checkStates(GLboolean writeAlpha) llassert_always(src == GL_SRC_ALPHA); llassert_always(dst == GL_ONE_MINUS_SRC_ALPHA); - GLboolean colorMask[4]; - glGetBooleanv(GL_COLOR_WRITEMASK, colorMask); - llassert_always(colorMask[0]); - llassert_always(colorMask[1]); - llassert_always(colorMask[2]); - llassert_always(colorMask[3] == writeAlpha); + // disable for now until usage is consistent + //GLboolean colorMask[4]; + //glGetBooleanv(GL_COLOR_WRITEMASK, colorMask); + //llassert_always(colorMask[0]); + //llassert_always(colorMask[1]); + //llassert_always(colorMask[2]); + // llassert_always(colorMask[3] == writeAlpha); for (boost::unordered_map::iterator iter = sStateMap.begin(); iter != sStateMap.end(); ++iter) diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index a4cdf4787f..3d54b16fff 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -1043,26 +1043,10 @@ void LLGLSLShader::bind(bool rigged) } } -void LLGLSLShader::unbind() +void LLGLSLShader::unbind(void) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; gGL.flush(); - if (sCurBoundShaderPtr) - { - sCurBoundShaderPtr->readProfileQuery(); - } - stop_glerror(); - LLVertexBuffer::unbind(); - glUseProgram(0); - sCurBoundShader = 0; - sCurBoundShaderPtr = NULL; - stop_glerror(); -} - -void LLGLSLShader::bindNoShader(void) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; - LLVertexBuffer::unbind(); if (sCurBoundShaderPtr) @@ -1136,6 +1120,11 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode) return uniform; } +S32 LLGLSLShader::getTextureChannel(S32 uniform) const +{ + return mTexture[uniform]; +} + S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 0522f78614..6c18282fec 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -240,6 +240,9 @@ public: S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); + // get the texture channel of the given uniform, or -1 if uniform is not used as a texture + S32 getTextureChannel(S32 uniform) const; + // bindTexture returns the texture unit we've bound the texture to. // You can reuse the return value to unbind a texture when required. S32 bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); @@ -251,10 +254,9 @@ public: void bind(); //helper to conditionally bind mRiggedVariant instead of this void bind(bool rigged); - void unbind(); - + // Unbinds any previously bound shader by explicitly binding no shader. - static void bindNoShader(void); + static void unbind(); U32 mMatHash[LLRender::NUM_MATRIX_MODES]; U32 mLightHash; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 77785b1fe8..8bb87584ec 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1428,6 +1428,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt { case GL_UNSIGNED_BYTE: case GL_BYTE: + case GL_UNSIGNED_INT_8_8_8_8_REV: type_width = 1; break; case GL_UNSIGNED_SHORT: diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index 0d87800690..f1e5b71207 100644 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -376,7 +376,7 @@ void LLPostProcess::doEffects(void) checkError(); applyShaders(); - LLGLSLShader::bindNoShader(); + LLGLSLShader::unbind(); checkError(); /// Change to a perspective view diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 3e709f03f7..42265274a4 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -35,7 +35,7 @@ #include "llrendertarget.h" #include "lltexture.h" #include "llshadermgr.h" -#include "llmd5.h" +#include "hbxxh.h" #if LL_WINDOWS extern void APIENTRY gl_debug_callback(GLenum source, @@ -55,8 +55,14 @@ F32 gGLModelView[16]; F32 gGLLastModelView[16]; F32 gGLLastProjection[16]; F32 gGLProjection[16]; + +// transform from last frame's camera space to this frame's camera space (and inverse) +F32 gGLDeltaModelView[16]; +F32 gGLInverseDeltaModelView[16]; + S32 gGLViewport[4]; + U32 LLRender::sUICalls = 0; U32 LLRender::sUIVerts = 0; U32 LLTexUnit::sWhiteTexture = 0; @@ -73,7 +79,7 @@ struct LLVBCache std::chrono::steady_clock::time_point touched; }; -static std::unordered_map sVBCache; +static std::unordered_map sVBCache; static const GLenum sGLTextureType[] = { @@ -372,11 +378,7 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) if (bindDepth) { - - if (renderTarget->getDepth() && !renderTarget->canSampleDepth()) - { - LL_ERRS() << "Cannot bind a render buffer for sampling. Allocate render target with depth buffer sampling enabled." << LL_ENDL; - } + llassert(renderTarget->getDepth()); // target MUST have a depth buffer attachment bindManual(renderTarget->getUsage(), renderTarget->getDepth()); } @@ -1682,7 +1684,7 @@ void LLRender::flush() if (mBuffer) { - LLMD5 hash; + HBXXH64 hash; U32 attribute_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask; { @@ -1702,8 +1704,8 @@ void LLRender::flush() hash.finalize(); } - size_t vhash[2]; - hash.raw_digest((unsigned char*) vhash); + + U64 vhash = hash.digest(); // check the VB cache before making a new vertex buffer // This is a giant hack to deal with (mostly) our terrible UI rendering code @@ -1714,7 +1716,7 @@ void LLRender::flush() // To leverage this, we maintain a running hash of the vertex stream being // built up before a flush, and then check that hash against a VB // cache just before creating a vertex buffer in VRAM - std::unordered_map::iterator cache = sVBCache.find(vhash[0]); + std::unordered_map::iterator cache = sVBCache.find(vhash); LLPointer vb; @@ -1747,7 +1749,7 @@ void LLRender::flush() vb->unbind(); - sVBCache[vhash[0]] = { vb , std::chrono::steady_clock::now() }; + sVBCache[vhash] = { vb , std::chrono::steady_clock::now() }; static U32 miss_count = 0; miss_count++; @@ -1759,7 +1761,7 @@ void LLRender::flush() using namespace std::chrono_literals; // every 1024 misses, clean the cache of any VBs that haven't been touched in the last second - for (std::unordered_map::iterator iter = sVBCache.begin(); iter != sVBCache.end(); ) + for (std::unordered_map::iterator iter = sVBCache.begin(); iter != sVBCache.end(); ) { if (now - iter->second.touched > 1s) { diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index eb88755f70..de0d8ba748 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -526,6 +526,8 @@ extern F32 gGLLastModelView[16]; extern F32 gGLLastProjection[16]; extern F32 gGLProjection[16]; extern S32 gGLViewport[4]; +extern F32 gGLDeltaModelView[16]; +extern F32 gGLInverseDeltaModelView[16]; extern thread_local LLRender gGL; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index ca65b9b323..e5d3633641 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -35,19 +35,19 @@ U32 LLRenderTarget::sBytesAllocated = 0; void check_framebuffer_status() { - if (gDebugGL) - { - GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); - switch (status) - { - case GL_FRAMEBUFFER_COMPLETE: - break; - default: - LL_WARNS() << "check_framebuffer_status failed -- " << std::hex << status << LL_ENDL; - ll_fail("check_framebuffer_status failed"); - break; - } - } + if (gDebugGL) + { + GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + switch (status) + { + case GL_FRAMEBUFFER_COMPLETE: + break; + default: + LL_WARNS() << "check_framebuffer_status failed -- " << std::hex << status << LL_ENDL; + ll_fail("check_framebuffer_status failed"); + break; + } + } } bool LLRenderTarget::sUseFBO = false; @@ -60,112 +60,86 @@ U32 LLRenderTarget::sCurResX = 0; U32 LLRenderTarget::sCurResY = 0; LLRenderTarget::LLRenderTarget() : - mResX(0), - mResY(0), - mFBO(0), - mPreviousFBO(0), - mPreviousResX(0), - mPreviousResY(0), - mDepth(0), - mUseDepth(false), - mSampleDepth(false), - mUsage(LLTexUnit::TT_TEXTURE) + mResX(0), + mResY(0), + mFBO(0), + mDepth(0), + mUseDepth(false), + mUsage(LLTexUnit::TT_TEXTURE) { } LLRenderTarget::~LLRenderTarget() { - release(); + release(); } void LLRenderTarget::resize(U32 resx, U32 resy) { - //for accounting, get the number of pixels added/subtracted - S32 pix_diff = (resx*resy)-(mResX*mResY); - - mResX = resx; - mResY = resy; + //for accounting, get the number of pixels added/subtracted + S32 pix_diff = (resx*resy)-(mResX*mResY); + + mResX = resx; + mResY = resy; - llassert(mInternalFormat.size() == mTex.size()); + llassert(mInternalFormat.size() == mTex.size()); - for (U32 i = 0; i < mTex.size(); ++i) - { //resize color attachments - gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]); - LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, mInternalFormat[i], mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false); - sBytesAllocated += pix_diff*4; - } + for (U32 i = 0; i < mTex.size(); ++i) + { //resize color attachments + gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]); + LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, mInternalFormat[i], mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false); + sBytesAllocated += pix_diff*4; + } - if (mDepth) - { //resize depth attachment - if (!mSampleDepth) - { - //use render buffers where stencil buffers are in play - glBindRenderbuffer(GL_RENDERBUFFER, mDepth); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mResX, mResY); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - } - else - { - gGL.getTexUnit(0)->bindManual(mUsage, mDepth); - U32 internal_type = LLTexUnit::getInternalType(mUsage); - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); - } + if (mDepth) + { + gGL.getTexUnit(0)->bindManual(mUsage, mDepth); + U32 internal_type = LLTexUnit::getInternalType(mUsage); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); - sBytesAllocated += pix_diff*4; - } + sBytesAllocated += pix_diff*4; + } } - + -bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool sample_depth, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples) +bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, LLTexUnit::eTextureType usage) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; - resx = llmin(resx, (U32) gGLManager.mGLMaxTextureSize); - resy = llmin(resy, (U32) gGLManager.mGLMaxTextureSize); + llassert(usage == LLTexUnit::TT_TEXTURE); + llassert(!isBoundInStack()); - stop_glerror(); - release(); - stop_glerror(); + resx = llmin(resx, (U32) gGLManager.mGLMaxTextureSize); + resy = llmin(resy, (U32) gGLManager.mGLMaxTextureSize); - mResX = resx; - mResY = resy; + release(); + + mResX = resx; + mResY = resy; - mUsage = usage; + mUsage = usage; mUseDepth = depth; - mSampleDepth = sample_depth; + + if (depth) + { + if (!allocateDepth()) + { + LL_WARNS() << "Failed to allocate depth buffer for render target." << LL_ENDL; + return false; + } + } - if ((sUseFBO || use_fbo)) - { - if (depth) - { - if (!allocateDepth()) - { - LL_WARNS() << "Failed to allocate depth buffer for render target." << LL_ENDL; - return false; - } - } + glGenFramebuffers(1, (GLuint *) &mFBO); - glGenFramebuffers(1, (GLuint *) &mFBO); - - if (mDepth) - { - glBindFramebuffer(GL_FRAMEBUFFER, mFBO); + if (mDepth) + { + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); - if (!canSampleDepth()) - { - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth); - } - else - { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0); - stop_glerror(); - } - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); - } - - stop_glerror(); - } + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0); - return addColorAttachment(color_fmt); + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + } + + return addColorAttachment(color_fmt); } void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name) @@ -175,6 +149,7 @@ void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name) llassert(sUseFBO); // FBO support must be enabled llassert(mDepth == 0); // depth buffers not supported with this mode llassert(mTex.empty()); // mTex must be empty with this mode (binding target should be done via LLImageGL) + llassert(!isBoundInStack()); if (mFBO == 0) { @@ -205,6 +180,7 @@ void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name) void LLRenderTarget::releaseColorAttachment() { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + llassert(!isBoundInStack()); llassert(mTex.size() == 1); //cannot use releaseColorAttachment with LLRenderTarget managed color targets llassert(mFBO != 0); // mFBO must be valid @@ -218,323 +194,291 @@ void LLRenderTarget::releaseColorAttachment() bool LLRenderTarget::addColorAttachment(U32 color_fmt) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; - if (color_fmt == 0) - { - return true; - } + llassert(!isBoundInStack()); - U32 offset = mTex.size(); + if (color_fmt == 0) + { + return true; + } - if( offset >= 4 ) - { - LL_WARNS() << "Too many color attachments" << LL_ENDL; - llassert( offset < 4 ); - return false; - } - if( offset > 0 && (mFBO == 0) ) - { - llassert( mFBO != 0 ); - return false; - } + U32 offset = mTex.size(); - U32 tex; - LLImageGL::generateTextures(1, &tex); - gGL.getTexUnit(0)->bindManual(mUsage, tex); + if( offset >= 4 ) + { + LL_WARNS() << "Too many color attachments" << LL_ENDL; + llassert( offset < 4 ); + return false; + } + if( offset > 0 && (mFBO == 0) ) + { + llassert( mFBO != 0 ); + return false; + } - stop_glerror(); + U32 tex; + LLImageGL::generateTextures(1, &tex); + gGL.getTexUnit(0)->bindManual(mUsage, tex); + + stop_glerror(); - { - clear_glerror(); - LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false); - if (glGetError() != GL_NO_ERROR) - { - LL_WARNS() << "Could not allocate color buffer for render target." << LL_ENDL; - return false; - } - } - - sBytesAllocated += mResX*mResY*4; + { + clear_glerror(); + LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false); + if (glGetError() != GL_NO_ERROR) + { + LL_WARNS() << "Could not allocate color buffer for render target." << LL_ENDL; + return false; + } + } + + sBytesAllocated += mResX*mResY*4; - stop_glerror(); + stop_glerror(); - - if (offset == 0) - { //use bilinear filtering on single texture render targets that aren't multisampled - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - stop_glerror(); - } - else - { //don't filter data attachments - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - stop_glerror(); - } + + if (offset == 0) + { //use bilinear filtering on single texture render targets that aren't multisampled + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + stop_glerror(); + } + else + { //don't filter data attachments + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + stop_glerror(); + } - if (mUsage != LLTexUnit::TT_RECT_TEXTURE) - { - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR); - stop_glerror(); - } - else - { - // ATI doesn't support mirrored repeat for rectangular textures. - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - } - - if (mFBO) - { - stop_glerror(); - glBindFramebuffer(GL_FRAMEBUFFER, mFBO); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset, - LLTexUnit::getInternalType(mUsage), tex, 0); - stop_glerror(); + if (mUsage != LLTexUnit::TT_RECT_TEXTURE) + { + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR); + stop_glerror(); + } + else + { + // ATI doesn't support mirrored repeat for rectangular textures. + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); + } + + if (mFBO) + { + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset, + LLTexUnit::getInternalType(mUsage), tex, 0); + + check_framebuffer_status(); + + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + } - check_framebuffer_status(); - - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); - } + mTex.push_back(tex); + mInternalFormat.push_back(color_fmt); - mTex.push_back(tex); - mInternalFormat.push_back(color_fmt); - - if (gDebugGL) - { //bind and unbind to validate target - bindTarget(); - flush(); - } + if (gDebugGL) + { //bind and unbind to validate target + bindTarget(); + flush(); + } - return true; + return true; } bool LLRenderTarget::allocateDepth() { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; - if (!mSampleDepth) - { - //use render buffers if depth buffer won't be sampled - glGenRenderbuffers(1, (GLuint *) &mDepth); - glBindRenderbuffer(GL_RENDERBUFFER, mDepth); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mResX, mResY); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - } - else - { - LLImageGL::generateTextures(1, &mDepth); - gGL.getTexUnit(0)->bindManual(mUsage, mDepth); - - U32 internal_type = LLTexUnit::getInternalType(mUsage); - stop_glerror(); - clear_glerror(); - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } + LLImageGL::generateTextures(1, &mDepth); + gGL.getTexUnit(0)->bindManual(mUsage, mDepth); + + U32 internal_type = LLTexUnit::getInternalType(mUsage); + stop_glerror(); + clear_glerror(); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - sBytesAllocated += mResX*mResY*4; + sBytesAllocated += mResX*mResY*4; - if (glGetError() != GL_NO_ERROR) - { - LL_WARNS() << "Unable to allocate depth buffer for render target." << LL_ENDL; - return false; - } + if (glGetError() != GL_NO_ERROR) + { + LL_WARNS() << "Unable to allocate depth buffer for render target." << LL_ENDL; + return false; + } - return true; + return true; } void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target) { - if (!mFBO || !target.mFBO) - { - LL_ERRS() << "Cannot share depth buffer between non FBO render targets." << LL_ENDL; - } + llassert(!isBoundInStack()); - if (target.mDepth) - { - LL_ERRS() << "Attempting to override existing depth buffer. Detach existing buffer first." << LL_ENDL; - } + if (!mFBO || !target.mFBO) + { + LL_ERRS() << "Cannot share depth buffer between non FBO render targets." << LL_ENDL; + } - if (target.mUseDepth) - { - LL_ERRS() << "Attempting to override existing shared depth buffer. Detach existing buffer first." << LL_ENDL; - } + if (target.mDepth) + { + LL_ERRS() << "Attempting to override existing depth buffer. Detach existing buffer first." << LL_ENDL; + } - if (mDepth) - { - glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO); - - if (!mSampleDepth) - { - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth); - } - else - { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0); - } + if (target.mUseDepth) + { + LL_ERRS() << "Attempting to override existing shared depth buffer. Detach existing buffer first." << LL_ENDL; + } - check_framebuffer_status(); + if (mDepth) + { + glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0); - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + check_framebuffer_status(); - target.mUseDepth = true; - } + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + + target.mUseDepth = true; + } } void LLRenderTarget::release() { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; - if (mDepth) - { - if (!mSampleDepth) - { - glDeleteRenderbuffers(1, (GLuint*) &mDepth); - } - else - { - LLImageGL::deleteTextures(1, &mDepth); - } - mDepth = 0; + llassert(!isBoundInStack()); - sBytesAllocated -= mResX*mResY*4; - } - else if (mFBO) - { - glBindFramebuffer(GL_FRAMEBUFFER, mFBO); + if (mDepth) + { + LLImageGL::deleteTextures(1, &mDepth); + + mDepth = 0; - if (mUseDepth) - { //detach shared depth buffer - if (!mSampleDepth) - { //attached as a renderbuffer - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); - mSampleDepth = false; - } - else - { //attached as a texture - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0); - } - mUseDepth = false; - } - } + sBytesAllocated -= mResX*mResY*4; + } + else if (mFBO) + { + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); - // Detach any extra color buffers (e.g. SRGB spec buffers) - // - if (mFBO && (mTex.size() > 1)) - { - glBindFramebuffer(GL_FRAMEBUFFER, mFBO); - S32 z; - for (z = mTex.size() - 1; z >= 1; z--) - { - sBytesAllocated -= mResX*mResY*4; - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+z, LLTexUnit::getInternalType(mUsage), 0, 0); - stop_glerror(); - LLImageGL::deleteTextures(1, &mTex[z]); - } - } + if (mUseDepth) + { //detach shared depth buffer + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0); + mUseDepth = false; + } - if (mFBO) - { - glDeleteFramebuffers(1, (GLuint *) &mFBO); - stop_glerror(); - mFBO = 0; - } + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + } - if (mTex.size() > 0) - { - sBytesAllocated -= mResX*mResY*4; - LLImageGL::deleteTextures(1, &mTex[0]); - } + // Detach any extra color buffers (e.g. SRGB spec buffers) + // + if (mFBO && (mTex.size() > 1)) + { + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); + S32 z; + for (z = mTex.size() - 1; z >= 1; z--) + { + sBytesAllocated -= mResX*mResY*4; + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+z, LLTexUnit::getInternalType(mUsage), 0, 0); + LLImageGL::deleteTextures(1, &mTex[z]); + } + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + } - mTex.clear(); - mInternalFormat.clear(); - - mResX = mResY = 0; + if (mFBO == sCurFBO) + { + sCurFBO = 0; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } - sBoundTarget = NULL; + if (mFBO) + { + glDeleteFramebuffers(1, (GLuint *) &mFBO); + mFBO = 0; + } + + if (mTex.size() > 0) + { + sBytesAllocated -= mResX*mResY*4; + LLImageGL::deleteTextures(1, &mTex[0]); + } + + mTex.clear(); + mInternalFormat.clear(); + + mResX = mResY = 0; } void LLRenderTarget::bindTarget() { LL_PROFILE_GPU_ZONE("bindTarget"); llassert(mFBO); + llassert(!isBoundInStack()); + + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); + sCurFBO = mFBO; - if (mFBO) - { - stop_glerror(); - - mPreviousFBO = sCurFBO; - glBindFramebuffer(GL_FRAMEBUFFER, mFBO); - sCurFBO = mFBO; - - stop_glerror(); - //setup multiple render targets - GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1, - GL_COLOR_ATTACHMENT2, - GL_COLOR_ATTACHMENT3}; - glDrawBuffers(mTex.size(), drawbuffers); - - if (mTex.empty()) - { //no color buffer to draw to - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - } + //setup multiple render targets + GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3}; + glDrawBuffers(mTex.size(), drawbuffers); + + if (mTex.empty()) + { //no color buffer to draw to + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } - check_framebuffer_status(); + check_framebuffer_status(); - stop_glerror(); - } + glViewport(0, 0, mResX, mResY); + sCurResX = mResX; + sCurResY = mResY; - mPreviousResX = sCurResX; - mPreviousResY = sCurResY; - glViewport(0, 0, mResX, mResY); - sCurResX = mResX; - sCurResY = mResY; - - sBoundTarget = this; + mPreviousRT = sBoundTarget; + sBoundTarget = this; } void LLRenderTarget::clear(U32 mask_in) { LL_PROFILE_GPU_ZONE("clear"); llassert(mFBO); - U32 mask = GL_COLOR_BUFFER_BIT; - if (mUseDepth) - { - mask |= GL_DEPTH_BUFFER_BIT; // stencil buffer is deprecated, performance pnealty | GL_STENCIL_BUFFER_BIT; + U32 mask = GL_COLOR_BUFFER_BIT; + if (mUseDepth) + { + mask |= GL_DEPTH_BUFFER_BIT; - } - if (mFBO) - { - check_framebuffer_status(); - stop_glerror(); - glClear(mask & mask_in); - stop_glerror(); - } - else - { - LLGLEnable scissor(GL_SCISSOR_TEST); - glScissor(0, 0, mResX, mResY); - stop_glerror(); - glClear(mask & mask_in); - } + } + if (mFBO) + { + check_framebuffer_status(); + stop_glerror(); + glClear(mask & mask_in); + stop_glerror(); + } + else + { + LLGLEnable scissor(GL_SCISSOR_TEST); + glScissor(0, 0, mResX, mResY); + stop_glerror(); + glClear(mask & mask_in); + } } U32 LLRenderTarget::getTexture(U32 attachment) const { - if (attachment > mTex.size()-1) - { - LL_ERRS() << "Invalid attachment index." << LL_ENDL; - } - if (mTex.empty()) - { - return 0; - } - return mTex[attachment]; + if (attachment > mTex.size()-1) + { + LL_ERRS() << "Invalid attachment index." << LL_ENDL; + } + if (mTex.empty()) + { + return 0; + } + return mTex[attachment]; } U32 LLRenderTarget::getNumTextures() const { - return mTex.size(); + return mTex.size(); } void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options) @@ -560,61 +504,54 @@ void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilt gGL.getTexUnit(channel)->setTextureColorSpace(isSRGB ? LLTexUnit::TCS_SRGB : LLTexUnit::TCS_LINEAR); } -void LLRenderTarget::flush(bool fetch_depth) +void LLRenderTarget::flush() { LL_PROFILE_GPU_ZONE("rt flush"); - gGL.flush(); + gGL.flush(); llassert(mFBO); - if (!mFBO) - { - gGL.getTexUnit(0)->bind(this); - glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, 0, 0, 0, 0, mResX, mResY); + llassert(sCurFBO == mFBO); + llassert(sBoundTarget == this); - if (fetch_depth) - { - if (!mDepth) - { - allocateDepth(); - } - - gGL.getTexUnit(0)->bind(this); - glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8, 0, 0, mResX, mResY, 0); - } - - gGL.getTexUnit(0)->disable(); - } - else - { - stop_glerror(); - glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFBO); - sCurFBO = mPreviousFBO; - - if (mPreviousFBO) - { - glViewport(0, 0, mPreviousResX, mPreviousResY); - sCurResX = mPreviousResX; - sCurResY = mPreviousResY; - } - else - { - glViewport(gGLViewport[0],gGLViewport[1],gGLViewport[2],gGLViewport[3]); - sCurResX = gGLViewport[2]; - sCurResY = gGLViewport[3]; - } - - stop_glerror(); - } + if (mPreviousRT) + { + // a bit hacky -- pop the RT stack back two frames and push + // the previous frame back on to play nice with the GL state machine + sBoundTarget = mPreviousRT->mPreviousRT; + mPreviousRT->bindTarget(); + } + else + { + sBoundTarget = nullptr; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + sCurFBO = 0; + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + sCurResX = gGLViewport[2]; + sCurResY = gGLViewport[3]; + } } bool LLRenderTarget::isComplete() const { - return (!mTex.empty() || mDepth) ? true : false; + return (!mTex.empty() || mDepth) ? true : false; } void LLRenderTarget::getViewport(S32* viewport) { - viewport[0] = 0; - viewport[1] = 0; - viewport[2] = mResX; - viewport[3] = mResY; + viewport[0] = 0; + viewport[1] = 0; + viewport[2] = mResX; + viewport[3] = mResY; } + +bool LLRenderTarget::isBoundInStack() const +{ + LLRenderTarget* cur = sBoundTarget; + while (cur && cur != this) + { + cur = cur->mPreviousRT; + } + + return cur == this; +} + + diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 5f3214add3..71727bf09d 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -33,6 +33,8 @@ #include "llrender.h" /* + Wrapper around OpenGL framebuffer objects for use in render-to-texture + SAMPLE USAGE: LLRenderTarget target; @@ -73,7 +75,12 @@ public: //allocate resources for rendering //must be called before use //multiple calls will release previously allocated resources - bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool sample_depth, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = false, S32 samples = 0); + // resX - width + // resY - height + // color_fmt - GL color format (e.g. GL_RGB) + // depth - if true, allocate a depth buffer + // usage - deprecated, should always be TT_TEXTURE + bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth = false, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE); //resize existing attachments to use new resolution and color format // CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined @@ -93,7 +100,7 @@ public: // attachment -- LLImageGL to render into // use_name -- optional texture name to target instead of attachment->getTexName() // NOTE: setColorAttachment and releaseColorAttachment cannot be used in conjuction with - // addColorAttachment, allocateDepth, resize, etc. + // addColorAttachment, allocateDepth, resize, etc. void setColorAttachment(LLImageGL* attachment, LLGLuint use_name = 0); // detach from current color attachment @@ -111,14 +118,19 @@ public: //free any allocated resources //safe to call redundantly + // asserts that this target is not currently bound or present in the RT stack void release(); //bind target for rendering //applies appropriate viewport + // If an LLRenderTarget is currently bound, stores a reference to that LLRenderTarget + // and restores previous binding on flush() (maintains a stack of Render Targets) + // Asserts that this target is not currently bound in the stack void bindTarget(); //clear render targer, clears depth buffer if present, //uses scissor rect if in copy-to-texture mode + // asserts that this target is currently bound void clear(U32 mask = 0xFFFFFFFF); //get applied viewport @@ -136,7 +148,6 @@ public: U32 getNumTextures() const; U32 getDepth(void) const { return mDepth; } - bool canSampleDepth() const { return mSampleDepth; } void bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options = LLTexUnit::TFO_BILINEAR); @@ -144,15 +155,18 @@ public: //must be called when rendering is complete //should be used 1:1 with bindTarget // call bindTarget once, do all your rendering, call flush once - // if fetch_depth is TRUE, every effort will be made to copy the depth buffer into - // the current depth texture. A depth texture will be allocated if needed. - void flush(bool fetch_depth = FALSE); + // If an LLRenderTarget was bound when bindTarget was called, binds that RenderTarget for rendering (maintains RT stack) + // asserts that this target is currently bound + void flush(); //Returns TRUE if target is ready to be rendered into. //That is, if the target has been allocated with at least //one renderable attachment (i.e. color buffer, depth buffer). bool isComplete() const; + // Returns true if this RenderTarget is bound somewhere in the stack + bool isBoundInStack() const; + static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; } protected: @@ -161,13 +175,10 @@ protected: std::vector mTex; std::vector mInternalFormat; U32 mFBO; - U32 mPreviousFBO; - U32 mPreviousResX; - U32 mPreviousResY; + LLRenderTarget* mPreviousRT = nullptr; - U32 mDepth; + U32 mDepth; bool mUseDepth; - bool mSampleDepth; LLTexUnit::eTextureType mUsage; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index fca43a03c3..b2af7b31f2 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -222,7 +222,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } } - if (features->hasScreenSpaceReflections) + if (features->hasScreenSpaceReflections || features->hasReflectionProbes) { if (!shader->attachFragmentObject("deferred/screenSpaceReflUtil.glsl")) { @@ -262,7 +262,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } } - if (features->hasGamma) + if (features->hasGamma || features->isDeferred) { if (!shader->attachFragmentObject("windlight/gammaF.glsl")) { @@ -278,7 +278,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } } - if (features->hasAtmospherics) + if (features->hasAtmospherics || features->isDeferred) { if (!shader->attachFragmentObject("windlight/atmosphericsFuncs.glsl")) { return FALSE; @@ -1250,6 +1250,8 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("bumpMap"); mReservedUniforms.push_back("bumpMap2"); mReservedUniforms.push_back("environmentMap"); + mReservedUniforms.push_back("sceneMap"); + mReservedUniforms.push_back("sceneDepth"); mReservedUniforms.push_back("reflectionProbes"); mReservedUniforms.push_back("irradianceProbes"); mReservedUniforms.push_back("cloud_noise_texture"); @@ -1326,9 +1328,12 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("depth_cutoff"); mReservedUniforms.push_back("norm_cutoff"); mReservedUniforms.push_back("shadow_target_width"); - mReservedUniforms.push_back("view_dir"); // DEFERRED_VIEW_DIR - llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_VIEW_DIR+1); + llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH+1); + + mReservedUniforms.push_back("modelview_delta"); + mReservedUniforms.push_back("inv_modelview_delta"); + mReservedUniforms.push_back("cube_snapshot"); mReservedUniforms.push_back("tc_scale"); mReservedUniforms.push_back("rcp_screen_res"); @@ -1445,6 +1450,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("moon_brightness"); mReservedUniforms.push_back("cloud_variance"); mReservedUniforms.push_back("reflection_probe_ambiance"); + mReservedUniforms.push_back("max_probe_lod"); mReservedUniforms.push_back("sh_input_r"); mReservedUniforms.push_back("sh_input_g"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 1abfe63e2a..9b78f04732 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -90,6 +90,8 @@ public: BUMP_MAP, // "bumpMap" BUMP_MAP2, // "bumpMap2" ENVIRONMENT_MAP, // "environmentMap" + SCENE_MAP, // "sceneMap" + SCENE_DEPTH, // "sceneDepth" REFLECTION_PROBES, // "reflectionProbes" IRRADIANCE_PROBES, // "irradianceProbes" CLOUD_NOISE_MAP, // "cloud_noise_texture" @@ -157,7 +159,10 @@ public: DEFERRED_DEPTH_CUTOFF, // "depth_cutoff" DEFERRED_NORM_CUTOFF, // "norm_cutoff" DEFERRED_SHADOW_TARGET_WIDTH, // "shadow_target_width" - DEFERRED_VIEW_DIR, // "view_dir" + + MODELVIEW_DELTA_MATRIX, // "modelview_delta" + INVERSE_MODELVIEW_DELTA_MATRIX, // "inv_modelview_delta" + CUBE_SNAPSHOT, // "cube_snapshot" FXAA_TC_SCALE, // "tc_scale" FXAA_RCP_SCREEN_RES, // "rcp_screen_res" @@ -276,6 +281,7 @@ public: CLOUD_VARIANCE, // "cloud_variance" REFLECTION_PROBE_AMBIANCE, // "reflection_probe_ambiance" + REFLECTION_PROBE_MAX_LOD, // "max_probe_lod" SH_INPUT_L1R, // "sh_input_r" SH_INPUT_L1G, // "sh_input_g" SH_INPUT_L1B, // "sh_input_b" diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index fc560bb804..6b01e54ed4 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -260,6 +260,8 @@ static GLWorkQueue* sQueue = nullptr; static GLuint gen_buffer() { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + + GLuint ret = 0; constexpr U32 pool_size = 4096; thread_local static GLuint sNamePool[pool_size]; @@ -269,10 +271,21 @@ static GLuint gen_buffer() { LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("gen buffer"); sIndex = pool_size; - glGenBuffers(pool_size, sNamePool); + if (!gGLManager.mIsAMD) + { + glGenBuffers(pool_size, sNamePool); + } + else + { // work around for AMD driver bug + for (U32 i = 0; i < pool_size; ++i) + { + glGenBuffers(1, sNamePool + i); + } + } } - return sNamePool[--sIndex]; + ret = sNamePool[--sIndex]; + return ret; } #define ANALYZE_VBO_POOL 0 @@ -741,14 +754,13 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi llassert(mGLBuffer == sGLRenderBuffer); llassert(mGLIndices == sGLRenderIndices); gGL.syncMatrices(); - glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, (GLvoid*) (indices_offset * sizeof(U16))); } void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { - drawRange(mode, 0, mNumVerts, count, indices_offset); + drawRange(mode, 0, mNumVerts-1, count, indices_offset); } @@ -1160,7 +1172,8 @@ static void flush_vbo(GLenum target, U32 start, U32 end, void* data) LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block"); //LL_PROFILE_GPU_ZONE("glBufferSubData"); U32 tend = llmin(i + block_size, end); - glBufferSubData(target, i, tend - i+1, (U8*) data + (i-start)); + U32 size = tend - i + 1; + glBufferSubData(target, i, size, (U8*) data + (i-start)); } } } diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e6d69aba2f..e4727764bf 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12716,18 +12716,6 @@ Change of this parameter will affect the layout of buttons in notification toast 0 - RenderPBR - - Comment - DEPRECATED - only true supported - Use PBR rendering pipeline (Physically Based Rendering). - Persist - 1 - Type - Boolean - Value - 1 - - RenderDeferred Comment @@ -13480,6 +13468,28 @@ Change of this parameter will affect the layout of buttons in notification toast Value 256 + RenderReflectionProbeResolution + + Comment + Resolution of reflection probe radiance maps (requires restart). Will be set to the next highest power of two clamped to [64, 512]. Note that changing this value may consume a massive amount of video memory. + Persist + 1 + Type + U32 + Value + 256 + + RenderReflectionProbeAmbianceScale + + Comment + Scaler to apply to reflection probes to over-brighten sky contributions to indirect light + Persist + 1 + Type + F32 + Value + 8 + RenderReflectionProbeDrawDistance diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 9bead273ff..93a85cad40 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -39,6 +39,7 @@ uniform sampler2D lightMap; uniform float dist_factor; uniform float blur_size; uniform vec2 delta; +uniform vec2 screen_res; uniform vec3 kern[4]; uniform float kern_scale; @@ -52,8 +53,8 @@ void main() vec2 tc = vary_fragcoord.xy; vec3 norm = getNorm(tc); vec3 pos = getPosition(tc).xyz; - vec4 ccol = texture2D(lightMap, tc).rgba; - + vec4 ccol = texture(lightMap, tc).rgba; + vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy); dlt /= max(-pos.z*dist_factor, 1.0); @@ -64,7 +65,8 @@ void main() float pointplanedist_tolerance_pow2 = pos.z*pos.z*0.00005; // perturb sampling origin slightly in screen-space to hide edge-ghosting artifacts where smoothing radius is quite large - float tc_mod = 0.5*(tc.x + tc.y); // mod(tc.x+tc.y,2) + tc *= screen_res; + float tc_mod = 0.5*(tc.x + tc.y); tc_mod -= floor(tc_mod); tc_mod *= 2.0; tc += ( (tc_mod - 0.5) * kern[1].z * dlt * 0.5 ); @@ -83,13 +85,14 @@ void main() for (int i = 1; i < 7; i++) { vec2 samptc = tc + k[i].z*dlt*2.0; + samptc /= screen_res; vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane if (d*d <= pointplanedist_tolerance_pow2) { - col += texture2D(lightMap, samptc)*k[i].xyxx; + col += texture(lightMap, samptc)*k[i].xyxx; defined_weight += k[i].xy; } } @@ -97,19 +100,20 @@ void main() for (int i = 1; i < 7; i++) { vec2 samptc = tc - k[i].z*dlt*2.0; + samptc /= screen_res; vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane if (d*d <= pointplanedist_tolerance_pow2) { - col += texture2D(lightMap, samptc)*k[i].xyxx; + col += texture(lightMap, samptc)*k[i].xyxx; defined_weight += k[i].xy; } } col /= defined_weight.xyxx; - //col.y *= max(col.y, 0.75); + //col.y *= col.y; frag_color = col; diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl index 2aeb9e86e9..8fdb5e7154 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl @@ -23,124 +23,11 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + // debug stub -/*[EXTRA_CODE_HERE]*/ - -#ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -//uniform sampler2D depthMap; // Colour space and shader fixes for BUG-228586 (Rye) -uniform sampler2D diffuseRect; -uniform sampler2D specularRect; -uniform sampler2D noiseMap; -uniform sampler2D lightFunc; - -uniform vec3 env_mat[3]; -uniform float sun_wash; -uniform int light_count; -uniform vec4 light[LIGHT_COUNT]; -uniform vec4 light_col[LIGHT_COUNT]; - -uniform vec2 screen_res; -uniform float far_z; -uniform mat4 inv_proj; - -VARYING vec4 vary_fragcoord; - -vec4 getPosition(vec2 pos_screen); -vec3 getNorm(vec2 pos_screen); -vec3 srgb_to_linear(vec3 c); -float getDepth(vec2 tc); -vec2 getScreenCoord(vec4 clip); void main() { -#if defined(LOCAL_LIGHT_KILL) - discard; // Bail immediately -#endif - - vec3 out_col = vec3(0, 0, 0); - vec2 frag = getScreenCoord(vary_fragcoord); - vec3 pos = getPosition(frag.xy).xyz; - if (pos.z < far_z) - { - discard; - } - - vec3 norm = getNorm(frag.xy); - - vec4 spec = texture2D(specularRect, frag.xy); - vec3 diff = texture2D(diffuseRect, frag.xy).rgb; - - float noise = texture2D(noiseMap, frag.xy).b; - vec3 npos = normalize(-pos); - - // As of OSX 10.6.7 ATI Apple's crash when using a variable size loop - for (int i = 0; i < LIGHT_COUNT; ++i) - { - vec3 lv = light[i].xyz - pos; - float dist = length(lv); - dist /= light[i].w; - if (dist <= 1.0) - { - float da = dot(norm, lv); - if (da > 0.0) - { - lv = normalize(lv); - da = dot(norm, lv); - - float fa = light_col[i].a + 1.0; - float dist_atten = clamp(1.0 - (dist - 1.0 * (1.0 - fa)) / fa, 0.0, 1.0); - dist_atten *= dist_atten; - - // Tweak falloff slightly to match pre-EEP attenuation - // NOTE: this magic number also shows up in a great many other places, search for dist_atten *= to audit - dist_atten *= 2.0; - - dist_atten *= noise; - - float lit = da * dist_atten; - - vec3 col = light_col[i].rgb * lit * diff; - - if (spec.a > 0.0) - { - lit = min(da * 6.0, 1.0) * dist_atten; - vec3 h = normalize(lv + npos); - float nh = dot(norm, h); - float nv = dot(norm, npos); - float vh = dot(npos, h); - float sa = nh; - float fres = pow(1 - dot(h, npos), 5) * 0.4 + 0.5; - - float gtdenom = 2 * nh; - float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); - - if (nh > 0.0) - { - float scol = fres * texture2D(lightFunc, vec2(nh, spec.a)).r * gt / (nh * da); - col += lit * scol * light_col[i].rgb * spec.rgb; - } - } - - out_col += col; - } - } - } - - frag_color.rgb = out_col; - frag_color.a = 0.0; - -#ifdef IS_AMD_CARD - // If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage - // awawy which leads to unfun crashes and artifacts. - vec4 dummy1 = light[0]; - vec4 dummy2 = light_col[0]; - vec4 dummy3 = light[LIGHT_COUNT - 1]; - vec4 dummy4 = light_col[LIGHT_COUNT - 1]; -#endif + frag_color = vec4(0.5, 0.5, 0.0, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl index 58864e07e6..a025c4a1b4 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl @@ -22,113 +22,11 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - -#extension GL_ARB_texture_rectangle : enable -/*[EXTRA_CODE_HERE]*/ - -#ifdef DEFINE_GL_FRAGCOLOR +// debug stub out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform sampler2D diffuseRect; -uniform sampler2D specularRect; -// Colour space and shader fixes for BUG-228586 (Rye) -//uniform sampler2D normalMap; -// -uniform sampler2D noiseMap; -uniform sampler2D lightFunc; -//uniform sampler2D depthMap;// Colour space and shader fixes for BUG-228586 (Rye) - -uniform vec3 env_mat[3]; -uniform float sun_wash; - -uniform vec3 color; -uniform float falloff; -uniform float size; - -VARYING vec4 vary_fragcoord; -VARYING vec3 trans_center; - -uniform vec2 screen_res; - -uniform mat4 inv_proj; -uniform vec4 viewport; - -vec3 getNorm(vec2 pos_screen); -vec4 getPosition(vec2 pos_screen); -float getDepth(vec2 pos); -vec3 srgb_to_linear(vec3 c); void main() { - vec4 frag = vary_fragcoord; - frag.xyz /= frag.w; - frag.xyz = frag.xyz*0.5+0.5; - - vec3 pos = getPosition(frag.xy).xyz; - vec3 lv = trans_center.xyz-pos; - float dist = length(lv); - dist /= size; - if (dist > 1.0) - { - discard; - } - - vec3 norm = getNorm(frag.xy); - - float da = dot(norm, lv); - if (da < 0.0) - { - discard; - } - - lv = normalize(lv); - da = dot(norm, lv); - - float noise = texture2D(noiseMap, frag.xy).b; - - vec3 col = texture2D(diffuseRect, frag.xy).rgb; - - float fa = falloff+1.0; - float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0); - dist_atten *= dist_atten; - dist_atten *= 2.0; - - float lit = da * dist_atten * noise; - - col = color.rgb*lit*col; - - vec4 spec = texture2D(specularRect, frag.xy); - if (spec.a > 0.0) - { - lit = min(da*6.0, 1.0) * dist_atten; - - vec3 npos = -normalize(pos); - vec3 h = normalize(lv+npos); - float nh = dot(norm, h); - float nv = dot(norm, npos); - float vh = dot(npos, h); - float sa = nh; - float fres = pow(1 - dot(h, npos), 5) * 0.4+0.5; - float gtdenom = 2 * nh; - float gt = max(0,(min(gtdenom * nv / vh, gtdenom * da / vh))); - - if (nh > 0.0) - { - float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); - col += lit*scol*color.rgb*spec.rgb; - } - } - - if (dot(col, col) <= 0.0) - { - discard; - } - final_color.rgb = vec3(getDepth(frag.xy)); - - frag_color.rgb = col; - frag_color.a = 0.0; + frag_color = vec4(0.0, 0.5, 0.5, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl index a73a59bc6f..987b2d1fe8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl @@ -84,7 +84,9 @@ void main() //this is the one of the rare spots where diffuseRect contains linear color values (not sRGB) vec4 diff = texture2D(diffuseRect, vary_fragcoord); diff.rgb = linear_to_srgb(diff.rgb); - vec3 seed = (diff.rgb+vec3(1.0))*vec3(vary_fragcoord.xy, vary_fragcoord.x+vary_fragcoord.y); + vec2 tc = vary_fragcoord.xy*screen_res; + + vec3 seed = (diff.rgb+vec3(1.0))*vec3(tc.xy, tc.x+tc.y); vec3 nz = vec3(noise(seed.rg), noise(seed.gb), noise(seed.rb)); diff.rgb += nz*0.008; //diff.rgb = nz; diff --git a/indra/newview/app_settings/shaders/class1/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/reflectionProbeF.glsl index 95abd4d932..2ffe688524 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/reflectionProbeF.glsl @@ -25,14 +25,14 @@ // fallback stub -- will be used if actual reflection probe shader failed to load (output pink so it's obvious) void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, - vec3 pos, vec3 norm, float glossiness, bool errorCorrect) + vec2 tc, vec3 pos, vec3 norm, float glossiness, bool errorCorrect) { ambenv = vec3(1,0,1); glossenv = vec3(1,0,1); } void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, - vec3 pos, vec3 norm, float glossiness) + vec2 tc, vec3 pos, vec3 norm, float glossiness) { sampleReflectionProbes(ambenv, glossenv, pos, norm, glossiness, false); diff --git a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflPostF.glsl b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflPostF.glsl index 8373567bb0..df16e7f0e7 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflPostF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflPostF.glsl @@ -23,35 +23,11 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + // debug stub -/*[EXTRA_CODE_HERE]*/ - -#ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif -uniform vec2 screen_res; -uniform mat4 projection_matrix; -uniform mat4 inv_proj; -uniform float zNear; -uniform float zFar; - -VARYING vec2 vary_fragcoord; - -uniform sampler2D depthMap; -uniform sampler2D normalMap; -uniform sampler2D sceneMap; -uniform sampler2D diffuseRect; - -vec3 getNorm(vec2 screenpos); -float getDepth(vec2 pos_screen); -float linearDepth(float d, float znear, float zfar); - -void main() { - vec2 tc = vary_fragcoord.xy; - vec4 pos = getPositionWithDepth(tc, getDepth(tc)); - frag_color = pos; +void main() +{ + frag_color = vec4(0.5, 0.4, 0.1, 0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl index 6dfc89a6c6..d054305767 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl @@ -23,98 +23,15 @@ * $/LicenseInfo$ */ -uniform sampler2D depthMap; -uniform sampler2D normalMap; -uniform sampler2D sceneMap; -uniform vec2 screen_res; -uniform mat4 projection_matrix; +// debug stub -// Shamelessly taken from http://casual-effects.blogspot.com/2014/08/screen-space-ray-tracing.html -// Original paper: https://jcgt.org/published/0003/04/04/ -// By Morgan McGuire and Michael Mara at Williams College 2014 -// Released as open source under the BSD 2-Clause License -// http://opensource.org/licenses/BSD-2-Clause - -float distanceSquared(vec2 a, vec2 b) { a -= b; return dot(a, a); } - -bool traceScreenSpaceRay1(vec3 csOrig, vec3 csDir, mat4 proj, float zThickness, - float nearPlaneZ, float stride, float jitter, const float maxSteps, float maxDistance, - out vec2 hitPixel, out vec3 hitPoint) +float random (vec2 uv) { - - // Clip to the near plane - float rayLength = ((csOrig.z + csDir.z * maxDistance) > nearPlaneZ) ? - (nearPlaneZ - csOrig.z) / csDir.z : maxDistance; - vec3 csEndPoint = csOrig + csDir * rayLength; - - // Project into homogeneous clip space - vec4 H0 = proj * vec4(csOrig, 1.0); - vec4 H1 = proj * vec4(csEndPoint, 1.0); - float k0 = 1.0 / H0.w, k1 = 1.0 / H1.w; - - // The interpolated homogeneous version of the camera-space points - vec3 Q0 = csOrig * k0, Q1 = csEndPoint * k1; - - // Screen-space endpoints - vec2 P0 = H0.xy * k0, P1 = H1.xy * k1; - - // If the line is degenerate, make it cover at least one pixel - // to avoid handling zero-pixel extent as a special case later - P1 += vec2((distanceSquared(P0, P1) < 0.0001) ? 0.01 : 0.0); - vec2 delta = P1 - P0; - - // Permute so that the primary iteration is in x to collapse - // all quadrant-specific DDA cases later - bool permute = false; - if (abs(delta.x) < abs(delta.y)) { - // This is a more-vertical line - permute = true; delta = delta.yx; P0 = P0.yx; P1 = P1.yx; - } - - float stepDir = sign(delta.x); - float invdx = stepDir / delta.x; - - // Track the derivatives of Q and k - vec3 dQ = (Q1 - Q0) * invdx; - float dk = (k1 - k0) * invdx; - vec2 dP = vec2(stepDir, delta.y * invdx); - - // Scale derivatives by the desired pixel stride and then - // offset the starting values by the jitter fraction - dP *= stride; dQ *= stride; dk *= stride; - P0 += dP * jitter; Q0 += dQ * jitter; k0 += dk * jitter; - - // Slide P from P0 to P1, (now-homogeneous) Q from Q0 to Q1, k from k0 to k1 - vec3 Q = Q0; - - // Adjust end condition for iteration direction - float end = P1.x * stepDir; - - float k = k0, stepCount = 0.0, prevZMaxEstimate = csOrig.z; - float rayZMin = prevZMaxEstimate, rayZMax = prevZMaxEstimate; - float sceneZMax = rayZMax + 100; - for (vec2 P = P0; - ((P.x * stepDir) <= end) && (stepCount < maxSteps) && - ((rayZMax < sceneZMax - zThickness) || (rayZMin > sceneZMax)) && - (sceneZMax != 0); - P += dP, Q.z += dQ.z, k += dk, ++stepCount) { - - rayZMin = prevZMaxEstimate; - rayZMax = (dQ.z * 0.5 + Q.z) / (dk * 0.5 + k); - prevZMaxEstimate = rayZMax; - if (rayZMin > rayZMax) { - float t = rayZMin; rayZMin = rayZMax; rayZMax = t; - } - - hitPixel = permute ? P.yx : P; - hitPixel.y = screen_res.y - hitPixel.y; - // You may need hitPixel.y = screen_res.y - hitPixel.y; here if your vertical axis - // is different than ours in screen space - sceneZMax = texelFetch(depthMap, ivec2(hitPixel)).r; - } - - // Advance Q based on the number of steps - Q.xy += dQ.xy * stepCount; - hitPoint = Q * (1.0 / k); - return (rayZMax >= sceneZMax - zThickness) && (rayZMin < sceneZMax); + return 0; +} + +float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source) +{ + collectedColor = vec4(0); + return 0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl index 5dc219702d..cd49202f89 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl @@ -25,12 +25,18 @@ uniform sampler2D normalMap; uniform sampler2D depthMap; + +#if defined(SUN_SHADOW) uniform sampler2DShadow shadowMap0; uniform sampler2DShadow shadowMap1; uniform sampler2DShadow shadowMap2; uniform sampler2DShadow shadowMap3; +#endif + +#if defined(SPOT_SHADOW) uniform sampler2DShadow shadowMap4; uniform sampler2DShadow shadowMap5; +#endif uniform vec3 sun_dir; uniform vec3 moon_dir; @@ -48,6 +54,7 @@ uniform int sun_up_factor; float pcfShadow(sampler2DShadow shadowMap, vec3 norm, vec4 stc, float bias_mul, vec2 pos_screen, vec3 light_dir) { +#if defined(SUN_SHADOW) float offset = shadow_bias * bias_mul; stc.xyz /= stc.w; stc.z += offset * 2.0; @@ -59,10 +66,14 @@ float pcfShadow(sampler2DShadow shadowMap, vec3 norm, vec4 stc, float bias_mul, shadow += shadow2D(shadowMap, stc.xyz+vec3(-1.5/shadow_res.x, -0.5/shadow_res.y, 0.0)).x; shadow += shadow2D(shadowMap, stc.xyz+vec3(-0.5/shadow_res.x, 1.5/shadow_res.y, 0.0)).x; return clamp(shadow * 0.125, 0.0, 1.0); +#else + return 1.0; +#endif } float pcfSpotShadow(sampler2DShadow shadowMap, vec4 stc, float bias_scale, vec2 pos_screen) { +#if defined(SPOT_SHADOW) stc.xyz /= stc.w; stc.z += spot_shadow_bias * bias_scale; stc.x = floor(proj_shadow_res.x * stc.x + fract(pos_screen.y*0.666666666)) / proj_shadow_res.x; // snap @@ -78,10 +89,14 @@ float pcfSpotShadow(sampler2DShadow shadowMap, vec4 stc, float bias_scale, vec2 shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x; shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x*2.0, -off.y, 0.0)).x; return shadow*0.2; +#else + return 1.0; +#endif } float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen) { +#if defined(SUN_SHADOW) float shadow = 0.0f; vec3 light_dir = normalize((sun_up_factor == 1) ? sun_dir : moon_dir); @@ -175,10 +190,14 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen) } //shadow = min(dp_directional_light,shadow); return shadow; +#else + return 1.0; +#endif } float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen) { +#if defined(SPOT_SHADOW) float shadow = 0.0f; pos += norm * spot_shadow_offset; @@ -217,5 +236,8 @@ float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen) shadow = 1.0f; } return shadow; +#else + return 1.0; +#endif } diff --git a/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl b/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl index 6376527273..152316c117 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl @@ -36,7 +36,6 @@ VARYING vec2 vary_texcoord0; VARYING vec2 screenpos; uniform sampler2D diffuseMap; -uniform sampler2D altDiffuseMap; uniform float blend_factor; uniform float custom_alpha; uniform float time; diff --git a/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl b/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl index feaf562686..2b1e794b52 100644 --- a/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl @@ -23,205 +23,11 @@ * $/LicenseInfo$ */ +// debug stub -/*[EXTRA_CODE_HERE]*/ - - -#ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif -uniform samplerCubeArray reflectionProbes; -uniform int sourceIdx; - -VARYING vec3 vary_dir; - - -// Code below is derived from the Khronos GLTF Sample viewer: -// https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/master/source/shaders/ibl_filtering.frag - - -#define MATH_PI 3.1415926535897932384626433832795 - -float u_roughness = 1.0; -int u_sampleCount = 16; -float u_lodBias = 2.0; -int u_width = 64; - -// Hammersley Points on the Hemisphere -// CC BY 3.0 (Holger Dammertz) -// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html -// with adapted interface -float radicalInverse_VdC(uint bits) -{ - bits = (bits << 16u) | (bits >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - return float(bits) * 2.3283064365386963e-10; // / 0x100000000 -} - -// hammersley2d describes a sequence of points in the 2d unit square [0,1)^2 -// that can be used for quasi Monte Carlo integration -vec2 hammersley2d(int i, int N) { - return vec2(float(i)/float(N), radicalInverse_VdC(uint(i))); -} - -// Hemisphere Sample - -// TBN generates a tangent bitangent normal coordinate frame from the normal -// (the normal must be normalized) -mat3 generateTBN(vec3 normal) -{ - vec3 bitangent = vec3(0.0, 1.0, 0.0); - - float NdotUp = dot(normal, vec3(0.0, 1.0, 0.0)); - float epsilon = 0.0000001; - /*if (1.0 - abs(NdotUp) <= epsilon) - { - // Sampling +Y or -Y, so we need a more robust bitangent. - if (NdotUp > 0.0) - { - bitangent = vec3(0.0, 0.0, 1.0); - } - else - { - bitangent = vec3(0.0, 0.0, -1.0); - } - }*/ - - vec3 tangent = normalize(cross(bitangent, normal)); - bitangent = cross(normal, tangent); - - return mat3(tangent, bitangent, normal); -} - -struct MicrofacetDistributionSample -{ - float pdf; - float cosTheta; - float sinTheta; - float phi; -}; - -MicrofacetDistributionSample Lambertian(vec2 xi, float roughness) -{ - MicrofacetDistributionSample lambertian; - - // Cosine weighted hemisphere sampling - // http://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/2D_Sampling_with_Multidimensional_Transformations.html#Cosine-WeightedHemisphereSampling - lambertian.cosTheta = sqrt(1.0 - xi.y); - lambertian.sinTheta = sqrt(xi.y); // equivalent to `sqrt(1.0 - cosTheta*cosTheta)`; - lambertian.phi = 2.0 * MATH_PI * xi.x; - - lambertian.pdf = lambertian.cosTheta / MATH_PI; // evaluation for solid angle, therefore drop the sinTheta - - return lambertian; -} - - -// getImportanceSample returns an importance sample direction with pdf in the .w component -vec4 getImportanceSample(int sampleIndex, vec3 N, float roughness) -{ - // generate a quasi monte carlo point in the unit square [0.1)^2 - vec2 xi = hammersley2d(sampleIndex, u_sampleCount); - - MicrofacetDistributionSample importanceSample; - - // generate the points on the hemisphere with a fitting mapping for - // the distribution (e.g. lambertian uses a cosine importance) - importanceSample = Lambertian(xi, roughness); - - // transform the hemisphere sample to the normal coordinate frame - // i.e. rotate the hemisphere to the normal direction - vec3 localSpaceDirection = normalize(vec3( - importanceSample.sinTheta * cos(importanceSample.phi), - importanceSample.sinTheta * sin(importanceSample.phi), - importanceSample.cosTheta - )); - mat3 TBN = generateTBN(N); - vec3 direction = TBN * localSpaceDirection; - - return vec4(direction, importanceSample.pdf); -} - -// Mipmap Filtered Samples (GPU Gems 3, 20.4) -// https://developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-20-gpu-based-importance-sampling -// https://cgg.mff.cuni.cz/~jaroslav/papers/2007-sketch-fis/Final_sap_0073.pdf -float computeLod(float pdf) -{ - // // Solid angle of current sample -- bigger for less likely samples - // float omegaS = 1.0 / (float(u_sampleCount) * pdf); - // // Solid angle of texel - // // note: the factor of 4.0 * MATH_PI - // float omegaP = 4.0 * MATH_PI / (6.0 * float(u_width) * float(u_width)); - // // Mip level is determined by the ratio of our sample's solid angle to a texel's solid angle - // // note that 0.5 * log2 is equivalent to log4 - // float lod = 0.5 * log2(omegaS / omegaP); - - // babylon introduces a factor of K (=4) to the solid angle ratio - // this helps to avoid undersampling the environment map - // this does not appear in the original formulation by Jaroslav Krivanek and Mark Colbert - // log4(4) == 1 - // lod += 1.0; - - // We achieved good results by using the original formulation from Krivanek & Colbert adapted to cubemaps - - // https://cgg.mff.cuni.cz/~jaroslav/papers/2007-sketch-fis/Final_sap_0073.pdf - float lod = 0.5 * log2( 6.0 * float(u_width) * float(u_width) / (float(u_sampleCount) * pdf)); - - - return lod; -} - -vec4 filterColor(vec3 N) -{ - //return textureLod(uCubeMap, N, 3.0).rgb; - vec4 color = vec4(0.f); - float weight = 0.0f; - - for(int i = 0; i < u_sampleCount; ++i) - { - vec4 importanceSample = getImportanceSample(i, N, 1.0); - - vec3 H = vec3(importanceSample.xyz); - float pdf = importanceSample.w; - - // mipmap filtered samples (GPU Gems 3, 20.4) - float lod = computeLod(pdf); - - // apply the bias to the lod - lod += u_lodBias; - - lod = clamp(lod, 0, 6); - // sample lambertian at a lower resolution to avoid fireflies - vec4 lambertian = textureLod(reflectionProbes, vec4(H, sourceIdx), lod); - - color += lambertian; - } - - if(weight != 0.0f) - { - color /= weight; - } - else - { - color /= float(u_sampleCount); - } - - return color; -} - -// entry point void main() { - vec4 color = vec4(0); - - color = filterColor(vary_dir); - - frag_color = color; + frag_color = vec4(0.5, 0, 0.5, 0); } - diff --git a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl index 858052281b..e60ddcd569 100644 --- a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl @@ -37,6 +37,8 @@ VARYING vec3 vary_dir; uniform float mipLevel; uniform int u_width; +uniform float max_probe_lod; + // ============================================================================================================= // Parts of this file are (c) 2018 Sascha Willems @@ -128,7 +130,7 @@ vec4 prefilterEnvMap(vec3 R) float envMapDim = u_width; int numSamples = 4; - float numMips = 6.0; + float numMips = max_probe_lod; float roughness = mipLevel/numMips; diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index 076b976dc4..7435f1c0e1 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -90,8 +90,8 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); float getAmbientClamp(); -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, - vec3 pos, vec3 norm, float glossiness, float envIntensity); +void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, + vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity); vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, float ambiance) { @@ -253,7 +253,7 @@ void main() vec3 irradiance; vec3 glossenv; vec3 legacyenv; - sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, pos.xyz, norm.xyz, 0.0, 0.0); + sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, frag, pos.xyz, norm.xyz, 0.0, 0.0); float da = dot(norm.xyz, light_dir.xyz); diff --git a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl index d81102991e..ccf20942e3 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl @@ -84,7 +84,7 @@ void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float float calcLegacyDistanceAttenuation(float distance, float falloff); float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, - vec3 pos, vec3 norm, float glossiness); + vec2 tc, vec3 pos, vec3 norm, float glossiness); void waterClip(vec3 pos); @@ -207,7 +207,7 @@ void main() float gloss = 1.0 - perceptualRoughness; vec3 irradiance = vec3(0); vec3 radiance = vec3(0); - sampleReflectionProbes(irradiance, radiance, pos.xyz, norm.xyz, gloss); + sampleReflectionProbes(irradiance, radiance, vec2(0), pos.xyz, norm.xyz, gloss); // Take maximium of legacy ambient vs irradiance sample as irradiance // NOTE: ao is applied in pbrIbl (see pbrBaseLight), do not apply here irradiance = max(amblit,irradiance); diff --git a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl index af43c7b4e3..f1ee4b4681 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl @@ -34,7 +34,7 @@ uniform mat3 env_mat; vec3 srgb_to_linear(vec3 c); void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, - vec3 pos, vec3 norm, float glossiness, bool errorCorrect) + vec2 tc, vec3 pos, vec3 norm, float glossiness, bool errorCorrect) { ambenv = vec3(reflection_probe_ambiance * 0.25); @@ -44,10 +44,10 @@ void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, } void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, - vec3 pos, vec3 norm, float glossiness) + vec2 tc, vec3 pos, vec3 norm, float glossiness) { sampleReflectionProbes(ambenv, glossenv, - pos, norm, glossiness, false); + tc, pos, norm, glossiness, false); } vec4 sampleReflectionProbesDebug(vec3 pos) @@ -56,8 +56,8 @@ vec4 sampleReflectionProbesDebug(vec3 pos) return vec4(0, 0, 0, 0); } -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, - vec3 pos, vec3 norm, float glossiness, float envIntensity) +void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, + vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity) { ambenv = vec3(reflection_probe_ambiance * 0.25); diff --git a/indra/newview/app_settings/shaders/class2/interface/irradianceGenF.glsl b/indra/newview/app_settings/shaders/class2/interface/irradianceGenF.glsl new file mode 100644 index 0000000000..c7da23fb00 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/interface/irradianceGenF.glsl @@ -0,0 +1,218 @@ +/** + * @file irradianceGenF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +/*[EXTRA_CODE_HERE]*/ + +out vec4 frag_color; + +uniform samplerCubeArray reflectionProbes; +uniform int sourceIdx; + +uniform float max_probe_lod; +uniform float ambiance_scale; + +in vec3 vary_dir; + +// Code below is derived from the Khronos GLTF Sample viewer: +// https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/master/source/shaders/ibl_filtering.frag + + +#define MATH_PI 3.1415926535897932384626433832795 + +float u_roughness = 1.0; +int u_sampleCount = 32; +float u_lodBias = 2.0; +int u_width = 64; + +// Hammersley Points on the Hemisphere +// CC BY 3.0 (Holger Dammertz) +// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html +// with adapted interface +float radicalInverse_VdC(uint bits) +{ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +// hammersley2d describes a sequence of points in the 2d unit square [0,1)^2 +// that can be used for quasi Monte Carlo integration +vec2 hammersley2d(int i, int N) { + return vec2(float(i)/float(N), radicalInverse_VdC(uint(i))); +} + +// Hemisphere Sample + +// TBN generates a tangent bitangent normal coordinate frame from the normal +// (the normal must be normalized) +mat3 generateTBN(vec3 normal) +{ + vec3 bitangent = vec3(0.0, 1.0, 0.0); + + float NdotUp = dot(normal, vec3(0.0, 1.0, 0.0)); + float epsilon = 0.0000001; + /*if (1.0 - abs(NdotUp) <= epsilon) + { + // Sampling +Y or -Y, so we need a more robust bitangent. + if (NdotUp > 0.0) + { + bitangent = vec3(0.0, 0.0, 1.0); + } + else + { + bitangent = vec3(0.0, 0.0, -1.0); + } + }*/ + + vec3 tangent = normalize(cross(bitangent, normal)); + bitangent = cross(normal, tangent); + + return mat3(tangent, bitangent, normal); +} + +struct MicrofacetDistributionSample +{ + float pdf; + float cosTheta; + float sinTheta; + float phi; +}; + +MicrofacetDistributionSample Lambertian(vec2 xi, float roughness) +{ + MicrofacetDistributionSample lambertian; + + // Cosine weighted hemisphere sampling + // http://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/2D_Sampling_with_Multidimensional_Transformations.html#Cosine-WeightedHemisphereSampling + lambertian.cosTheta = sqrt(1.0 - xi.y); + lambertian.sinTheta = sqrt(xi.y); // equivalent to `sqrt(1.0 - cosTheta*cosTheta)`; + lambertian.phi = 2.0 * MATH_PI * xi.x; + + lambertian.pdf = lambertian.cosTheta / MATH_PI; // evaluation for solid angle, therefore drop the sinTheta + + return lambertian; +} + + +// getImportanceSample returns an importance sample direction with pdf in the .w component +vec4 getImportanceSample(int sampleIndex, vec3 N, float roughness) +{ + // generate a quasi monte carlo point in the unit square [0.1)^2 + vec2 xi = hammersley2d(sampleIndex, u_sampleCount); + + MicrofacetDistributionSample importanceSample; + + // generate the points on the hemisphere with a fitting mapping for + // the distribution (e.g. lambertian uses a cosine importance) + importanceSample = Lambertian(xi, roughness); + + // transform the hemisphere sample to the normal coordinate frame + // i.e. rotate the hemisphere to the normal direction + vec3 localSpaceDirection = normalize(vec3( + importanceSample.sinTheta * cos(importanceSample.phi), + importanceSample.sinTheta * sin(importanceSample.phi), + importanceSample.cosTheta + )); + mat3 TBN = generateTBN(N); + vec3 direction = TBN * localSpaceDirection; + + return vec4(direction, importanceSample.pdf); +} + +// Mipmap Filtered Samples (GPU Gems 3, 20.4) +// https://developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-20-gpu-based-importance-sampling +// https://cgg.mff.cuni.cz/~jaroslav/papers/2007-sketch-fis/Final_sap_0073.pdf +float computeLod(float pdf) +{ + // // Solid angle of current sample -- bigger for less likely samples + // float omegaS = 1.0 / (float(u_sampleCount) * pdf); + // // Solid angle of texel + // // note: the factor of 4.0 * MATH_PI + // float omegaP = 4.0 * MATH_PI / (6.0 * float(u_width) * float(u_width)); + // // Mip level is determined by the ratio of our sample's solid angle to a texel's solid angle + // // note that 0.5 * log2 is equivalent to log4 + // float lod = 0.5 * log2(omegaS / omegaP); + + // babylon introduces a factor of K (=4) to the solid angle ratio + // this helps to avoid undersampling the environment map + // this does not appear in the original formulation by Jaroslav Krivanek and Mark Colbert + // log4(4) == 1 + // lod += 1.0; + + // We achieved good results by using the original formulation from Krivanek & Colbert adapted to cubemaps + + // https://cgg.mff.cuni.cz/~jaroslav/papers/2007-sketch-fis/Final_sap_0073.pdf + float lod = 0.5 * log2( 6.0 * float(u_width) * float(u_width) / (float(u_sampleCount) * pdf)); + + + return lod; +} + +vec4 filterColor(vec3 N) +{ + //return textureLod(uCubeMap, N, 3.0).rgb; + vec4 color = vec4(0.f); + + for(int i = 0; i < u_sampleCount; ++i) + { + vec4 importanceSample = getImportanceSample(i, N, 1.0); + + vec3 H = vec3(importanceSample.xyz); + float pdf = importanceSample.w; + + // mipmap filtered samples (GPU Gems 3, 20.4) + float lod = computeLod(pdf); + + // apply the bias to the lod + lod += u_lodBias; + + lod = clamp(lod, 0, 7); + // sample lambertian at a lower resolution to avoid fireflies + vec4 lambertian = textureLod(reflectionProbes, vec4(H, sourceIdx), lod); + + color += lambertian; + } + + color /= float(u_sampleCount); + + color.rgb *= ambiance_scale; + + return color; +} + +// entry point +void main() +{ + vec4 color = vec4(0); + + color = filterColor(vary_dir); + + frag_color = color; +} + diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl index c69eba93b6..ba02070e45 100644 --- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl +++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl @@ -162,90 +162,10 @@ float ambientLighting(vec3 norm, vec3 light_dir) void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten) { -#if 1 calcAtmosphericVars(inPositionEye, light_dir, 1.0, sunlit, amblit, additive, atten, false); sunlit = srgb_to_linear(sunlit); additive = srgb_to_linear(additive); amblit = ambient_linear; amblit *= ambientLighting(norm, light_dir); -#else - - //EXPERIMENTAL -- attempt to factor out srgb_to_linear conversions above - vec3 rel_pos = inPositionEye; - - //(TERRAIN) limit altitude - if (abs(rel_pos.y) > max_y) rel_pos *= (max_y / rel_pos.y); - - vec3 rel_pos_norm = normalize(rel_pos); - float rel_pos_len = length(rel_pos); - vec3 sunlight = (sun_up_factor == 1) ? vec3(sunlight_linear, 0.0) : vec3(moonlight_linear, 0.0); - - // sunlight attenuation effect (hue and brightness) due to atmosphere - // this is used later for sunlight modulation at various altitudes - vec3 light_atten = (blue_density + vec3(haze_density * 0.25)) * (density_multiplier * max_y); - // I had thought blue_density and haze_density should have equal weighting, - // but attenuation due to haze_density tends to seem too strong - - vec3 combined_haze = blue_density + vec3(haze_density); - vec3 blue_weight = blue_density / combined_haze; - vec3 haze_weight = vec3(haze_density) / combined_haze; - - //(TERRAIN) compute sunlight from lightnorm y component. Factor is roughly cosecant(sun elevation) (for short rays like terrain) - float above_horizon_factor = 1.0 / max(1e-6, lightnorm.y); - sunlight *= exp(-light_atten * above_horizon_factor); // for sun [horizon..overhead] this maps to an exp curve [0..1] - - // main atmospheric scattering line integral - float density_dist = rel_pos_len * density_multiplier; - - // Transparency (-> combined_haze) - // ATI Bugfix -- can't store combined_haze*density_dist*distance_multiplier in a variable because the ati - // compiler gets confused. - combined_haze = exp(-combined_haze * density_dist * distance_multiplier); - - // final atmosphere attenuation factor - atten = combined_haze.rgb; - - // compute haze glow - float haze_glow = dot(rel_pos_norm, lightnorm.xyz); - - // dampen sun additive contrib when not facing it... - // SL-13539: This "if" clause causes an "additive" white artifact at roughly 77 degreees. - // if (length(light_dir) > 0.01) - haze_glow *= max(0.0f, dot(light_dir, rel_pos_norm)); - - haze_glow = 1. - haze_glow; - // haze_glow is 0 at the sun and increases away from sun - haze_glow = max(haze_glow, .001); // set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) - haze_glow *= glow.x; - // higher glow.x gives dimmer glow (because next step is 1 / "angle") - haze_glow = pow(haze_glow, glow.z); - // glow.z should be negative, so we're doing a sort of (1 / "angle") function - - // add "minimum anti-solar illumination" - haze_glow += .25; - - haze_glow *= sun_moon_glow_factor; - - //vec3 amb_color = vec4(ambient_linear, 0.0); - vec3 amb_color = ambient_color; - - // increase ambient when there are more clouds - vec3 tmpAmbient = amb_color + (vec3(1.) - amb_color) * cloud_shadow * 0.5; - - // Similar/Shared Algorithms: - // indra\llinventory\llsettingssky.cpp -- LLSettingsSky::calculateLightSettings() - // indra\newview\app_settings\shaders\class1\windlight\atmosphericsFuncs.glsl -- calcAtmosphericVars() - // haze color - vec3 cs = sunlight.rgb * (1. - cloud_shadow); - additive = (blue_horizon.rgb * blue_weight.rgb) * (cs + tmpAmbient.rgb) + (haze_horizon * haze_weight.rgb) * (cs * haze_glow + tmpAmbient.rgb); - - // brightness of surface both sunlight and ambient - sunlit = min(sunlight.rgb, vec3(1)); - amblit = tmpAmbient.rgb; - additive *= vec3(1.0 - combined_haze); - - //sunlit = sunlight_linear; - amblit = ambient_linear*0.8; -#endif } diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl index c0a1491446..160d360256 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl @@ -56,8 +56,9 @@ vec3 linear_to_srgb(vec3 c); vec3 srgb_to_linear(vec3 c); // reflection probe interface -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv, - vec3 pos, vec3 norm, float glossiness, float envIntensity); +void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, + vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity); + void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm); void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); @@ -91,7 +92,7 @@ void main() vec3 legacyenv; vec3 norm = normalize(vary_texcoord1.xyz); vec4 spec = vec4(0,0,0,0); - sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, env_intensity); + sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, vec2(0), pos.xyz, norm.xyz, spec.a, env_intensity); applyLegacyEnv(color.rgb, legacyenv, spec, pos, norm, env_intensity); color.rgb = fullbrightAtmosTransportFrag(color.rgb, additive, atten); diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index 8016022d78..8d2a65d4a9 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -61,8 +61,8 @@ out vec4 frag_color; float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); #endif -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, - vec3 pos, vec3 norm, float glossiness, float envIntensity); +void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, + vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity); void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm); void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); @@ -310,7 +310,7 @@ void main() vec3 ambenv; vec3 glossenv; vec3 legacyenv; - sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, final_specular.a, env_intensity); + sampleReflectionProbesLegacy(ambenv, glossenv, legacyenv, pos_screen, pos.xyz, norm.xyz, final_specular.a, env_intensity); // use sky settings ambient or irradiance map sample, whichever is brighter color = max(amblit, ambenv); diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl index 0cb966296a..bb3be7260b 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -25,11 +25,18 @@ #define FLT_MAX 3.402823466e+38 +#if defined(SSR) +float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source); +#endif + #define REFMAP_COUNT 256 #define REF_SAMPLE_COUNT 64 //maximum number of samples to consider uniform samplerCubeArray reflectionProbes; uniform samplerCubeArray irradianceProbes; +uniform sampler2D sceneMap; +uniform int cube_snapshot; +uniform float max_probe_lod; layout (std140) uniform ReflectionProbes { @@ -92,14 +99,17 @@ bool shouldSampleProbe(int i, vec3 pos) } else { - vec3 delta = pos.xyz - refSphere[i].xyz; - float d = dot(delta, delta); - float r2 = refSphere[i].w; - r2 *= r2; + if (refSphere[i].w > 0.0) // zero is special indicator to always sample this probe + { + vec3 delta = pos.xyz - refSphere[i].xyz; + float d = dot(delta, delta); + float r2 = refSphere[i].w; + r2 *= r2; - if (d > r2) - { //outside bounding sphere - return false; + if (d > r2) + { //outside bounding sphere + return false; + } } max_priority = max(max_priority, refIndex[i].w); @@ -138,13 +148,13 @@ void preProbeSample(vec3 pos) probeIndex[probeInfluences++] = idx; if (probeInfluences == REF_SAMPLE_COUNT) { - return; + break; } } count++; if (count == neighborCount) { - return; + break; } idx = refNeighbor[neighborIdx].y; @@ -153,13 +163,13 @@ void preProbeSample(vec3 pos) probeIndex[probeInfluences++] = idx; if (probeInfluences == REF_SAMPLE_COUNT) { - return; + break; } } count++; if (count == neighborCount) { - return; + break; } idx = refNeighbor[neighborIdx].z; @@ -168,13 +178,13 @@ void preProbeSample(vec3 pos) probeIndex[probeInfluences++] = idx; if (probeInfluences == REF_SAMPLE_COUNT) { - return; + break; } } count++; if (count == neighborCount) { - return; + break; } idx = refNeighbor[neighborIdx].w; @@ -183,27 +193,26 @@ void preProbeSample(vec3 pos) probeIndex[probeInfluences++] = idx; if (probeInfluences == REF_SAMPLE_COUNT) { - return; + break; } } count++; if (count == neighborCount) { - return; + break; } ++neighborIdx; } - return; + break; } } } - if (probeInfluences == 0) - { // probe at index 0 is a special fallback probe - probeIndex[0] = 0; - probeInfluences = 1; + if (max_priority <= 1) + { // probe at index 0 is a special probe for smoothing out automatic probes + probeIndex[probeInfluences++] = 0; } } @@ -330,7 +339,8 @@ return texCUBE(envMap, ReflDirectionWS); // origin - ray origin in clip space // dir - ray direction in clip space // i - probe index in refBox/refSphere -vec3 boxIntersect(vec3 origin, vec3 dir, int i) +// d - distance to nearest wall in clip space +vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d) { // Intersection with OBB convertto unit box space // Transform in local unit parallax cube space (scaled and rotated) @@ -339,6 +349,8 @@ vec3 boxIntersect(vec3 origin, vec3 dir, int i) vec3 RayLS = mat3(clipToLocal) * dir; vec3 PositionLS = (clipToLocal * vec4(origin, 1.0)).xyz; + d = 1.0-max(max(abs(PositionLS.x), abs(PositionLS.y)), abs(PositionLS.z)); + vec3 Unitary = vec3(1.0f, 1.0f, 1.0f); vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS; vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS; @@ -413,6 +425,29 @@ void boxIntersectDebug(vec3 origin, vec3 pos, int i, inout vec4 col) } +// get the weight of a sphere probe +// pos - position to be weighted +// dir - normal to be weighted +// origin - center of sphere probe +// r - radius of probe influence volume +// min_da - minimum angular attenuation coefficient +float sphereWeight(vec3 pos, vec3 dir, vec3 origin, float r, float min_da) +{ + float r1 = r * 0.5; // 50% of radius (outer sphere to start interpolating down) + vec3 delta = pos.xyz - origin; + float d2 = max(length(delta), 0.001); + float r2 = r1; //r1 * r1; + + //float atten = 1.0 - max(d2 - r2, 0.0) / max((rr - r2), 0.001); + float atten = 1.0 - max(d2 - r2, 0.0) / max((r - r2), 0.001); + + atten *= max(dot(normalize(-delta), dir), min_da); + float w = 1.0 / d2; + w *= atten; + + return w; +} + // Tap a reflection probe // pos - position of pixel // dir - pixel normal @@ -431,27 +466,21 @@ vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out vec3 vi, out vec3 wi, float if (refIndex[i].w < 0) { - v = boxIntersect(pos, dir, i); - w = 1.0; + float d = 0; + v = boxIntersect(pos, dir, i, d); + + w = max(d, 0.001); } else { float r = refSphere[i].w; // radius of sphere volume float rr = r * r; // radius squared - v = sphereIntersect(pos, dir, c, rr); + v = sphereIntersect(pos, dir, c, + refIndex[i].w <= 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres + rr); - float p = float(abs(refIndex[i].w)); // priority - - float r1 = r * 0.1; // 90% of radius (outer sphere to start interpolating down) - vec3 delta = pos.xyz - refSphere[i].xyz; - float d2 = max(dot(delta, delta), 0.001); - float r2 = r1 * r1; - - float atten = 1.0 - max(d2 - r2, 0.0) / max((rr - r2), 0.001); - - w = 1.0 / d2; - w *= atten; + w = sphereWeight(pos, dir, refSphere[i].xyz, r, 0.25); } vi = v; @@ -480,8 +509,9 @@ vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, vec3 c, int i) vec3 v; if (refIndex[i].w < 0) { - v = boxIntersect(pos, dir, i); - w = 1.0; + float d = 0.0; + v = boxIntersect(pos, dir, i, d); + w = max(d, 0.001); } else { @@ -489,17 +519,11 @@ vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, vec3 c, int i) float p = float(abs(refIndex[i].w)); // priority float rr = r * r; // radius squred - v = sphereIntersect(pos, dir, c, rr); + v = sphereIntersect(pos, dir, c, + refIndex[i].w <= 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres + rr); - float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down) - vec3 delta = pos.xyz - refSphere[i].xyz; - float d2 = dot(delta, delta); - float r2 = r1 * r1; - - w = 1.0 / d2; - - float atten = 1.0 - max(d2 - r2, 0.0) / (rr - r2); - w *= atten; + w = sphereWeight(pos, dir, refSphere[i].xyz, r, 0.001); } v -= c; @@ -600,15 +624,15 @@ vec3 sampleProbeAmbient(vec3 pos, vec3 dir) { col *= 1.0/wsum; } - + return col; } void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, - vec3 pos, vec3 norm, float glossiness, bool errorCorrect) + vec2 tc, vec3 pos, vec3 norm, float glossiness, bool errorCorrect) { // TODO - don't hard code lods - float reflection_lods = 6; + float reflection_lods = max_probe_lod; preProbeSample(pos); vec3 refnormpersp = reflect(pos.xyz, norm.xyz); @@ -617,6 +641,17 @@ void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, float lod = (1.0-glossiness)*reflection_lods; glossenv = sampleProbes(pos, normalize(refnormpersp), lod, errorCorrect); + +#if defined(SSR) + if (cube_snapshot != 1) + { + vec4 ssr = vec4(0); + //float w = tapScreenSpaceReflection(errorCorrect ? 1 : 4, tc, pos, norm, ssr, sceneMap); + float w = tapScreenSpaceReflection(1, tc, pos, norm, ssr, sceneMap); + + glossenv = mix(glossenv, ssr.rgb, w); + } +#endif } void debugTapRefMap(vec3 pos, vec3 dir, float depth, int i, inout vec4 col) @@ -660,23 +695,22 @@ vec4 sampleReflectionProbesDebug(vec3 pos) } void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, - vec3 pos, vec3 norm, float glossiness) + vec2 tc, vec3 pos, vec3 norm, float glossiness) { sampleReflectionProbes(ambenv, glossenv, - pos, norm, glossiness, false); + tc, pos, norm, glossiness, false); } void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, - vec3 pos, vec3 norm, float glossiness, float envIntensity) + vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity) { // TODO - don't hard code lods - float reflection_lods = 7; + float reflection_lods = max_probe_lod; preProbeSample(pos); vec3 refnormpersp = reflect(pos.xyz, norm.xyz); - ambenv = sampleProbeAmbient(pos, norm); if (glossiness > 0.0) @@ -689,6 +723,17 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout { legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0, false); } + +#if defined(SSR) + if (cube_snapshot != 1) + { + vec4 ssr = vec4(0); + float w = tapScreenSpaceReflection(1, tc, pos, norm, ssr, sceneMap); + + glossenv = mix(glossenv, ssr.rgb, w); + legacyenv = mix(legacyenv, ssr.rgb, w); + } +#endif } void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm) diff --git a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl index d48aeb98b6..742f528cb1 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl @@ -42,10 +42,7 @@ uniform float zFar; VARYING vec2 vary_fragcoord; VARYING vec3 camera_ray; -uniform sampler2D depthMap; -uniform sampler2D normalMap; uniform sampler2D specularRect; -uniform sampler2D sceneMap; uniform sampler2D diffuseRect; uniform sampler2D diffuseMap; @@ -57,62 +54,45 @@ float linearDepth01(float d, float znear, float zfar); vec4 getPositionWithDepth(vec2 pos_screen, float depth); vec4 getPosition(vec2 pos_screen); vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); -bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float hitDepth, float depth, sampler2D textureFrame); + float random (vec2 uv); -void main() { + +float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source); + +void main() +{ vec2 tc = vary_fragcoord.xy; float depth = linearDepth01(getDepth(tc), zNear, zFar); - vec3 n = vec3(0, 0, 1); float envIntensity; + vec3 n; vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG() vec3 pos = getPositionWithDepth(tc, getDepth(tc)).xyz; vec4 spec = texture2D(specularRect, tc); - vec3 viewPos = camera_ray * depth; - vec3 rayDirection = normalize(reflect(normalize(viewPos), n)) * -viewPos.z; vec2 hitpixel; - vec4 hitpoint; + vec4 diffuse = texture2D(diffuseRect, tc); vec3 specCol = spec.rgb; - if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { + frag_color = texture(diffuseMap, tc); + + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) + { vec3 orm = specCol.rgb; float perceptualRoughness = orm.g; float metallic = orm.b; vec3 f0 = vec3(0.04); vec3 baseColor = diffuse.rgb; - + vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0); specCol = mix(f0, baseColor.rgb, metallic); } - vec2 uv2 = tc * screen_res; - float c = (uv2.x + uv2.y) * 0.125; - float jitter = mod( c, 1.0); + vec4 collectedColor = vec4(0); - vec3 firstBasis = normalize(cross(vec3(1.f, 1.f, 1.f), rayDirection)); - vec3 secondBasis = normalize(cross(rayDirection, firstBasis)); - - frag_color = texture(diffuseMap, tc); - vec4 collectedColor; - - vec2 screenpos = 1 - abs(tc * 2 - 1); - float vignette = clamp((screenpos.x * screenpos.y) * 16,0, 1); - vignette *= clamp((dot(normalize(viewPos), n) * 0.5 + 0.5 - 0.2) * 8, 0, 1); - vignette *= min(linearDepth(getDepth(tc), zNear, zFar) / zFar, 1); - int totalSamples = 4; - for (int i = 0; i < totalSamples; i++) { - vec2 coeffs = vec2(random(tc + vec2(0, i)) + random(tc + vec2(i, 0))); - vec3 reflectionDirectionRandomized = rayDirection + firstBasis * coeffs.x + secondBasis * coeffs.y; + float w = tapScreenSpaceReflection(4, tc, pos, n, collectedColor, diffuseMap); - bool hit = traceScreenRay(pos, reflectionDirectionRandomized, hitpoint, depth, depth, diffuseMap); - if (hit) { - collectedColor += hitpoint; - collectedColor.rgb *= specCol.rgb; - } - } + collectedColor.rgb *= specCol.rgb; - collectedColor *= vignette; - - frag_color += collectedColor; + frag_color += collectedColor * w; } diff --git a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflUtil.glsl b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflUtil.glsl index f8c6e5701a..c355b671c0 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflUtil.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflUtil.glsl @@ -23,31 +23,32 @@ * $/LicenseInfo$ */ -uniform sampler2D depthMap; -uniform sampler2D normalMap; uniform sampler2D sceneMap; +uniform sampler2D sceneDepth; + uniform vec2 screen_res; uniform mat4 projection_matrix; -uniform float zNear; -uniform float zFar; +//uniform float zNear; +//uniform float zFar; uniform mat4 inv_proj; +uniform mat4 modelview_delta; // should be transform from last camera space to current camera space +uniform mat4 inv_modelview_delta; vec4 getPositionWithDepth(vec2 pos_screen, float depth); -float linearDepth(float depth, float near, float far); -float getDepth(vec2 pos_screen); -float linearDepth01(float d, float znear, float zfar); -float random (vec2 uv) { - return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123); //simple random function +float random (vec2 uv) +{ + return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123); //simple random function } // Based off of https://github.com/RoundedGlint585/ScreenSpaceReflection/ // A few tweaks here and there to suit our needs. -vec2 generateProjectedPosition(vec3 pos){ - vec4 samplePosition = projection_matrix * vec4(pos, 1.f); - samplePosition.xy = (samplePosition.xy / samplePosition.w) * 0.5 + 0.5; - return samplePosition.xy; +vec2 generateProjectedPosition(vec3 pos) +{ + vec4 samplePosition = projection_matrix * vec4(pos, 1.f); + samplePosition.xy = (samplePosition.xy / samplePosition.w) * 0.5 + 0.5; + return samplePosition.xy; } bool isBinarySearchEnabled = true; @@ -60,79 +61,174 @@ float distanceBias = 0.02; float depthRejectBias = 0.001; float epsilon = 0.1; -bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float hitDepth, float depth, sampler2D textureFrame) { - vec3 step = rayStep * reflection; - vec3 marchingPosition = position + step; - float delta; - float depthFromScreen; - vec2 screenPosition; +float getLinearDepth(vec2 tc) +{ + float depth = texture(sceneDepth, tc).r; + + vec4 pos = getPositionWithDepth(tc, depth); + + return -pos.z; +} + +bool traceScreenRay(vec3 position, vec3 reflection, out vec4 hitColor, out float hitDepth, float depth, sampler2D textureFrame) +{ + // transform position and reflection into same coordinate frame as the sceneMap and sceneDepth + reflection += position; + position = (inv_modelview_delta * vec4(position, 1)).xyz; + reflection = (inv_modelview_delta * vec4(reflection, 1)).xyz; + reflection -= position; + + depth = -position.z; + + vec3 step = rayStep * reflection; + vec3 marchingPosition = position + step; + float delta; + float depthFromScreen; + vec2 screenPosition; bool hit = false; hitColor = vec4(0); - - int i = 0; - if (depth > depthRejectBias) { - for (; i < iterationCount && !hit; i++) { - screenPosition = generateProjectedPosition(marchingPosition); - depthFromScreen = linearDepth(getDepth(screenPosition), zNear, zFar); - delta = abs(marchingPosition.z) - depthFromScreen; - - if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon) { - break; - } + + + int i = 0; + if (depth > depthRejectBias) + { + for (; i < iterationCount && !hit; i++) + { + screenPosition = generateProjectedPosition(marchingPosition); + depthFromScreen = getLinearDepth(screenPosition); + delta = abs(marchingPosition.z) - depthFromScreen; + + if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon) + { + break; + } - if (abs(delta) < distanceBias) { - vec4 color = vec4(1); - if(debugDraw) - color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0); - hitColor = texture(textureFrame, screenPosition) * color; - hitDepth = depthFromScreen; - hit = true; - break; - } - if (isBinarySearchEnabled && delta > 0) { - break; - } - if (isAdaptiveStepEnabled){ - float directionSign = sign(abs(marchingPosition.z) - depthFromScreen); - //this is sort of adapting step, should prevent lining reflection by doing sort of iterative converging - //some implementation doing it by binary search, but I found this idea more cheaty and way easier to implement - step = step * (1.0 - rayStep * max(directionSign, 0.0)); - marchingPosition += step * (-directionSign); - } - else { - marchingPosition += step; - } + if (abs(delta) < distanceBias) + { + vec4 color = vec4(1); + if(debugDraw) + color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0); + hitColor = texture(sceneMap, screenPosition) * color; + hitDepth = depthFromScreen; + hit = true; + break; + } + if (isBinarySearchEnabled && delta > 0) + { + break; + } + if (isAdaptiveStepEnabled) + { + float directionSign = sign(abs(marchingPosition.z) - depthFromScreen); + //this is sort of adapting step, should prevent lining reflection by doing sort of iterative converging + //some implementation doing it by binary search, but I found this idea more cheaty and way easier to implement + step = step * (1.0 - rayStep * max(directionSign, 0.0)); + marchingPosition += step * (-directionSign); + } + else + { + marchingPosition += step; + } - if (isExponentialStepEnabled){ - step *= 1.05; - } - } - if(isBinarySearchEnabled){ - for(; i < iterationCount && !hit; i++){ - - step *= 0.5; - marchingPosition = marchingPosition - step * sign(delta); - - screenPosition = generateProjectedPosition(marchingPosition); - depthFromScreen = linearDepth(getDepth(screenPosition), zNear, zFar); - delta = abs(marchingPosition.z) - depthFromScreen; + if (isExponentialStepEnabled) + { + step *= 1.05; + } + } + if(isBinarySearchEnabled) + { + for(; i < iterationCount && !hit; i++) + { + step *= 0.5; + marchingPosition = marchingPosition - step * sign(delta); + + screenPosition = generateProjectedPosition(marchingPosition); + depthFromScreen = getLinearDepth(screenPosition); + delta = abs(marchingPosition.z) - depthFromScreen; - if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon) { - break; - } + if (depth < depthFromScreen + epsilon && depth > depthFromScreen - epsilon) + { + break; + } - if (abs(delta) < distanceBias && depthFromScreen != (depth - distanceBias)) { - vec4 color = vec4(1); - if(debugDraw) - color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0); - hitColor = texture(textureFrame, screenPosition) * color; - hitDepth = depthFromScreen; - hit = true; - break; - } - } - } - } - + if (abs(delta) < distanceBias && depthFromScreen != (depth - distanceBias)) + { + vec4 color = vec4(1); + if(debugDraw) + color = vec4( 0.5+ sign(delta)/2,0.3,0.5- sign(delta)/2, 0); + hitColor = texture(sceneMap, screenPosition) * color; + hitDepth = depthFromScreen; + hit = true; + break; + } + } + } + } + return hit; } + +float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n, inout vec4 collectedColor, sampler2D source) +{ + collectedColor = vec4(0); + int hits = 0; + + float depth = -viewPos.z; + + vec3 rayDirection = normalize(reflect(viewPos, normalize(n))); + + vec2 uv2 = tc * screen_res; + float c = (uv2.x + uv2.y) * 0.125; + float jitter = mod( c, 1.0); + + vec3 firstBasis = normalize(cross(vec3(1,1,1), rayDirection)); + vec3 secondBasis = normalize(cross(rayDirection, firstBasis)); + + vec2 screenpos = 1 - abs(tc * 2 - 1); + float vignette = clamp((screenpos.x * screenpos.y) * 16,0, 1); + vignette *= clamp((dot(normalize(viewPos), n) * 0.5 + 0.5 - 0.2) * 8, 0, 1); + float zFar = 64.0; + vignette *= clamp(1.0+(viewPos.z/zFar), 0.0, 1.0); + //vignette *= min(linearDepth(getDepth(tc), zNear, zFar) / zFar, 1); + + vec4 hitpoint; + + if (totalSamples > 1) + { + for (int i = 0; i < totalSamples; i++) + { + vec2 coeffs = vec2(random(tc + vec2(0, i)) + random(tc + vec2(i, 0))); + vec3 reflectionDirectionRandomized = rayDirection + firstBasis * coeffs.x + secondBasis * coeffs.y; + + //float hitDepth; + + bool hit = traceScreenRay(viewPos, normalize(reflectionDirectionRandomized), hitpoint, depth, depth, source); + + if (hit) + { + ++hits; + collectedColor += hitpoint; + } + } + } + else + { + bool hit = traceScreenRay(viewPos, normalize(rayDirection), hitpoint, depth, depth, source); + if (hit) + { + ++hits; + collectedColor += hitpoint; + } + } + + if (hits > 0) + { + collectedColor /= hits; + } + else + { + collectedColor = vec4(0); + } + + return min(float(hits), 1.0) * vignette; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl index 5f6982746b..8d48e6f596 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -41,7 +41,6 @@ uniform sampler2D diffuseRect; uniform sampler2D specularRect; uniform sampler2D normalMap; uniform sampler2D emissiveRect; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl -uniform sampler2D altDiffuseMap; // PBR: irradiance, skins/default/textures/default_irradiance.png const float M_PI = 3.14159265; @@ -76,9 +75,9 @@ vec3 fullbrightAtmosTransportFragLinear(vec3 light, vec3 additive, vec3 atten); // reflection probe interface void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, - vec3 pos, vec3 norm, float glossiness); -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv, - vec3 pos, vec3 norm, float glossiness, float envIntensity); + vec2 tc, vec3 pos, vec3 norm, float glossiness); +void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, + vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity); void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm); void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); float getDepth(vec2 pos_screen); @@ -167,7 +166,7 @@ void main() float gloss = 1.0 - perceptualRoughness; vec3 irradiance = vec3(0); vec3 radiance = vec3(0); - sampleReflectionProbes(irradiance, radiance, pos.xyz, norm.xyz, gloss); + sampleReflectionProbes(irradiance, radiance, tc, pos.xyz, norm.xyz, gloss); // Take maximium of legacy ambient vs irradiance sample as irradiance // NOTE: ao is applied in pbrIbl (see pbrBaseLight), do not apply here @@ -197,7 +196,7 @@ void main() vec3 glossenv = vec3(0); vec3 legacyenv = vec3(0); - sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity); + sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, tc, pos.xyz, norm.xyz, spec.a, envIntensity); // use sky settings ambient or irradiance map sample, whichever is brighter irradiance = max(amblit, irradiance); diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl index 85c3f42801..b792feee2a 100644 --- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl @@ -95,9 +95,6 @@ vec3 BlendNormal(vec3 bump1, vec3 bump2) vec3 srgb_to_linear(vec3 col); -void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, - vec3 pos, vec3 norm, float glossiness, float envIntensity); - vec3 vN, vT, vB; vec3 transform_normal(vec3 vNt) @@ -106,7 +103,10 @@ vec3 transform_normal(vec3 vNt) } void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, - vec3 pos, vec3 norm, float glossiness, bool errorCorrect); + vec2 tc, vec3 pos, vec3 norm, float glossiness); + +void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, + vec2 tc, vec3 pos, vec3 norm, float glossiness, bool errorCorrect); vec3 getPositionWithNDC(vec3 ndc); @@ -225,7 +225,7 @@ void main() vec3 irradiance = vec3(0); vec3 radiance = vec3(0); - sampleReflectionProbes(irradiance, radiance, pos, refnorm, gloss, true); + sampleReflectionProbes(irradiance, radiance, distort, pos, refnorm, gloss, true); radiance *= 0.5; irradiance = fb.rgb; diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index 72698b2831..526aceca26 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -1,4 +1,4 @@ -version 45 +version 47 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended @@ -62,7 +62,6 @@ Disregard128DefaultDrawDistance 1 1 Disregard96DefaultDrawDistance 1 1 RenderCompressTextures 1 1 RenderShaderLightingMaxLevel 1 3 -RenderPBR 1 1 RenderReflectionProbeCount 1 256 RenderDeferred 1 1 RenderDeferredSSAO 1 1 @@ -73,6 +72,7 @@ RenderFSAASamples 1 16 RenderMaxTextureIndex 1 16 RenderGLContextCoreProfile 1 1 RenderGLMultiThreaded 1 0 +RenderReflectionProbeResolution 1 256 // @@ -272,6 +272,12 @@ RenderUseAdvancedAtmospherics 1 0 list VRAMGT512 RenderCompressTextures 1 0 +// +// VRAM < 2GB +// +list VRAMLT2GB +RenderReflectionProbeResolution 1 128 + // // "Default" setups for safe, low, medium, high // @@ -292,6 +298,9 @@ RenderAnisotropic 1 0 RenderFSAASamples 1 0 RenderGLContextCoreProfile 1 0 +list AMD +RenderGLMultiThreaded 1 1 + list GL3 RenderFSAASamples 0 0 RenderReflectionsEnabled 0 0 diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index a687fe95d9..b0044faca9 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -1,4 +1,4 @@ -version 35 +version 36 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended @@ -62,7 +62,6 @@ Disregard128DefaultDrawDistance 1 1 Disregard96DefaultDrawDistance 1 1 RenderCompressTextures 1 1 RenderShaderLightingMaxLevel 1 3 -RenderPBR 1 1 RenderReflectionProbeCount 1 256 RenderDeferred 1 1 RenderDeferredSSAO 1 1 @@ -73,6 +72,7 @@ RenderFSAASamples 1 16 RenderMaxTextureIndex 1 16 RenderGLContextCoreProfile 1 1 RenderGLMultiThreaded 1 0 +RenderReflectionProbeResolution 1 256 // @@ -272,6 +272,12 @@ RenderUseAdvancedAtmospherics 1 0 list VRAMGT512 RenderCompressTextures 1 0 +// +// VRAM < 2GB +// +list VRAMLT2GB +RenderReflectionProbeResolution 1 128 + // // "Default" setups for safe, low, medium, high // diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index bd9c733d8a..1eaecd16cd 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -61,7 +61,6 @@ Disregard96DefaultDrawDistance 1 1 RenderCompressTextures 1 1 RenderShaderLightingMaxLevel 1 3 RenderDeferred 1 1 -RenderPBR 1 1 RenderDeferredSSAO 1 1 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index a535037121..e04de904b0 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -88,11 +88,6 @@ void LLDrawPoolAlpha::prerender() // TODO: is this even necessay? These are probably set to never discard LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(1024.f*1024.f); LLViewerFetchedTexture::sWhiteImagep->addTextureStats(1024.f * 1024.f); - - if (LLPipeline::sRenderPBR) - { - gPipeline.setupHWLights(NULL); - } } S32 LLDrawPoolAlpha::getNumPostDeferredPasses() @@ -200,10 +195,6 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField") && !gCubeSnapshot) { //update depth buffer sampler - /*gPipeline.mRT->screen.flush(); - gPipeline.mRT->deferredDepth.copyContents(gPipeline.mRT->deferredScreen, 0, 0, gPipeline.mRT->deferredScreen.getWidth(), gPipeline.mRT->deferredScreen.getHeight(), - 0, 0, gPipeline.mRT->deferredDepth.getWidth(), gPipeline.mRT->deferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); - gPipeline.mRT->deferredDepth.bindTarget();*/ simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram; simple_shader->bind(); @@ -217,8 +208,6 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, true); // <--- discard mostly transparent faces - //gPipeline.mRT->deferredDepth.flush(); - //gPipeline.mRT->screen.bindTarget(); gGL.setColorMask(true, false); } @@ -723,12 +712,11 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) LLRenderPass::applyModelMatrix(params); LLMaterial* mat = NULL; - LLGLTFMaterial *gltf_mat = params.mGLTFMaterial; // Also see: LLPipeline::getPoolTypeFromTE() - bool is_pbr = LLPipeline::sRenderPBR && gltf_mat; + LLGLTFMaterial *gltf_mat = params.mGLTFMaterial; - LLGLDisable cull_face(is_pbr && gltf_mat->mDoubleSided ? GL_CULL_FACE : 0); + LLGLDisable cull_face(gltf_mat && gltf_mat->mDoubleSided ? GL_CULL_FACE : 0); - if (is_pbr && gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) + if (gltf_mat && gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) { target_shader = &gDeferredPBRAlphaProgram; if (params.mAvatar != nullptr) diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 8e65bb56f8..7fa95d0947 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -689,7 +689,7 @@ void LLDrawPoolBump::renderBump(U32 pass) //static void LLDrawPoolBump::endBump(U32 pass) { - gObjectBumpProgram.unbind(); + LLGLSLShader::unbind(); gGL.setSceneBlendType(LLRender::BT_ALPHA); } diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index 3a659e0efc..7a8b2b4b35 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -358,7 +358,7 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass) else { gGL.flush(); - LLGLSLShader::bindNoShader(); + LLGLSLShader::unbind(); } } diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index cee1b91ae2..4de6667a5c 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -50,8 +50,6 @@ #include "llsettingssky.h" #include "llsettingswater.h" -BOOL deferred_render = FALSE; - BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE; BOOL LLDrawPoolWater::sNeedsReflectionUpdate = TRUE; BOOL LLDrawPoolWater::sNeedsDistortionUpdate = TRUE; @@ -114,21 +112,26 @@ S32 LLDrawPoolWater::getNumPostDeferredPasses() void LLDrawPoolWater::beginPostDeferredPass(S32 pass) { LL_PROFILE_GPU_ZONE("water beginPostDeferredPass") + gGL.setColorMask(true, true); + if (LLPipeline::sRenderTransparentWater && !gCubeSnapshot) { // copy framebuffer contents so far to a texture to be used for // reflections and refractions + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + LLRenderTarget& src = gPipeline.mRT->screen; + LLRenderTarget& depth_src = gPipeline.mRT->deferredScreen; LLRenderTarget& dst = gPipeline.mWaterDis; dst.bindTarget(); gCopyDepthProgram.bind(); - S32 diff_map = gCopyDepthProgram.enableTexture(LLShaderMgr::DIFFUSE_MAP); - S32 depth_map = gCopyDepthProgram.enableTexture(LLShaderMgr::DEFERRED_DEPTH); + S32 diff_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DIFFUSE_MAP); + S32 depth_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DEFERRED_DEPTH); gGL.getTexUnit(diff_map)->bind(&src); - gGL.getTexUnit(depth_map)->bind(&src, true); + gGL.getTexUnit(depth_map)->bind(&depth_src, true); gPipeline.mScreenTriangleVB->setBuffer(); gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); @@ -140,12 +143,9 @@ void LLDrawPoolWater::beginPostDeferredPass(S32 pass) void LLDrawPoolWater::renderPostDeferred(S32 pass) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - if (!deferred_render) - { - gGL.setColorMask(true, true); - } - LLGLDisable blend(GL_BLEND); + + gGL.setColorMask(true, true); LLColor3 light_diffuse(0, 0, 0); F32 light_exp = 0.0f; @@ -194,195 +194,174 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) LLGLSLShader *shader = nullptr; // two passes, first with standard water shader bound, second with edge water shader bound - for( int edge = 0 ; edge < 2; edge++ ) + for (int edge = 0; edge < 2; edge++) { // select shader if (underwater) { - shader = deferred_render ? &gDeferredUnderWaterProgram : &gUnderWaterProgram; + shader = &gUnderWaterProgram; } else { - if (edge && !deferred_render) + if (edge) { shader = &gWaterEdgeProgram; } else { - shader = deferred_render ? &gDeferredWaterProgram : &gWaterProgram; + shader = &gWaterProgram; } } gPipeline.bindDeferredShader(*shader); - - // bind textures for water rendering - S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX); - if (reftex > -1) - { - gGL.getTexUnit(reftex)->activate(); - gGL.getTexUnit(reftex)->bind(&gPipeline.mWaterRef); - gGL.getTexUnit(0)->activate(); - } - //bind normal map - S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP); - S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2); + //bind normal map + S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP); + S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2); - LLViewerTexture* tex_a = mWaterNormp[0]; - LLViewerTexture* tex_b = mWaterNormp[1]; + LLViewerTexture* tex_a = mWaterNormp[0]; + LLViewerTexture* tex_b = mWaterNormp[1]; F32 blend_factor = pwater->getBlendFactor(); - - gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); - if (tex_a && (!tex_b || (tex_a == tex_b))) - { - gGL.getTexUnit(bumpTex)->bind(tex_a); - blend_factor = 0; // only one tex provided, no blending - } - else if (tex_b && !tex_a) - { - gGL.getTexUnit(bumpTex)->bind(tex_b); - blend_factor = 0; // only one tex provided, no blending - } - else if (tex_b != tex_a) - { - gGL.getTexUnit(bumpTex)->bind(tex_a); - gGL.getTexUnit(bumpTex2)->bind(tex_b); - } - - // bind reflection texture from RenderTarget - S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX); - S32 screenDepth = shader->enableTexture(LLShaderMgr::WATER_SCREENDEPTH); + gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); - F32 screenRes[] = {1.f / gGLViewport[2], 1.f / gGLViewport[3]}; - - S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP); - - // set uniforms for shader - if (deferred_render) + if (tex_a && (!tex_b || (tex_a == tex_b))) { - if (shader->getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0) - { - glh::matrix4f norm_mat = get_current_modelview().inverse().transpose(); - shader->uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m); - } + gGL.getTexUnit(bumpTex)->bind(tex_a); + blend_factor = 0; // only one tex provided, no blending + } + else if (tex_b && !tex_a) + { + gGL.getTexUnit(bumpTex)->bind(tex_b); + blend_factor = 0; // only one tex provided, no blending + } + else if (tex_b != tex_a) + { + gGL.getTexUnit(bumpTex)->bind(tex_a); + gGL.getTexUnit(bumpTex2)->bind(tex_b); } - shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes); - shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + // bind reflection texture from RenderTarget + S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX); + S32 screenDepth = shader->enableTexture(LLShaderMgr::WATER_SCREENDEPTH); - F32 fog_density = pwater->getModifiedWaterFogDensity(underwater); + F32 screenRes[] = { 1.f / gGLViewport[2], 1.f / gGLViewport[3] }; + + S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP); + + shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes); + shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + + F32 fog_density = pwater->getModifiedWaterFogDensity(underwater); + + if (screentex > -1) + { + shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density); + gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis); + } - if (screentex > -1) - { - shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density); - gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis); - } - if (screenDepth > -1) { gGL.getTexUnit(screenDepth)->bind(&gPipeline.mWaterDis, true); } - if (mShaderLevel == 1) - { - fog_color.mV[VW] = log(fog_density) / log(2); - } + if (mShaderLevel == 1) + { + fog_color.mV[VW] = log(fog_density) / log(2); + } - F32 water_height = environment.getWaterHeight(); + F32 water_height = environment.getWaterHeight(); F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2]; shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height); shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time); shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV); shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV); - shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV); + shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV); shader->uniform3fv(LLShaderMgr::WATER_FOGCOLOR_LINEAR, 1, fog_color_linear.mV); - shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV); - shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp); + shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV); + shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp); - shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV); - shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV); + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV); + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV); - shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV); + shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV); - shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV); - shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale()); - shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset()); - shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier()); + shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV); + shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale()); + shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset()); + shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier()); - F32 sunAngle = llmax(0.f, light_dir.mV[1]); - F32 scaledAngle = 1.f - sunAngle; + F32 sunAngle = llmax(0.f, light_dir.mV[1]); + F32 scaledAngle = 1.f - sunAngle; shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0); - shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle); - shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle); - shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f*sunAngle); - shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0); + shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle); + shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle); + shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f * sunAngle); + shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0); - // SL-15861 This was changed from getRotatedLightNorm() as it was causing - // lightnorm in shaders\class1\windlight\atmosphericsFuncs.glsl in have inconsistent additive lighting for 180 degrees of the FOV. - LLVector4 rotated_light_direction = LLEnvironment::instance().getClampedLightNorm(); - shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV); + // SL-15861 This was changed from getRotatedLightNorm() as it was causing + // lightnorm in shaders\class1\windlight\atmosphericsFuncs.glsl in have inconsistent additive lighting for 180 degrees of the FOV. + LLVector4 rotated_light_direction = LLEnvironment::instance().getClampedLightNorm(); + shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV); - shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); + shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); - if (LLViewerCamera::getInstance()->cameraUnderWater()) - { - shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow()); - } - else - { - shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove()); - } + if (LLViewerCamera::getInstance()->cameraUnderWater()) + { + shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow()); + } + else + { + shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove()); + } - LLGLDisable cullface(GL_CULL_FACE); + LLGLDisable cullface(GL_CULL_FACE); - LLVOWater *water = nullptr; - for (LLFace *const &face : mDrawFace) + LLVOWater* water = nullptr; + for (LLFace* const& face : mDrawFace) { if (!face) continue; - water = static_cast(face->getViewerObject()); + water = static_cast(face->getViewerObject()); if (!water) continue; - gGL.getTexUnit(diffTex)->bind(face->getTexture()); + gGL.getTexUnit(diffTex)->bind(face->getTexture()); - if ((bool)edge == (bool) water->getIsEdgePatch()) - { - face->renderIndexed(); + if ((bool)edge == (bool)water->getIsEdgePatch()) + { + face->renderIndexed(); // Note non-void water being drawn, updates required if (!edge) // SL-16461 remove !LLPipeline::sUseOcclusion check - { - sNeedsReflectionUpdate = TRUE; - sNeedsDistortionUpdate = TRUE; + { + sNeedsReflectionUpdate = TRUE; + sNeedsDistortionUpdate = TRUE; } - } + } } - shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - shader->disableTexture(LLShaderMgr::WATER_SCREENTEX); - shader->disableTexture(LLShaderMgr::BUMP_MAP); - shader->disableTexture(LLShaderMgr::DIFFUSE_MAP); - shader->disableTexture(LLShaderMgr::WATER_REFTEX); - shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH); + shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + shader->disableTexture(LLShaderMgr::WATER_SCREENTEX); + shader->disableTexture(LLShaderMgr::BUMP_MAP); + shader->disableTexture(LLShaderMgr::DIFFUSE_MAP); + shader->disableTexture(LLShaderMgr::WATER_REFTEX); + shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH); // clean up gPipeline.unbindDeferredShader(*shader); gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); - } + } gGL.getTexUnit(0)->activate(); gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - if (!deferred_render) - { - gGL.setColorMask(true, false); - } + + gGL.setColorMask(true, false); } LLViewerTexture *LLDrawPoolWater::getDebugTexture() diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 700f810545..fc2dbb5bc4 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -195,7 +195,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances() gPipeline.mBake.clear(); } - LLGLSLShader::bindNoShader(); + LLGLSLShader::unbind(); LLVertexBuffer::unbind(); BOOL result = FALSE; diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 5cf76ce36f..dd3ed72fec 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -1754,28 +1754,31 @@ LLVector4 LLEnvironment::getRotatedLightNorm() const return toLightNorm(light_direction); } +extern BOOL gCubeSnapshot; + //------------------------------------------------------------------------- void LLEnvironment::update(const LLViewerCamera * cam) { LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; //LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE); //F32Seconds now(LLDate::now().secondsSinceEpoch()); - static LLFrameTimer timer; - - F32Seconds delta(timer.getElapsedTimeAndResetF32()); - + if (!gCubeSnapshot) { - DayInstance::ptr_t keeper = mCurrentEnvironment; - // make sure the current environment does not go away until applyTimeDelta is done. - mCurrentEnvironment->applyTimeDelta(delta); + static LLFrameTimer timer; + F32Seconds delta(timer.getElapsedTimeAndResetF32()); + + { + DayInstance::ptr_t keeper = mCurrentEnvironment; + // make sure the current environment does not go away until applyTimeDelta is done. + mCurrentEnvironment->applyTimeDelta(delta); + + } + // update clouds, sun, and general + updateCloudScroll(); + + // cache this for use in rotating the rotated light vec for shader param updates later... + mLastCamYaw = cam->getYaw() + SUN_DELTA_YAW; } - // update clouds, sun, and general - updateCloudScroll(); - - // cache this for use in rotating the rotated light vec for shader param updates later... - mLastCamYaw = cam->getYaw() + SUN_DELTA_YAW; - - stop_glerror(); updateSettingsUniforms(); @@ -1876,13 +1879,23 @@ void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, con { LLVector4 vect4(value); - switch (it.second.getShaderKey()) - { // convert to linear color space if this is a color parameter - case LLShaderMgr::BLUE_HORIZON: - case LLShaderMgr::BLUE_DENSITY: - //vect4 = LLVector4(linearColor4(LLColor4(vect4.mV)).mV); - break; + if (gCubeSnapshot && !gPipeline.mReflectionMapManager.isRadiancePass()) + { // maximize and remove tinting if this is an irradiance map render pass and the parameter feeds into the sky background color + auto max_vec = [](LLVector4 col) + { + col.mV[0] = col.mV[1] = col.mV[2] = llmax(llmax(col.mV[0], col.mV[1]), col.mV[2]); + return col; + }; + + switch (it.second.getShaderKey()) + { + case LLShaderMgr::BLUE_HORIZON: + case LLShaderMgr::BLUE_DENSITY: + vect4 = max_vec(vect4); + break; + } } + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << vect4 << LL_ENDL; shader->uniform3fv(it.second.getShaderKey(), LLVector3(vect4.mV) ); break; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 1ce9c585eb..5cb2c89172 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -492,7 +492,7 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t { //allocate render target for drawing charts LLRenderTarget buffer; - buffer.allocate(1024,512, GL_RGB, FALSE, FALSE); + buffer.allocate(1024,512, GL_RGB); LLSD cur; diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 6ab2efcd53..c73cd45ba1 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -661,6 +661,10 @@ void LLFeatureManager::applyBaseMasks() { maskFeatures("VRAMGT512"); } + if (gGLManager.mVRAM < 2048) + { + maskFeatures("VRAMLT2GB"); + } if (gGLManager.mGLVersion < 3.99f) { maskFeatures("GL3"); diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp index b095b74519..047f1a4965 100644 --- a/indra/newview/llfetchedgltfmaterial.cpp +++ b/indra/newview/llfetchedgltfmaterial.cpp @@ -115,3 +115,35 @@ void LLFetchedGLTFMaterial::bind() } } + +void LLFetchedGLTFMaterial::materialBegin() +{ + llassert(!mFetching); + mFetching = true; +} + +void LLFetchedGLTFMaterial::onMaterialComplete(std::function material_complete) +{ + if (!material_complete) { return; } + + if (!mFetching) + { + material_complete(); + return; + } + + materialCompleteCallbacks.push_back(material_complete); +} + +void LLFetchedGLTFMaterial::materialComplete() +{ + llassert(mFetching); + mFetching = false; + + for (std::function material_complete : materialCompleteCallbacks) + { + material_complete(); + } + materialCompleteCallbacks.clear(); + materialCompleteCallbacks.shrink_to_fit(); +} diff --git a/indra/newview/llfetchedgltfmaterial.h b/indra/newview/llfetchedgltfmaterial.h index 4f6c56012e..f784f19c4f 100644 --- a/indra/newview/llfetchedgltfmaterial.h +++ b/indra/newview/llfetchedgltfmaterial.h @@ -39,6 +39,9 @@ public: LLFetchedGLTFMaterial(); virtual ~LLFetchedGLTFMaterial(); + // If this material is loaded, fire the given function + void onMaterialComplete(std::function material_complete); + // bind this material for rendering void bind(); @@ -49,9 +52,14 @@ public: LLPointer mEmissiveTexture; protected: - //Lifetime management + // Lifetime management + + void materialBegin(); + void materialComplete(); + F64 mExpectedFlusTime; // since epoch in seconds bool mActive; bool mFetching; + std::vector> materialCompleteCallbacks; }; diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 6dcf478b88..2fbe7d17bf 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -905,6 +905,8 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance) { *(index_strider++) = vf.mIndices[i]; } + + mVertexBuffer->unmapBuffer(); } diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index f1f347ac99..8e90e8b384 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -2130,7 +2130,7 @@ void LLFloaterPreference::refreshEnabledState() sky->setEnabled(TRUE); //PBR - ctrl_pbr->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("RenderPBR")); + ctrl_pbr->setEnabled(TRUE); LLCheckBoxCtrl* ctrl_ssao = getChild("UseSSAO"); LLCheckBoxCtrl* ctrl_dof = getChild("UseDoF"); diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index eaf298b51e..3ac21f2f2c 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -1200,7 +1200,7 @@ F32 gpu_benchmark() for (U32 i = 0; i < count; ++i) { //allocate render targets and textures - if (!dest[i].allocate(res, res, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true)) + if (!dest[i].allocate(res, res, GL_RGBA)) { LL_WARNS("Benchmark") << "Failed to allocate render target." << LL_ENDL; // abandon the benchmark test diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index 9399342a61..bc094ac838 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -392,15 +392,18 @@ void LLGLTFMaterialList::applyQueuedOverrides(LLViewerObject* obj) } } -void LLGLTFMaterialList::queueModify(const LLUUID& id, S32 side, const LLGLTFMaterial* mat) +void LLGLTFMaterialList::queueModify(const LLViewerObject* obj, S32 side, const LLGLTFMaterial* mat) { - if (mat == nullptr) + if (obj && obj->getRenderMaterialID(side).notNull()) { - sModifyQueue.push_back({ id, side, LLGLTFMaterial(), false }); - } - else - { - sModifyQueue.push_back({ id, side, *mat, true}); + if (mat == nullptr) + { + sModifyQueue.push_back({ obj->getID(), side, LLGLTFMaterial(), false }); + } + else + { + sModifyQueue.push_back({ obj->getID(), side, *mat, true }); + } } } @@ -437,8 +440,14 @@ void LLGLTFMaterialList::flushUpdates(void(*done_callback)(bool)) S32 i = data.size(); - for (auto& e : sModifyQueue) + for (ModifyMaterialData& e : sModifyQueue) { +#ifdef SHOW_ASSERT + // validate object has a material id + LLViewerObject* obj = gObjectList.findObject(e.object_id); + llassert(obj && obj->getRenderMaterialID(e.side).notNull()); +#endif + data[i]["object_id"] = e.object_id; data[i]["side"] = e.side; @@ -516,7 +525,7 @@ void LLGLTFMaterialList::onAssetLoadComplete(const LLUUID& id, LLAssetType::ETyp if (status != LL_ERR_NOERR) { LL_WARNS("GLTF") << "Error getting material asset data: " << LLAssetStorage::getErrorString(status) << " (" << status << ")" << LL_ENDL; - asset_data->mMaterial->mFetching = false; + asset_data->mMaterial->materialComplete(); delete asset_data; } else @@ -602,13 +611,15 @@ void LLGLTFMaterialList::onAssetLoadComplete(const LLUUID& id, LLAssetType::ETyp { LL_DEBUGS("GLTF") << "Failed to get material " << id << LL_ENDL; } - asset_data->mMaterial->mFetching = false; + + asset_data->mMaterial->materialComplete(); + delete asset_data; }); } } -LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id) +LLFetchedGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id) { LL_PROFILE_ZONE_SCOPED; uuid_mat_map_t::iterator iter = mList.find(id); @@ -620,7 +631,7 @@ LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id) if (!mat->mFetching) { - mat->mFetching = true; + mat->materialBegin(); AssetLoadUserData *user_data = new AssetLoadUserData(); user_data->mMaterial = mat; diff --git a/indra/newview/llgltfmateriallist.h b/indra/newview/llgltfmateriallist.h index 70540e5e01..85e60aa17f 100644 --- a/indra/newview/llgltfmateriallist.h +++ b/indra/newview/llgltfmateriallist.h @@ -45,7 +45,7 @@ public: LLGLTFMaterialList() {} - LLGLTFMaterial* getMaterial(const LLUUID& id); + LLFetchedGLTFMaterial* getMaterial(const LLUUID& id); void addMaterial(const LLUUID& id, LLFetchedGLTFMaterial* material); void removeMaterial(const LLUUID& id); @@ -60,7 +60,7 @@ public: // mat - material to apply as override, or nullptr to remove existing overrides and revert to asset // // NOTE: do not use to revert to asset when applying a new asset id, use queueApply below - static void queueModify(const LLUUID& id, S32 side, const LLGLTFMaterial* mat); + static void queueModify(const LLViewerObject* obj, S32 side, const LLGLTFMaterial* mat); // Queue an application of a material asset we want to send to the simulator. Call "flushUpdates" to flush pending updates. // object_id - ID of object to apply material asset to diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 8dc3a7094d..4664af1943 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -271,11 +271,7 @@ void LLManipTranslate::restoreGL() } } } -#ifdef LL_WINDOWS LLImageGL::setManualImage(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, GL_RGBA, GL_UNSIGNED_BYTE, d); -#else - LLImageGL::setManualImage(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, d); -#endif rez = rez >> 1; mip++; } diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 9efe5dc1f1..5628327ebe 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -2156,6 +2156,8 @@ void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std:: { openFloater(getKey()); setFocus(TRUE); + setCanSave(true); + setCanSaveAs(true); applyToSelection(); } @@ -2673,7 +2675,7 @@ public: { mSuccess = true; } - LLGLTFMaterialList::queueModify(objectp->getID(), te, material); + LLGLTFMaterialList::queueModify(objectp, te, material); } return true; } diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 181d43c116..1a01d7b846 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -152,7 +152,7 @@ void LLPanelFace::updateSelectedGLTFMaterials(std::functiongetGLTFMaterialOverride(); } mFunc(&new_override); - LLGLTFMaterialList::queueModify(object->getID(), face, &new_override); + LLGLTFMaterialList::queueModify(object, face, &new_override); return true; } diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 66396824a0..fa195a9cd3 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -39,6 +39,18 @@ extern BOOL gCubeSnapshot; extern BOOL gTeleportDisplay; +// get the next highest power of two of v (or v if v is already a power of two) +//defined in llvertexbuffer.cpp +extern U32 nhpo2(U32 v); + +static void touch_default_probe(LLReflectionMap* probe) +{ + LLVector3 origin = LLViewerCamera::getInstance()->getOrigin(); + origin.mV[2] += 64.f; + + probe->mOrigin.load3(origin.mV); +} + LLReflectionMapManager::LLReflectionMapManager() { initCubeFree(); @@ -83,21 +95,19 @@ void LLReflectionMapManager::update() if (!mRenderTarget.isComplete()) { U32 color_fmt = GL_RGB16F; - const bool use_depth_buffer = true; - const bool use_stencil_buffer = false; - U32 targetRes = LL_REFLECTION_PROBE_RESOLUTION * 2; // super sample - mRenderTarget.allocate(targetRes, targetRes, color_fmt, use_depth_buffer, use_stencil_buffer, LLTexUnit::TT_TEXTURE); + U32 targetRes = mProbeResolution * 2; // super sample + mRenderTarget.allocate(targetRes, targetRes, color_fmt, true); } if (mMipChain.empty()) { - U32 res = LL_REFLECTION_PROBE_RESOLUTION; + U32 res = mProbeResolution; U32 count = log2((F32)res) + 0.5f; mMipChain.resize(count); for (int i = 0; i < count; ++i) { - mMipChain[i].allocate(res, res, GL_RGBA16F, false, false, LLTexUnit::TT_TEXTURE); + mMipChain[i].allocate(res, res, GL_RGBA16F); res /= 2; } } @@ -108,9 +118,8 @@ void LLReflectionMapManager::update() 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); } - - mDefaultProbe->mOrigin.load3(LLViewerCamera::getInstance()->getOrigin().mV); LLVector4a camera_pos; camera_pos.load3(LLViewerCamera::instance().getOrigin().mV); @@ -155,6 +164,8 @@ void LLReflectionMapManager::update() doProbeUpdate(); } + //LL_INFOS() << mProbes.size() << LL_ENDL; + for (int i = 0; i < mProbes.size(); ++i) { LLReflectionMap* probe = mProbes[i]; @@ -394,32 +405,67 @@ void LLReflectionMapManager::doProbeUpdate() if (++mUpdatingFace == 6) { updateNeighbors(mUpdatingProbe); - mUpdatingProbe = nullptr; mUpdatingFace = 0; + if (isRadiancePass()) + { + mUpdatingProbe = nullptr; + mRadiancePass = false; + } + else + { + mRadiancePass = true; + } } } +// Do the reflection map update render passes. +// For every 12 calls of this function, one complete reflection probe radiance map and irradiance map is generated +// First six passes render the scene with direct lighting only into a scratch space cube map at the end of the cube map array and generate +// a simple mip chain (not convolution filter). +// At the end of these passes, an irradiance map is generated for this probe and placed into the irradiance cube map array at the index for this probe +// The next six passes render the scene with both radiance and irradiance into the same scratch space cube map and generate a simple mip chain. +// At the end of these passes, a radiance map is generated for this probe and placed into the radiance cube map array at the index for this probe. +// In effect this simulates single-bounce lighting. void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) { // hacky hot-swap of camera specific render targets gPipeline.mRT = &gPipeline.mAuxillaryRT; - probe->update(mRenderTarget.getWidth(), face); + + if (probe == mDefaultProbe) + { + touch_default_probe(probe); + + gPipeline.pushRenderTypeMask(); + + //only render sky, water, terrain, and clouds + gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::END_RENDER_TYPES); + + probe->update(mRenderTarget.getWidth(), face); + + gPipeline.popRenderTypeMask(); + } + else + { + probe->update(mRenderTarget.getWidth(), face); + } + gPipeline.mRT = &gPipeline.mMainRT; - S32 targetIdx = mReflectionProbeCount; + S32 sourceIdx = mReflectionProbeCount; if (probe != mUpdatingProbe) { // this is the "realtime" probe that's updating every frame, use the secondary scratch space channel - targetIdx += 1; + sourceIdx += 1; } gGL.setColorMask(true, true); + LLGLDepthTest depth(GL_FALSE, GL_FALSE); + LLGLDisable cull(GL_CULL_FACE); + LLGLDisable blend(GL_BLEND); // downsample to placeholder map { - LLGLDepthTest depth(GL_FALSE, GL_FALSE); - LLGLDisable cull(GL_CULL_FACE); - gReflectionMipProgram.bind(); gGL.matrixMode(gGL.MM_MODELVIEW); @@ -431,9 +477,9 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) gGL.loadIdentity(); gGL.flush(); - U32 res = LL_REFLECTION_PROBE_RESOLUTION * 2; + U32 res = mProbeResolution * 2; - S32 mips = log2((F32)LL_REFLECTION_PROBE_RESOLUTION) + 0.5f; + S32 mips = log2((F32)mProbeResolution) + 0.5f; S32 diffuseChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_TEXTURE); S32 depthChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_TEXTURE); @@ -508,7 +554,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) LL_PROFILE_GPU_ZONE("probe mip copy"); mTexture->bind(0); //glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res); - glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, targetIdx * 6 + face, 0, 0, res, res); + glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, sourceIdx * 6 + face, 0, 0, res, res); //if (i == 0) //{ //glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res); @@ -529,89 +575,102 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) if (face == 5) { - //generate radiance map - gRadianceGenProgram.bind(); - mVertexBuffer->setBuffer(); - - S32 channel = gRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); - mTexture->bind(channel); - static LLStaticHashedString sSourceIdx("sourceIdx"); - gRadianceGenProgram.uniform1i(sSourceIdx, targetIdx); - mMipChain[0].bindTarget(); - U32 res = mMipChain[0].getWidth(); + static LLStaticHashedString sSourceIdx("sourceIdx"); - for (int i = 0; i < mMipChain.size(); ++i) + if (isRadiancePass()) { - LL_PROFILE_GPU_ZONE("probe radiance gen"); - static LLStaticHashedString sMipLevel("mipLevel"); - static LLStaticHashedString sRoughness("roughness"); - static LLStaticHashedString sWidth("u_width"); + //generate radiance map (even if this is not the irradiance map, we need the mip chain for the irradiance map) + gRadianceGenProgram.bind(); + mVertexBuffer->setBuffer(); - gRadianceGenProgram.uniform1f(sRoughness, (F32)i / (F32)(mMipChain.size() - 1)); - gRadianceGenProgram.uniform1f(sMipLevel, i); - gRadianceGenProgram.uniform1i(sWidth, mMipChain[i].getWidth()); + S32 channel = gRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); + mTexture->bind(channel); + gRadianceGenProgram.uniform1i(sSourceIdx, sourceIdx); + gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD); - for (int cf = 0; cf < 6; ++cf) - { // for each cube face - LLCoordFrame frame; - frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]); + U32 res = mMipChain[0].getWidth(); - F32 mat[16]; - frame.getOpenGLRotation(mat); - gGL.loadMatrix(mat); - - mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4); - - glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res); - } - - if (i != mMipChain.size() - 1) + for (int i = 0; i < mMipChain.size(); ++i) { - res /= 2; - glViewport(0, 0, res, res); + LL_PROFILE_GPU_ZONE("probe radiance gen"); + static LLStaticHashedString sMipLevel("mipLevel"); + static LLStaticHashedString sRoughness("roughness"); + static LLStaticHashedString sWidth("u_width"); + + gRadianceGenProgram.uniform1f(sRoughness, (F32)i / (F32)(mMipChain.size() - 1)); + gRadianceGenProgram.uniform1f(sMipLevel, i); + gRadianceGenProgram.uniform1i(sWidth, mMipChain[i].getWidth()); + + for (int cf = 0; cf < 6; ++cf) + { // for each cube face + LLCoordFrame frame; + frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]); + + F32 mat[16]; + frame.getOpenGLRotation(mat); + gGL.loadMatrix(mat); + + mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4); + + glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res); + } + + if (i != mMipChain.size() - 1) + { + res /= 2; + glViewport(0, 0, res, res); + } } + + gRadianceGenProgram.unbind(); } - - gRadianceGenProgram.unbind(); - - //generate irradiance map - gIrradianceGenProgram.bind(); - channel = gIrradianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); - mTexture->bind(channel); - - gIrradianceGenProgram.uniform1i(sSourceIdx, targetIdx); - mVertexBuffer->setBuffer(); - int start_mip = 0; - // find the mip target to start with based on irradiance map resolution - for (start_mip = 0; start_mip < mMipChain.size(); ++start_mip) + else { - if (mMipChain[start_mip].getWidth() == LL_IRRADIANCE_MAP_RESOLUTION) + //generate irradiance map + gIrradianceGenProgram.bind(); + S32 channel = gIrradianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); + mTexture->bind(channel); + + static LLCachedControl ambiance_scale(gSavedSettings, "RenderReflectionProbeAmbianceScale", 8.f); + static LLStaticHashedString ambiance_scale_str("ambiance_scale"); + + gIrradianceGenProgram.uniform1f(ambiance_scale_str, ambiance_scale); + gIrradianceGenProgram.uniform1i(sSourceIdx, sourceIdx); + gIrradianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD); + + mVertexBuffer->setBuffer(); + int start_mip = 0; + // find the mip target to start with based on irradiance map resolution + for (start_mip = 0; start_mip < mMipChain.size(); ++start_mip) { - break; + if (mMipChain[start_mip].getWidth() == LL_IRRADIANCE_MAP_RESOLUTION) + { + break; + } } - } - //for (int i = start_mip; i < mMipChain.size(); ++i) - { - int i = start_mip; - LL_PROFILE_GPU_ZONE("probe irradiance gen"); - glViewport(0, 0, mMipChain[i].getWidth(), mMipChain[i].getHeight()); - for (int cf = 0; cf < 6; ++cf) - { // for each cube face - LLCoordFrame frame; - frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]); + //for (int i = start_mip; i < mMipChain.size(); ++i) + { + int i = start_mip; + LL_PROFILE_GPU_ZONE("probe irradiance gen"); + glViewport(0, 0, mMipChain[i].getWidth(), mMipChain[i].getHeight()); + for (int cf = 0; cf < 6; ++cf) + { // for each cube face + LLCoordFrame frame; + frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]); - F32 mat[16]; - frame.getOpenGLRotation(mat); - gGL.loadMatrix(mat); + F32 mat[16]; + frame.getOpenGLRotation(mat); + gGL.loadMatrix(mat); - mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4); + mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4); - S32 res = mMipChain[i].getWidth(); - mIrradianceMaps->bind(channel); - glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i - start_mip, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res); - mTexture->bind(channel); + S32 res = mMipChain[i].getWidth(); + mIrradianceMaps->bind(channel); + glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i - start_mip, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res); + mTexture->bind(channel); + } } } @@ -689,12 +748,28 @@ void LLReflectionMapManager::updateUniforms() // see class3/deferred/reflectionProbeF.glsl struct ReflectionProbeData { - LLMatrix4 refBox[LL_MAX_REFLECTION_PROBE_COUNT]; // object bounding box as needed - LLVector4 refSphere[LL_MAX_REFLECTION_PROBE_COUNT]; //origin and radius of refmaps in clip space - LLVector4 refParams[LL_MAX_REFLECTION_PROBE_COUNT]; //extra parameters (currently only ambiance) - GLint refIndex[LL_MAX_REFLECTION_PROBE_COUNT][4]; - GLint refNeighbor[4096]; - GLint refmapCount; + // for box probes, matrix that transforms from camera space to a [-1, 1] cube representing the bounding box of + // the box probe + LLMatrix4 refBox[LL_MAX_REFLECTION_PROBE_COUNT]; + + // for sphere probes, origin (xyz) and radius (w) of refmaps in clip space + LLVector4 refSphere[LL_MAX_REFLECTION_PROBE_COUNT]; + + // extra parameters (currently only ambiance in .x) + LLVector4 refParams[LL_MAX_REFLECTION_PROBE_COUNT]; + + // indices used by probe: + // [i][0] - cubemap array index for this probe + // [i][1] - index into "refNeighbor" for probes that intersect this probe + // [i][2] - number of probes that intersect this probe, or -1 for no neighbors + // [i][3] - priority (probe type stored in sign bit - positive for spheres, negative for boxes) + GLint refIndex[LL_MAX_REFLECTION_PROBE_COUNT][4]; + + // list of neighbor indices + GLint refNeighbor[4096]; + + // numbrer of active refmaps + GLint refmapCount; }; mReflectionMaps.resize(mReflectionProbeCount); @@ -714,7 +789,8 @@ void LLReflectionMapManager::updateUniforms() LLSettingsSky::ptr_t psky = environment.getCurrentSky(); F32 minimum_ambiance = psky->getTotalReflectionProbeAmbiance(); - F32 ambscale = gCubeSnapshot ? 0.5f : 1.f; + F32 ambscale = gCubeSnapshot && !isRadiancePass() ? 0.f : 1.f; + for (auto* refmap : mReflectionMaps) { @@ -904,12 +980,14 @@ void LLReflectionMapManager::initReflectionMaps() { if (mTexture.isNull()) { + mProbeResolution = nhpo2(llclamp(gSavedSettings.getU32("RenderReflectionProbeResolution"), (U32)64, (U32)512)); + mMaxProbeLOD = log2f(mProbeResolution) - 1.f; // number of mips - 1 mReflectionProbeCount = llclamp(gSavedSettings.getS32("RenderReflectionProbeCount"), 1, LL_MAX_REFLECTION_PROBE_COUNT); mTexture = new LLCubeMapArray(); // store mReflectionProbeCount+2 cube maps, final two cube maps are used for render target and radiance map generation source) - mTexture->allocate(LL_REFLECTION_PROBE_RESOLUTION, 4, mReflectionProbeCount + 2); + mTexture->allocate(mProbeResolution, 4, mReflectionProbeCount + 2); mIrradianceMaps = new LLCubeMapArray(); mIrradianceMaps->allocate(LL_IRRADIANCE_MAP_RESOLUTION, 4, mReflectionProbeCount, FALSE); diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h index 14a6c089da..5936b26b88 100644 --- a/indra/newview/llreflectionmapmanager.h +++ b/indra/newview/llreflectionmapmanager.h @@ -38,7 +38,6 @@ class LLViewerObject; #define LL_MAX_REFLECTION_PROBE_COUNT 256 // reflection probe resolution -#define LL_REFLECTION_PROBE_RESOLUTION 128 #define LL_IRRADIANCE_MAP_RESOLUTION 64 // reflection probe mininum scale @@ -94,6 +93,9 @@ public: // call once at startup to allocate cubemap arrays void initReflectionMaps(); + // True if currently updating a radiance map, false if currently updating an irradiance map + bool isRadiancePass() { return mRadiancePass; } + private: friend class LLPipeline; @@ -161,9 +163,21 @@ private: LLReflectionMap* mUpdatingProbe = nullptr; U32 mUpdatingFace = 0; + // if true, we're generating the radiance map for the current probe, otherwise we're generating the irradiance map. + // Update sequence should be to generate the irradiance map from render of the world that has no irradiance, + // then generate the radiance map from a render of the world that includes irradiance. + // This should avoid feedback loops and ensure that the colors in the radiance maps match the colors in the environment. + bool mRadiancePass = false; + LLPointer mDefaultProbe; // default reflection probe to fall back to for pixels with no probe influences (should always be at cube index 0) // number of reflection probes to use for rendering (based on saved setting RenderReflectionProbeCount) U32 mReflectionProbeCount; + + // resolution of reflection probes + U32 mProbeResolution = 128; + + // maximum LoD of reflection probes (mip levels - 1) + F32 mMaxProbeLOD = 6.f; }; diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp index 927140a8ae..2cc2b21c22 100644 --- a/indra/newview/llscenemonitor.cpp +++ b/indra/newview/llscenemonitor.cpp @@ -177,7 +177,7 @@ LLRenderTarget& LLSceneMonitor::getCaptureTarget() if(!mFrames[0]) { mFrames[0] = new LLRenderTarget(); - mFrames[0]->allocate(width, height, GL_RGB, false, false, LLTexUnit::TT_TEXTURE, true); + mFrames[0]->allocate(width, height, GL_RGB); gGL.getTexUnit(0)->bind(mFrames[0]); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -187,7 +187,7 @@ LLRenderTarget& LLSceneMonitor::getCaptureTarget() else if(!mFrames[1]) { mFrames[1] = new LLRenderTarget(); - mFrames[1]->allocate(width, height, GL_RGB, false, false, LLTexUnit::TT_TEXTURE, true); + mFrames[1]->allocate(width, height, GL_RGB); gGL.getTexUnit(0)->bind(mFrames[1]); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -360,7 +360,7 @@ void LLSceneMonitor::compare() if(!mDiff) { mDiff = new LLRenderTarget(); - mDiff->allocate(width, height, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true); + mDiff->allocate(width, height, GL_RGBA); generateDitheringTexture(width, height); } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 399b4a1dc0..59cae80ed9 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -2305,7 +2305,7 @@ void LLSelectMgr::selectionRevertGLTFMaterials() && asset_id.notNull()) { // Restore overrides - LLGLTFMaterialList::queueModify(objectp->getID(), te, nodep->mSavedGLTFOverrideMaterials[te]); + LLGLTFMaterialList::queueModify(objectp, te, nodep->mSavedGLTFOverrideMaterials[te]); } else { diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 870ac6bd5a..fd27c83270 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -68,6 +68,8 @@ #undef VERIFY_LEGACY_CONVERSION +extern BOOL gCubeSnapshot; + //========================================================================= namespace { @@ -673,6 +675,8 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force) LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; LLVector3 light_direction = LLVector3(LLEnvironment::instance().getClampedLightNorm().mV); + bool radiance_pass = gCubeSnapshot && !gPipeline.mReflectionMapManager.isRadiancePass(); + LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_DEFAULT]; { shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, light_direction); @@ -680,43 +684,54 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force) } shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_SKY]; - { - shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, light_direction); - // Legacy? SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate") - LLVector4 vect_c_p_d1(mSettings[SETTING_CLOUD_POS_DENSITY1]); - LLVector4 cloud_scroll( LLEnvironment::instance().getCloudScrollDelta() ); + shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, light_direction); - // SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll - // Keep in Sync! - // * indra\newview\llsettingsvo.cpp - // * indra\newview\app_settings\shaders\class2\windlight\cloudsV.glsl - // * indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl - cloud_scroll[0] = -cloud_scroll[0]; - vect_c_p_d1 += cloud_scroll; - shader->uniform3fv(LLShaderMgr::CLOUD_POS_DENSITY1, LLVector3(vect_c_p_d1.mV)); + // Legacy? SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate") + LLVector4 vect_c_p_d1(mSettings[SETTING_CLOUD_POS_DENSITY1]); + LLVector4 cloud_scroll( LLEnvironment::instance().getCloudScrollDelta() ); - LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + // SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll + // Keep in Sync! + // * indra\newview\llsettingsvo.cpp + // * indra\newview\app_settings\shaders\class2\windlight\cloudsV.glsl + // * indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl + cloud_scroll[0] = -cloud_scroll[0]; + vect_c_p_d1 += cloud_scroll; + shader->uniform3fv(LLShaderMgr::CLOUD_POS_DENSITY1, LLVector3(vect_c_p_d1.mV)); - // TODO -- make these getters return vec3s - LLVector3 sunDiffuse = LLVector3(psky->getSunlightColor().mV); - LLVector3 moonDiffuse = LLVector3(psky->getMoonlightColor().mV); + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sunDiffuse); - shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, moonDiffuse); + // TODO -- make these getters return vec3s + LLVector3 sunDiffuse = LLVector3(psky->getSunlightColor().mV); + LLVector3 moonDiffuse = LLVector3(psky->getMoonlightColor().mV); + + shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sunDiffuse); + shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, moonDiffuse); + + shader->uniform3fv(LLShaderMgr::CLOUD_COLOR, LLVector3(psky->getCloudColor().mV)); - shader->uniform3fv(LLShaderMgr::CLOUD_COLOR, LLVector3(psky->getCloudColor().mV)); - } - shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_ANY]; shader->uniform1f(LLShaderMgr::SCENE_LIGHT_STRENGTH, mSceneLightStrength); LLColor3 ambient(getTotalAmbient()); shader->uniform3fv(LLShaderMgr::AMBIENT, LLVector3(ambient.mV)); - shader->uniform3fv(LLShaderMgr::AMBIENT_LINEAR, linearColor3v(getAmbientColor()/3.f)); // note magic number 3.f comes from SLIDER_SCALE_SUN_AMBIENT - shader->uniform3fv(LLShaderMgr::SUNLIGHT_LINEAR, linearColor3v(getSunlightColor())); - shader->uniform3fv(LLShaderMgr::MOONLIGHT_LINEAR,linearColor3v(getMoonlightColor())); + + if (radiance_pass) + { // during an irradiance map update, disable ambient lighting (direct lighting only) and desaturate sky color (avoid tinting the world blue) + shader->uniform3fv(LLShaderMgr::AMBIENT_LINEAR, LLVector3::zero.mV); + } + else + { + shader->uniform3fv(LLShaderMgr::AMBIENT_LINEAR, linearColor3v(getAmbientColor() / 3.f)); // note magic number 3.f comes from SLIDER_SCALE_SUN_AMBIENT + } + + shader->uniform3fv(LLShaderMgr::BLUE_HORIZON_LINEAR, linearColor3v(getBlueHorizon() / 2.f)); // note magic number of 2.f comes from SLIDER_SCALE_BLUE_HORIZON_DENSITY + shader->uniform3fv(LLShaderMgr::BLUE_DENSITY_LINEAR, linearColor3v(getBlueDensity() / 2.f)); + + shader->uniform3fv(LLShaderMgr::SUNLIGHT_LINEAR, linearColor3v(sunDiffuse)); + shader->uniform3fv(LLShaderMgr::MOONLIGHT_LINEAR,linearColor3v(moonDiffuse)); shader->uniform1f(LLShaderMgr::REFLECTION_PROBE_AMBIANCE, getTotalReflectionProbeAmbiance()); @@ -724,16 +739,14 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force) shader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, getSunMoonGlowFactor()); shader->uniform1f(LLShaderMgr::DENSITY_MULTIPLIER, getDensityMultiplier()); shader->uniform1f(LLShaderMgr::DISTANCE_MULTIPLIER, getDistanceMultiplier()); - + + shader->uniform1f(LLShaderMgr::HAZE_DENSITY_LINEAR, sRGBtoLinear(getHazeDensity())); + F32 g = getGamma(); F32 display_gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); shader->uniform1f(LLShaderMgr::GAMMA, g); shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, display_gamma); - - shader->uniform3fv(LLShaderMgr::BLUE_HORIZON_LINEAR, linearColor3v(getBlueHorizon()/2.f)); // note magic number of 2.f comes from SLIDER_SCALE_BLUE_HORIZON_DENSITY - shader->uniform3fv(LLShaderMgr::BLUE_DENSITY_LINEAR, linearColor3v(getBlueDensity()/2.f)); - shader->uniform1f(LLShaderMgr::HAZE_DENSITY_LINEAR, sRGBtoLinear(getHazeDensity())); } LLSettingsSky::parammapping_t LLSettingsVOSky::getParameterMap() const diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index c801a8d903..57a815a804 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -245,7 +245,6 @@ bool handleSetShaderChanged(const LLSD& newvalue) // ALM depends onto atmospheric shaders, state might have changed bool old_state = LLPipeline::sRenderDeferred; LLPipeline::refreshCachedSettings(); - gPipeline.updateRenderDeferred(); if (old_state != LLPipeline::sRenderDeferred) { gPipeline.releaseGLBuffers(); @@ -301,7 +300,6 @@ bool handleRenderTransparentWaterChanged(const LLSD& newvalue) if (gPipeline.isInit()) { gPipeline.updateRenderTransparentWater(); - gPipeline.updateRenderDeferred(); gPipeline.releaseGLBuffers(); gPipeline.createGLBuffers(); gPipeline.resetVertexBuffers(); @@ -540,7 +538,6 @@ static bool handleReflectionProbeDetailChanged(const LLSD& newvalue) if (gPipeline.isInit()) { LLPipeline::refreshCachedSettings(); - gPipeline.updateRenderDeferred(); gPipeline.releaseGLBuffers(); gPipeline.createGLBuffers(); gPipeline.resetVertexBuffers(); @@ -549,46 +546,6 @@ static bool handleReflectionProbeDetailChanged(const LLSD& newvalue) return true; } -#if 0 // DEPRECATED -// NOTE: may be triggered by RenderDeferred OR RenderPBR changing, don't trust "newvalue" -static bool handleRenderDeferredChanged(const LLSD& newvalue) -{ - LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred"); - if (gPipeline.isInit()) - { - LLPipeline::refreshCachedSettings(); - gPipeline.updateRenderDeferred(); - gPipeline.releaseGLBuffers(); - gPipeline.createGLBuffers(); - gPipeline.resetVertexBuffers(); - if (LLPipeline::sRenderDeferred == (BOOL)LLRenderTarget::sUseFBO) - { - LLViewerShaderMgr::instance()->setShaders(); - } - } - return true; -} - -// This looks a great deal like handleRenderDeferredChanged because -// Advanced Lighting (Materials) implies bumps and shiny so disabling -// bumps should further disable that feature. -// -static bool handleRenderBumpChanged(const LLSD& newval) -{ - LLRenderTarget::sUseFBO = newval.asBoolean() && gSavedSettings.getBOOL("RenderDeferred"); - if (gPipeline.isInit()) - { - gPipeline.updateRenderBump(); - gPipeline.updateRenderDeferred(); - gPipeline.releaseGLBuffers(); - gPipeline.createGLBuffers(); - gPipeline.resetVertexBuffers(); - LLViewerShaderMgr::instance()->setShaders(); - } - return true; -} -#endif - static bool handleRenderDebugPipelineChanged(const LLSD& newvalue) { gDebugPipeline = newvalue.asBoolean(); @@ -1229,6 +1186,7 @@ void settings_setup_listeners() // DEPRECATED - setting_setup_signal_listener(gSavedSettings, "RenderDeferred", handleRenderDeferredChanged); setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeDetail", handleReflectionProbeDetailChanged); setting_setup_signal_listener(gSavedSettings, "RenderReflectionsEnabled", handleReflectionProbeDetailChanged); + setting_setup_signal_listener(gSavedSettings, "RenderScreenSpaceReflections", handleReflectionProbeDetailChanged); setting_setup_signal_listener(gSavedSettings, "RenderShadowDetail", handleSetShaderChanged); setting_setup_signal_listener(gSavedSettings, "RenderDeferredSSAO", handleSetShaderChanged); setting_setup_signal_listener(gSavedSettings, "RenderPerformanceTest", handleRenderPerfTestChanged); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index a57c12cc5a..0ef438dff6 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1062,15 +1062,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) gGL.setColorMask(true, true); gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance(), true); - - //store this frame's modelview matrix for use - //when rendering next frame's occlusion queries - for (U32 i = 0; i < 16; i++) - { - gGLLastModelView[i] = gGLModelView[i]; - gGLLastProjection[i] = gGLProjection[i]; - } - stop_glerror(); } { @@ -1171,6 +1162,12 @@ void display_cube_face() display_update_camera(); + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Env Update"); + // update all the sky/atmospheric/water settings + LLEnvironment::instance().update(LLViewerCamera::getInstance()); + } + LLSpatialGroup::sNoDelete = TRUE; S32 occlusion = LLPipeline::sUseOcclusion; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index d89db057b9..805f03f49d 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -7347,6 +7347,14 @@ const LLUUID& LLViewerObject::getRenderMaterialID(U8 te) const return LLUUID::null; } +void LLViewerObject::rebuildMaterial() +{ + llassert(!isDead()); + + faceMappingChanged(); + gPipeline.markTextured(mDrawable); +} + void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool update_server) { // implementation is delicate @@ -7375,17 +7383,16 @@ void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool updat } + LLFetchedGLTFMaterial* new_material = nullptr; + if (id.notNull()) + { + new_material = gGLTFMaterialList.getMaterial(id); + } + // update local state for (S32 te = start_idx; te < end_idx; ++te) { - - LLGLTFMaterial* new_material = nullptr; LLTextureEntry* tep = getTE(te); - - if (id.notNull()) - { - new_material = gGLTFMaterialList.getMaterial(id); - } bool material_changed = !param_block || id != param_block->getMaterial(te); @@ -7412,8 +7419,19 @@ void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool updat } // signal to render pipe that render batches must be rebuilt for this object - faceMappingChanged(); - gPipeline.markTextured(mDrawable); + if (!new_material) + { + rebuildMaterial(); + } + else + { + LLPointer this_ptr = this; + new_material->onMaterialComplete([this_ptr]() mutable { + if (this_ptr->isDead()) { return; } + + this_ptr->rebuildMaterial(); + }); + } if (update_server) { diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 9375bf2cbb..76c269c157 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -229,6 +229,7 @@ public: private: void resetRotTime(); void setRenderMaterialIDs(const LLRenderMaterialParams* material_params, bool local_origin); + void rebuildMaterial(); public: void resetRot(); void applyAngularVelocity(F32 dt); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index dfe152aebf..7eaabc61f3 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -475,7 +475,6 @@ void LLViewerShaderMgr::setShaders() gPipeline.releaseGLBuffers(); LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); - LLPipeline::updateRenderDeferred(); //hack to reset buffers that change behavior with shaders gPipeline.resetVertexBuffers(); @@ -504,10 +503,7 @@ void LLViewerShaderMgr::setShaders() //bool canRenderDeferred = true; // DEPRECATED -- LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); //bool hasWindLightShaders = true; // DEPRECATED -- LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders"); - S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); - bool pbr = gSavedSettings.getBOOL("RenderPBR"); bool doingWindLight = true; //DEPRECATED -- hasWindLightShaders&& gSavedSettings.getBOOL("WindLightUseAtmosShaders"); - bool useRenderDeferred = true; //DEPRECATED -- doingWindLight&& canRenderDeferred&& gSavedSettings.getBOOL("RenderDeferred"); S32 light_class = 3; S32 interface_class = 2; @@ -516,32 +512,7 @@ void LLViewerShaderMgr::setShaders() S32 effect_class = 2; S32 wl_class = 1; S32 water_class = 3; - S32 deferred_class = 0; - - if (useRenderDeferred) - { - //shadows - switch (shadow_detail) - { - case 1: - deferred_class = 2; // PCF shadows - break; - - case 2: - deferred_class = 2; // PCF shadows - break; - - case 0: - default: - deferred_class = 1; // no shadows - break; - } - } - - if (deferred_class > 0 && pbr) - { - deferred_class = 3; - } + S32 deferred_class = 3; if (doingWindLight) { @@ -880,6 +851,7 @@ std::string LLViewerShaderMgr::loadBasicShaders() BOOL ambient_kill = gSavedSettings.getBOOL("AmbientDisable"); BOOL sunlight_kill = gSavedSettings.getBOOL("SunlightDisable"); BOOL local_light_kill = gSavedSettings.getBOOL("LocalLightDisable"); + BOOL ssr = gSavedSettings.getBOOL("RenderScreenSpaceReflections"); if (ambient_kill) { @@ -896,6 +868,23 @@ std::string LLViewerShaderMgr::loadBasicShaders() attribs["LOCAL_LIGHT_KILL"] = "1"; } + S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); + + if (shadow_detail >= 1) + { + attribs["SUN_SHADOW"] = "1"; + + if (shadow_detail >= 2) + { + attribs["SPOT_SHADOW"] = "1"; + } + } + + if (ssr) + { + attribs["SSR"] = "1"; + } + // We no longer have to bind the shaders to global glhandles, they are automatically added to a map now. for (U32 i = 0; i < shaders.size(); i++) { @@ -935,7 +924,7 @@ std::string LLViewerShaderMgr::loadBasicShaders() index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/shadowUtil.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/aoUtil.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/reflectionProbeF.glsl", has_reflection_probes ? 3 : 2) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/screenSpaceReflUtil.glsl", 3) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/screenSpaceReflUtil.glsl", ssr ? 3 : 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightAlphaMaskNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); @@ -1759,8 +1748,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredTreeShadowProgram.mName = "Deferred Tree Shadow Shader"; gDeferredTreeShadowProgram.mShaderFiles.clear(); - gDeferredTreeShadowProgram.mFeatures.isDeferred = true; - gDeferredTreeShadowProgram.mFeatures.hasShadows = true; gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowV.glsl", GL_VERTEX_SHADER)); gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER)); gDeferredTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; @@ -1773,8 +1760,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredSkinnedTreeShadowProgram.mName = "Deferred Skinned Tree Shadow Shader"; gDeferredSkinnedTreeShadowProgram.mShaderFiles.clear(); - gDeferredSkinnedTreeShadowProgram.mFeatures.isDeferred = true; - gDeferredSkinnedTreeShadowProgram.mFeatures.hasShadows = true; gDeferredSkinnedTreeShadowProgram.mFeatures.hasObjectSkinning = true; gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowSkinnedV.glsl", GL_VERTEX_SHADER)); gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER)); @@ -3881,6 +3866,12 @@ BOOL LLViewerShaderMgr::loadShadersInterface() { gReflectionProbeDisplayProgram.mName = "Reflection Probe Display Shader"; gReflectionProbeDisplayProgram.mFeatures.hasReflectionProbes = true; + gReflectionProbeDisplayProgram.mFeatures.hasSrgb = true; + gReflectionProbeDisplayProgram.mFeatures.calculatesAtmospherics = true; + gReflectionProbeDisplayProgram.mFeatures.hasAtmospherics = true; + gReflectionProbeDisplayProgram.mFeatures.hasTransport = true; + gReflectionProbeDisplayProgram.mFeatures.hasGamma = true; + gReflectionProbeDisplayProgram.mFeatures.isDeferred = true; gReflectionProbeDisplayProgram.mShaderFiles.clear(); gReflectionProbeDisplayProgram.mShaderFiles.push_back(make_pair("interface/reflectionprobeV.glsl", GL_VERTEX_SHADER)); gReflectionProbeDisplayProgram.mShaderFiles.push_back(make_pair("interface/reflectionprobeF.glsl", GL_FRAGMENT_SHADER)); @@ -3934,6 +3925,9 @@ BOOL LLViewerShaderMgr::loadShadersInterface() { gReflectionMipProgram.mName = "Reflection Mip Shader"; gReflectionMipProgram.mFeatures.isDeferred = true; + gReflectionMipProgram.mFeatures.hasGamma = true; + gReflectionMipProgram.mFeatures.hasAtmospherics = true; + gReflectionMipProgram.mFeatures.calculatesAtmospherics = true; gReflectionMipProgram.mShaderFiles.clear(); gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/splattexturerectV.glsl", GL_VERTEX_SHADER)); gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/reflectionmipF.glsl", GL_FRAGMENT_SHADER)); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 71827fd378..6558d88cb4 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -6072,7 +6072,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei //U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA; U32 color_fmt = (type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH || type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH24) ? GL_DEPTH_COMPONENT : GL_RGBA; // - if (scratch_space.allocate(image_width, image_height, color_fmt, true, true)) + if (scratch_space.allocate(image_width, image_height, color_fmt, true)) { original_width = gPipeline.mRT->deferredScreen.getWidth(); original_height = gPipeline.mRT->deferredScreen.getHeight(); @@ -6379,9 +6379,7 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_ LLRenderTarget scratch_space; U32 color_fmt = GL_RGBA; - const bool use_depth_buffer = true; - const bool use_stencil_buffer = false; - if (scratch_space.allocate(image_width, image_height, color_fmt, use_depth_buffer, use_stencil_buffer)) + if (scratch_space.allocate(image_width, image_height, color_fmt, true)) { if (gPipeline.allocateScreenBuffer(image_width, image_height)) { diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index a70fefe6ab..4e9a8bb8d9 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -345,7 +345,6 @@ bool LLPipeline::sRenderAttachedLights = true; bool LLPipeline::sRenderAttachedParticles = true; bool LLPipeline::sRenderDeferred = false; bool LLPipeline::sReflectionProbesEnabled = false; -bool LLPipeline::sRenderPBR = false; S32 LLPipeline::sVisibleLightCount = 0; bool LLPipeline::sRenderingHUDs; F32 LLPipeline::sDistortionWaterClipPlaneMargin = 1.0125f; @@ -519,14 +518,9 @@ void LLPipeline::init() mBackfaceCull = true; - stop_glerror(); - // Enable features - LLViewerShaderMgr::instance()->setShaders(); - stop_glerror(); - for (U32 i = 0; i < 2; ++i) { mSpotLightFade[i] = 1.f; @@ -887,11 +881,12 @@ LLPipeline::eFBOStatus LLPipeline::doAllocateScreenBuffer(U32 resX, U32 resY) bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; - if (mRT == &mMainRT) + if (mRT == &mMainRT && sReflectionProbesEnabled) { // hacky -- allocate auxillary buffer gCubeSnapshot = TRUE; + mReflectionMapManager.initReflectionMaps(); mRT = &mAuxillaryRT; - U32 res = LL_REFLECTION_PROBE_RESOLUTION * 2; + U32 res = mReflectionMapManager.mProbeResolution * 2; //multiply by 2 because probes will be super sampled allocateScreenBuffer(res, res, samples); mRT = &mMainRT; gCubeSnapshot = FALSE; @@ -930,71 +925,60 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (RenderUIBuffer) { - if (!mRT->uiScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) + if (!mRT->uiScreen.allocate(resX,resY, GL_RGBA)) { return false; } } - if (LLPipeline::sRenderDeferred) - { - S32 shadow_detail = RenderShadowDetail; - bool ssao = RenderDeferredSSAO; + S32 shadow_detail = RenderShadowDetail; + bool ssao = RenderDeferredSSAO; - //allocate deferred rendering color buffers - if (!mRT->deferredScreen.allocate(resX, resY, GL_RGBA, true, true, LLTexUnit::TT_TEXTURE, false, samples)) return false; - if (!addDeferredAttachments(mRT->deferredScreen)) return false; + //allocate deferred rendering color buffers + if (!mRT->deferredScreen.allocate(resX, resY, GL_RGBA, true)) return false; + if (!addDeferredAttachments(mRT->deferredScreen)) return false; - GLuint screenFormat = GL_RGBA16; + GLuint screenFormat = GL_RGBA16; - if (!mRT->screen.allocate(resX, resY, screenFormat, FALSE, true, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false; + if (!mRT->screen.allocate(resX, resY, screenFormat)) return false; - mRT->deferredScreen.shareDepthBuffer(mRT->screen); + mRT->deferredScreen.shareDepthBuffer(mRT->screen); - if (samples > 0) - { - if (!mRT->fxaaBuffer.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false; - } - else - { - mRT->fxaaBuffer.release(); - } + if (samples > 0) + { + if (!mRT->fxaaBuffer.allocate(resX, resY, GL_RGBA)) return false; + } + else + { + mRT->fxaaBuffer.release(); + } // if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0) // [RLVa:KB] - @setsphere if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0 || RlvActions::hasPostProcess()) // [/RLVa:KB] { //only need mRT->deferredLight for shadows OR ssao OR dof OR fxaa - if (!mRT->deferredLight.allocate(resX, resY, GL_RGBA16, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false; + if (!mRT->deferredLight.allocate(resX, resY, GL_RGBA16)) return false; } else { mRT->deferredLight.release(); } - allocateShadowBuffer(resX, resY); + allocateShadowBuffer(resX, resY); - //HACK make screenbuffer allocations start failing after 30 seconds - if (gSavedSettings.getBOOL("SimulateFBOFailure")) - { - return false; - } - } - else + if (!gCubeSnapshot && RenderScreenSpaceReflections) // hack to not allocate mSceneMap for cube snapshots { - mRT->deferredLight.release(); + mSceneMap.allocate(resX, resY, GL_RGB, true); + } - releaseSunShadowTargets(); - releaseSpotShadowTargets(); + //HACK make screenbuffer allocations start failing after 30 seconds + if (gSavedSettings.getBOOL("SimulateFBOFailure")) + { + return false; + } - mRT->fxaaBuffer.release(); - mRT->screen.release(); - mRT->deferredScreen.release(); //make sure to release any render targets that share a depth buffer with mRT->deferredScreen first - - if (!mRT->screen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_TEXTURE, FALSE)) return false; - } - - gGL.getTexUnit(0)->disable(); + gGL.getTexUnit(0)->disable(); stop_glerror(); @@ -1017,7 +1001,7 @@ bool LLPipeline::allocateShadowBuffer(U32 resX, U32 resY) { //allocate 4 sun shadow maps for (U32 i = 0; i < 4; i++) { - if (!mRT->shadow[i].allocate(sun_shadow_map_width, sun_shadow_map_height, 0, true, true, LLTexUnit::TT_TEXTURE)) + if (!mRT->shadow[i].allocate(sun_shadow_map_width, sun_shadow_map_height, 0, true)) { return false; } @@ -1042,7 +1026,7 @@ bool LLPipeline::allocateShadowBuffer(U32 resX, U32 resY) U32 spot_shadow_map_height = height; for (U32 i = 0; i < 2; i++) { - if (!mSpotShadow[i].allocate(spot_shadow_map_width, spot_shadow_map_height, 0, true, true)) + if (!mSpotShadow[i].allocate(spot_shadow_map_width, spot_shadow_map_height, 0, true)) { return false; } @@ -1105,22 +1089,6 @@ void LLPipeline::updateRenderBump() sRenderBump = TRUE; // DEPRECATED -- gSavedSettings.getBOOL("RenderObjectBump"); } -// static -void LLPipeline::updateRenderDeferred() -{ - sRenderPBR = sRenderDeferred; - - exoPostProcess::instance().ExodusRenderPostUpdate(); // Import Vignette from Exodus - -// [RLVa:KB] - @setsphere - if (!sRenderDeferred && RlvActions::hasBehaviour(RLV_BHVR_SETSPHERE) && WindLightUseAtmosShaders) - { - LLRenderTarget::sUseFBO = true; - LLPipeline::sUseDepthTexture = true; - } -// [/RLVa:KB] -} - // static void LLPipeline::refreshCachedSettings() { @@ -1227,10 +1195,10 @@ void LLPipeline::refreshCachedSettings() RenderAutoHideSurfaceAreaLimit = gSavedSettings.getF32("RenderAutoHideSurfaceAreaLimit"); RenderScreenSpaceReflections = gSavedSettings.getBOOL("RenderScreenSpaceReflections"); - sReflectionProbesEnabled = gSavedSettings.getBOOL("RenderReflectionsEnabled"); + sReflectionProbesEnabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionsEnabled") && gSavedSettings.getBOOL("RenderReflectionsEnabled"); RenderSpotLight = nullptr; - updateRenderDeferred(); + exoPostProcess::instance().ExodusRenderPostUpdate(); // Import Vignette from Exodus if (gNonInteractive) { @@ -1261,6 +1229,8 @@ void LLPipeline::releaseGLBuffers() mWaterDis.release(); mBake.release(); + mSceneMap.release(); + for (U32 i = 0; i < 3; i++) { mGlow[i].release(); @@ -1331,17 +1301,17 @@ void LLPipeline::createGLBuffers() stop_glerror(); assertInitialized(); - updateRenderDeferred(); + exoPostProcess::instance().ExodusRenderPostUpdate(); // Import Vignette from Exodus if (LLPipeline::sRenderTransparentWater) { //water reflection texture U32 res = (U32) llmax(gSavedSettings.getS32("RenderWaterRefResolution"), 512); - mWaterDis.allocate(res,res,GL_RGBA,true,true,LLTexUnit::TT_TEXTURE); + mWaterDis.allocate(res,res,GL_RGBA,true); } // Use FBO for bake tex // Allow higher resolution rendering in mesh render preview - //mBake.allocate(512, 512, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_TEXTURE, true); // SL-12781 Build > Upload > Model; 3D Preview - mBake.allocate(1024, 1024, GL_RGBA, true, false, LLTexUnit::TT_TEXTURE, true); // SL-12781 Build > Upload > Model; 3D Preview + //mBake.allocate(512, 512, GL_RGBA, true); // SL-12781 Build > Upload > Model; 3D Preview + mBake.allocate(1024, 1024, GL_RGBA, true); // SL-12781 Build > Upload > Model; 3D Preview // stop_glerror(); @@ -1353,7 +1323,7 @@ void LLPipeline::createGLBuffers() const U32 glow_res = llmax(1, llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow"))); for (U32 i = 0; i < 3; i++) { - mGlow[i].allocate(512, glow_res, GL_RGBA, FALSE, FALSE); + mGlow[i].allocate(512, glow_res, GL_RGBA); } allocateScreenBuffer(resX, resY); @@ -1459,7 +1429,7 @@ void LLPipeline::createLUTBuffers() delete [] ls; } - mPbrBrdfLut.allocate(512, 512, GL_RG16F, false, false); + mPbrBrdfLut.allocate(512, 512, GL_RG16F); mPbrBrdfLut.bindTarget(); gDeferredGenBrdfLutProgram.bind(); @@ -4220,10 +4190,31 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } + if (&camera == LLViewerCamera::getInstance()) + { // a bit hacky, this is the start of the main render frame, figure out delta between last modelview matrix and + // current modelview matrix + glh::matrix4f last_modelview(gGLLastModelView); + glh::matrix4f cur_modelview(gGLModelView); + + // goal is to have a matrix here that goes from the last frame's camera space to the current frame's camera space + glh::matrix4f m = last_modelview.inverse(); // last camera space to world space + m.mult_left(cur_modelview); // world space to camera space + + glh::matrix4f n = m.inverse(); + + for (U32 i = 0; i < 16; ++i) + { + gGLDeltaModelView[i] = m.m[i]; + gGLInverseDeltaModelView[i] = n.m[i]; + } + } + bool occlude = LLPipeline::sUseOcclusion > 1 && do_occlusion; + setupHWLights(nullptr); + { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pools"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS); + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pools"); LLGLEnable cull(GL_CULL_FACE); @@ -4272,7 +4263,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pool render"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER); + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pool render"); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -4332,7 +4323,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion) void LLPipeline::renderGeomPostDeferred(LLCamera& camera) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LL_PROFILE_GPU_ZONE("renderGeomPostDeferred"); if (gUseWireframe) @@ -4349,10 +4340,16 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) calcNearbyLights(camera); setupHWLights(NULL); + gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.setColorMask(true, false); pool_set_t::iterator iter1 = mPools.begin(); + if (gDebugGL || gDebugPipeline) + { + LLGLState::checkStates(GL_FALSE); + } + while ( iter1 != mPools.end() ) { LLDrawPool *poolp = *iter1; @@ -4362,7 +4359,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred poolrender"); //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER); + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred poolrender"); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -5936,6 +5933,15 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) // Ambient LLColor4 ambient = psky->getTotalAmbient(); + static LLCachedControl ambiance_scale(gSavedSettings, "RenderReflectionProbeAmbianceScale", 8.f); + + F32 light_scale = 1.f; + + if (gCubeSnapshot && !mReflectionMapManager.isRadiancePass()) + { //darken local lights based on brightening of sky lighting + light_scale = 1.f / ambiance_scale; + } + gGL.setAmbientLightColor(ambient); bool sun_up = environment.getIsSunUp(); @@ -6029,7 +6035,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) } //send linear light color to shader - LLColor4 light_color = light->getLightLinearColor(); + LLColor4 light_color = light->getLightLinearColor()*light_scale; light_color.mV[3] = 0.0f; F32 fade = iter->fade; @@ -7057,10 +7063,9 @@ void LLPipeline::doResetVertexBuffers(bool forced) LLVOPartGroup::destroyGL(); gGL.resetVertexBuffer(); - LLVertexBuffer::unbind(); + LLVertexBuffer::unbind(); updateRenderBump(); - //updateRenderDeferred(); // Moved further down because of exoPostProcess creating a new VB sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight"); sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha"); @@ -7076,9 +7081,7 @@ void LLPipeline::doResetVertexBuffers(bool forced) LLVOPartGroup::restoreGL(); - // Reset VB during TP - updateRenderDeferred(); // Moved further down because of exoPostProcess creating a new VB - // + exoPostProcess::instance().ExodusRenderPostUpdate(); // Import Vignette from Exodus } void LLPipeline::renderObjects(U32 type, bool texture, bool batch_texture, bool rigged) @@ -7792,10 +7795,11 @@ void LLPipeline::renderFinalize() if (!gCubeSnapshot) { - screenTarget()->bindTarget(); + LLRenderTarget* screen_target = screenTarget(); - if (RenderScreenSpaceReflections) + if (RenderScreenSpaceReflections && !gCubeSnapshot) { +#if 0 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - screen space reflections"); LL_PROFILE_GPU_ZONE("screen space reflections"); @@ -7828,8 +7832,33 @@ void LLPipeline::renderFinalize() } unbindDeferredShader(gPostScreenSpaceReflectionProgram); +#else + LL_PROFILE_GPU_ZONE("ssr copy"); + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + + LLRenderTarget& src = *screen_target; + LLRenderTarget& depth_src = mRT->deferredScreen; + LLRenderTarget& dst = mSceneMap; + + dst.bindTarget(); + dst.clear(); + gCopyDepthProgram.bind(); + + S32 diff_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DIFFUSE_MAP); + S32 depth_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DEFERRED_DEPTH); + + gGL.getTexUnit(diff_map)->bind(&src); + gGL.getTexUnit(depth_map)->bind(&depth_src, true); + + mScreenTriangleVB->setBuffer(); + mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + + dst.flush(); +#endif } + screenTarget()->bindTarget(); + // gamma correct lighting { LL_PROFILE_GPU_ZONE("gamma correct"); @@ -7855,17 +7884,8 @@ void LLPipeline::renderFinalize() gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f)); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1, -1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1, 3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3, -1); - - gGL.end(); + mScreenTriangleVB->setBuffer(); + mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); gGL.getTexUnit(channel)->unbind(screenTarget()->getUsage()); gDeferredPostGammaCorrectProgram.unbind(); @@ -8133,56 +8153,6 @@ void LLPipeline::bindDeferredShaderFast(LLGLSLShader& shader) bindLightFunc(shader); bindShadowMaps(shader); bindReflectionProbes(shader); - -#if 0 - shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash); - shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise); - shader.uniform1f(LLShaderMgr::DEFERRED_BLUR_SIZE, RenderShadowBlurSize); - - shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_RADIUS, RenderSSAOScale); - shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_MAX_RADIUS, RenderSSAOMaxScale); - - F32 ssao_factor = RenderSSAOFactor; - shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR, ssao_factor); - shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR_INV, 1.0 / ssao_factor); - - LLVector3 ssao_effect = RenderSSAOEffect; - F32 matrix_diag = (ssao_effect[0] + 2.0 * ssao_effect[1]) / 3.0; - F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1]) / 3.0; - // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by - // value factor, and scales remainder by saturation factor - F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag, - matrix_nondiag, matrix_diag, matrix_nondiag, - matrix_nondiag, matrix_nondiag, matrix_diag }; - shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_SSAO_EFFECT_MAT, 1, GL_FALSE, ssao_effect_mat); - - //F32 shadow_offset_error = 1.f + RenderShadowOffsetError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); - F32 shadow_bias_error = RenderShadowBiasError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]) / 3000.f; - F32 shadow_bias = RenderShadowBias + shadow_bias_error; - - //shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, deferred_target->getWidth(), deferred_target->getHeight()); - shader.uniform1f(LLShaderMgr::DEFERRED_NEAR_CLIP, LLViewerCamera::getInstance()->getNear() * 2.f); - shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_OFFSET, RenderShadowOffset); //*shadow_offset_error); - shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_BIAS, shadow_bias); - shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_OFFSET, RenderSpotShadowOffset); - shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_BIAS, RenderSpotShadowBias); - - shader.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.mV); - shader.uniform3fv(LLShaderMgr::DEFERRED_MOON_DIR, 1, mTransformedMoonDir.mV); - shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mRT->shadow[0].getWidth(), mRT->shadow[0].getHeight()); - shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mSpotShadow[0].getWidth(), mSpotShadow[0].getHeight()); - shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff); - shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff); - - if (shader.getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0) - { - glh::matrix4f norm_mat = get_current_modelview().inverse().transpose(); - shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m); - } - - shader.uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, mSunDiffuse.mV); - shader.uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, 1, mMoonDiffuse.mV); -#endif } void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target) @@ -8222,21 +8192,24 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); } -#if 0 - channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_depth_target->getUsage()); - if (channel > -1) - { - gGL.getTexUnit(channel)->bind(deferred_depth_target, TRUE); - stop_glerror(); - } -#else channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_target->getUsage()); if (channel > -1) { gGL.getTexUnit(channel)->bind(deferred_target, TRUE); stop_glerror(); } -#endif + + channel = shader.enableTexture(LLShaderMgr::SCENE_MAP); + if (channel > -1) + { + gGL.getTexUnit(channel)->bind(&mSceneMap); + } + + channel = shader.enableTexture(LLShaderMgr::SCENE_DEPTH); + if (channel > -1) + { + gGL.getTexUnit(channel)->bind(&mSceneMap, true); + } if (shader.getUniformLocation(LLShaderMgr::VIEWPORT) != -1) { @@ -8402,6 +8375,11 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff); shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff); + shader.uniformMatrix4fv(LLShaderMgr::MODELVIEW_DELTA_MATRIX, 1, GL_FALSE, gGLDeltaModelView); + shader.uniformMatrix4fv(LLShaderMgr::INVERSE_MODELVIEW_DELTA_MATRIX, 1, GL_FALSE, gGLInverseDeltaModelView); + + shader.uniform1i(LLShaderMgr::CUBE_SNAPSHOT, gCubeSnapshot ? 1 : 0); + if (shader.getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0) { glh::matrix4f norm_mat = get_current_modelview().inverse().transpose(); @@ -8410,6 +8388,8 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ shader.uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, mSunDiffuse.mV); shader.uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, 1, mMoonDiffuse.mV); + + shader.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mReflectionMapManager.mMaxProbeLOD); } @@ -8431,8 +8411,6 @@ LLVector4 pow4fsrgb(LLVector4 v, F32 f) void LLPipeline::renderDeferredLighting() { - - LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; LL_PROFILE_GPU_ZONE("renderDeferredLighting"); if (!sCull) @@ -8440,32 +8418,22 @@ void LLPipeline::renderDeferredLighting() return; } + static LLCachedControl ambiance_scale(gSavedSettings, "RenderReflectionProbeAmbianceScale", 8.f); + + F32 light_scale = 1.f; + + if (gCubeSnapshot && !mReflectionMapManager.isRadiancePass()) + { //darken local lights based on brightening of sky lighting + light_scale = 1.f / ambiance_scale; + } + LLRenderTarget *screen_target = &mRT->screen; - //LLRenderTarget *deferred_target = &mRT->deferredScreen; - //LLRenderTarget *deferred_depth_target = &mRT->deferredDepth; LLRenderTarget* deferred_light_target = &mRT->deferredLight; { - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("deferred"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED); + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("deferred"); LLViewerCamera *camera = LLViewerCamera::getInstance(); -#if 0 - { - LLGLDepthTest depth(GL_TRUE); - deferred_depth_target->copyContents(*deferred_target, - 0, - 0, - deferred_target->getWidth(), - deferred_target->getHeight(), - 0, - 0, - deferred_depth_target->getWidth(), - deferred_depth_target->getHeight(), - GL_DEPTH_BUFFER_BIT, - GL_NEAREST); - } -#endif - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE : 0); if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) @@ -8473,11 +8441,6 @@ void LLPipeline::renderDeferredLighting() gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); } - // ati doesn't seem to love actually using the stencil buffer on FBO's - //LLGLDisable stencil(GL_STENCIL_TEST); - // glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); - // glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - gGL.setColorMask(true, true); // draw a cube around every light @@ -8547,76 +8510,64 @@ void LLPipeline::renderDeferredLighting() if (RenderDeferredSSAO) { - /*if (gCubeSnapshot) - { // SSAO and shadows disabled in reflection maps - deferred_light_target->bindTarget(); - glClearColor(1, 1, 1, 1); - deferred_light_target->clear(); - glClearColor(0, 0, 0, 0); - deferred_light_target->flush(); - } - else*/ + // soften direct lighting lightmap + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow"); + LL_PROFILE_GPU_ZONE("soften shadow"); + // blur lightmap + screen_target->bindTarget(); + glClearColor(1, 1, 1, 1); + screen_target->clear(GL_COLOR_BUFFER_BIT); + glClearColor(0, 0, 0, 0); + + bindDeferredShader(gDeferredBlurLightProgram); + + LLVector3 go = RenderShadowGaussian; + const U32 kern_length = 4; + F32 blur_size = RenderShadowBlurSize; + F32 dist_factor = RenderShadowBlurDistFactor; + + // sample symmetrically with the middle sample falling exactly on 0.0 + F32 x = 0.f; + + LLVector3 gauss[32]; // xweight, yweight, offset + + for (U32 i = 0; i < kern_length; i++) { - // soften direct lighting lightmap - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow"); - LL_PROFILE_GPU_ZONE("soften shadow"); - // blur lightmap - screen_target->bindTarget(); - glClearColor(1, 1, 1, 1); - screen_target->clear(GL_COLOR_BUFFER_BIT); - glClearColor(0, 0, 0, 0); - - bindDeferredShader(gDeferredBlurLightProgram); - mScreenTriangleVB->setBuffer(); - LLVector3 go = RenderShadowGaussian; - const U32 kern_length = 4; - F32 blur_size = RenderShadowBlurSize; - F32 dist_factor = RenderShadowBlurDistFactor; - - // sample symmetrically with the middle sample falling exactly on 0.0 - F32 x = 0.f; - - LLVector3 gauss[32]; // xweight, yweight, offset - - F32 screenPixelSize = 1.f / screen_target->getWidth(); - - for (U32 i = 0; i < kern_length; i++) - { - gauss[i].mV[0] = llgaussian(x, go.mV[0]); - gauss[i].mV[1] = llgaussian(x, go.mV[1]); - gauss[i].mV[2] = x; - x += screenPixelSize; - } - - gDeferredBlurLightProgram.uniform2f(sDelta, screenPixelSize, 0.f); - gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor); - gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV); - gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f)); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); - } - - screen_target->flush(); - unbindDeferredShader(gDeferredBlurLightProgram); - - bindDeferredShader(gDeferredBlurLightProgram, screen_target); - - mScreenTriangleVB->setBuffer(); - deferred_light_target->bindTarget(); - - gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f); - - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); - } - deferred_light_target->flush(); - unbindDeferredShader(gDeferredBlurLightProgram); + gauss[i].mV[0] = llgaussian(x, go.mV[0]); + gauss[i].mV[1] = llgaussian(x, go.mV[1]); + gauss[i].mV[2] = x; + x += 1.f; } + + gDeferredBlurLightProgram.uniform2f(sDelta, 1.f, 0.f); + gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor); + gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV); + gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f)); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + mScreenTriangleVB->setBuffer(); + mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + } + + screen_target->flush(); + unbindDeferredShader(gDeferredBlurLightProgram); + + bindDeferredShader(gDeferredBlurLightProgram, screen_target); + + deferred_light_target->bindTarget(); + + gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + mScreenTriangleVB->setBuffer(); + mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + } + deferred_light_target->flush(); + unbindDeferredShader(gDeferredBlurLightProgram); } screen_target->bindTarget(); @@ -8636,50 +8587,19 @@ void LLPipeline::renderDeferredLighting() soften_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); soften_shader.uniform3fv(LLShaderMgr::LIGHTNORM, 1, environment.getClampedLightNorm().mV); - if (!LLPipeline::sUnderWaterRender && LLPipeline::sRenderPBR) - { - soften_shader.bindTexture(LLShaderMgr::ALTERNATE_DIFFUSE_MAP, LLViewerFetchedTexture::sDefaultIrradiancePBRp); // PBR: irradiance - } - - if(LLPipeline::sRenderPBR) - { - LLVector3 cameraAtAxis = LLViewerCamera::getInstance()->getAtAxis(); - soften_shader.uniform3fv(LLShaderMgr::DEFERRED_VIEW_DIR, 1, cameraAtAxis.mV); - } - { LLGLDepthTest depth(GL_FALSE); LLGLDisable blend(GL_BLEND); LLGLDisable test(GL_ALPHA_TEST); // full screen blit - mScreenTriangleVB->setBuffer(); mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); - } unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram); } -#if 0 - { // render non-deferred geometry (fullbright, alpha, etc) - LLGLDisable blend(GL_BLEND); - //LLGLDisable stencil(GL_STENCIL_TEST); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - gPipeline.pushRenderTypeMask(); - - gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_CLOUDS, - LLPipeline::RENDER_TYPE_WL_SKY, - LLPipeline::END_RENDER_TYPES); - - renderGeomPostDeferred(*LLViewerCamera::getInstance(), false); - gPipeline.popRenderTypeMask(); - } -#endif - bool render_local = RenderLocalLights; // && !gCubeSnapshot; if (render_local) @@ -8740,7 +8660,7 @@ void LLPipeline::renderDeferredLighting() F32 s = volume->getLightRadius() * 1.5f; // send light color to shader in linear space - LLColor3 col = volume->getLightLinearColor(); + LLColor3 col = volume->getLightLinearColor()*light_scale; if (col.magVecSquared() < 0.001f) { @@ -8834,7 +8754,7 @@ void LLPipeline::renderDeferredLighting() setupSpotLight(gDeferredSpotLightProgram, drawablep); // send light color to shader in linear space - LLColor3 col = volume->getLightLinearColor(); + LLColor3 col = volume->getLightLinearColor() * light_scale; gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c); gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s); @@ -8909,7 +8829,7 @@ void LLPipeline::renderDeferredLighting() setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); // send light color to shader in linear space - LLColor3 col = volume->getLightLinearColor(); + LLColor3 col = volume->getLightLinearColor() * light_scale; gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, light_size_final); @@ -8965,6 +8885,16 @@ void LLPipeline::renderDeferredLighting() screen_target->flush(); + if (!gCubeSnapshot) + { + // this is the end of the 3D scene render, grab a copy of the modelview and projection + // matrix for use in off-by-one-frame effects in the next frame + for (U32 i = 0; i < 16; i++) + { + gGLLastModelView[i] = gGLModelView[i]; + gGLLastProjection[i] = gGLProjection[i]; + } + } gGL.setColorMask(true, true); } @@ -9304,24 +9234,23 @@ static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_TREE("Alpha Tree"); static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_GRASS("Alpha Grass"); static LLTrace::BlockTimerStatHandle FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED("Fullbright Alpha Masked"); -void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult& result, bool use_shader, bool use_occlusion, U32 target_width) +void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult& result, bool depth_clamp) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER); LL_PROFILE_GPU_ZONE("renderShadow"); - //disable occlusion culling for shadow passes (save setting to restore later) - S32 occlude = LLPipeline::sUseOcclusion; - if (!use_occlusion) - { - LLPipeline::sUseOcclusion = 0; - } + LLPipeline::sShadowRender = true; + // disable occlusion culling during shadow render + U32 saved_occlusion = sUseOcclusion; + sUseOcclusion = 0; + static const U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP, - LLRenderPass::PASS_FULLBRIGHT_SHINY , + LLRenderPass::PASS_FULLBRIGHT_SHINY, LLRenderPass::PASS_MATERIAL, LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, LLRenderPass::PASS_SPECMAP, @@ -9336,21 +9265,14 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera LLGLEnable cull(GL_CULL_FACE); //enable depth clamping if available - LLGLEnable depth_clamp(GL_DEPTH_CLAMP); + LLGLEnable clamp_depth(depth_clamp ? GL_DEPTH_CLAMP : 0); LLGLDepthTest depth_test(GL_TRUE, GL_TRUE, GL_LESS); - if (use_shader) - { - gDeferredShadowCubeProgram.bind(); - } - - updateCull(shadow_cam, result); stateSort(shadow_cam, result); - //generate shadow map gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); @@ -9413,25 +9335,14 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); } - if (occlude > 1) + if (LLPipeline::sUseOcclusion > 1) { // do occlusion culling against non-masked only to take advantage of hierarchical Z doOcclusion(shadow_cam); } - if (use_shader) { LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); - - gDeferredShadowProgram.unbind(); - renderGeomShadow(shadow_cam); - gDeferredShadowProgram.bind(); - gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); - } - else - { - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); - renderGeomShadow(shadow_cam); } @@ -9439,6 +9350,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha"); LL_PROFILE_GPU_ZONE("shadow alpha"); + U32 target_width = LLRenderTarget::sCurResX; + for (int i = 0; i < 2; ++i) { bool rigged = i == 1; @@ -9520,11 +9433,6 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); - if (use_shader) - { - gDeferredShadowProgram.unbind(); - } - gGL.setColorMask(true, true); gGL.matrixMode(LLRender::MM_PROJECTION); @@ -9533,7 +9441,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera gGL.popMatrix(); gGLLastMatrix = NULL; - LLPipeline::sUseOcclusion = occlude; + // reset occlusion culling flag + sUseOcclusion = saved_occlusion; LLPipeline::sShadowRender = false; } @@ -10374,11 +10283,9 @@ void LLPipeline::generateSunShadow(LLCamera& camera) mRT->shadow[j].getViewport(gGLViewport); mRT->shadow[j].clear(); - U32 target_width = mRT->shadow[j].getWidth(); - { static LLCullResult result[4]; - renderShadow(view[j], proj[j], shadow_cam, result[j], true, true, target_width); + renderShadow(view[j], proj[j], shadow_cam, result[j], true); } mRT->shadow[j].flush(); @@ -10525,15 +10432,13 @@ void LLPipeline::generateSunShadow(LLCamera& camera) mSpotShadow[i].getViewport(gGLViewport); mSpotShadow[i].clear(); - U32 target_width = mSpotShadow[i].getWidth(); - static LLCullResult result[2]; LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SPOT_SHADOW0 + i); RenderSpotLight = drawable; - renderShadow(view[i + 4], proj[i + 4], shadow_cam, result[i], false, true, target_width); + renderShadow(view[i + 4], proj[i + 4], shadow_cam, result[i], false); RenderSpotLight = nullptr; @@ -10818,7 +10723,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) if (!avatar->mImpostor.isComplete()) { - avatar->mImpostor.allocate(resX, resY, GL_RGBA, TRUE, FALSE); + avatar->mImpostor.allocate(resX, resY, GL_RGBA, true); if (LLPipeline::sRenderDeferred) { diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 8f76d80745..77852f04e0 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -318,7 +318,7 @@ public: void renderHighlight(const LLViewerObject* obj, F32 fade); - void renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& camera, LLCullResult& result, bool use_shader, bool use_occlusion, U32 target_width); + void renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& camera, LLCullResult& result, bool depth_clamp); void renderHighlights(); void renderDebug(); void renderPhysicsDisplay(); @@ -428,7 +428,6 @@ public: static void updateRenderTransparentWater(); static void updateRenderBump(); - static void updateRenderDeferred(); static void refreshCachedSettings(); void addDebugBlip(const LLVector3& position, const LLColor4& color); @@ -654,7 +653,6 @@ public: static bool sRenderAttachedParticles; static bool sRenderDeferred; static bool sReflectionProbesEnabled; - static bool sRenderPBR; static S32 sVisibleLightCount; static bool sRenderingHUDs; static F32 sDistortionWaterClipPlaneMargin; @@ -702,6 +700,10 @@ public: LLRenderTarget mPbrBrdfLut; + // copy of the color/depth buffer just before gamma correction + // for use by SSR + LLRenderTarget mSceneMap; + LLCullResult mSky; LLCullResult mReflectedObjects; LLCullResult mRefractedObjects; diff --git a/indra/newview/skins/default/xui/de/floater_about.xml b/indra/newview/skins/default/xui/de/floater_about.xml index f06b624702..5f2c7b75b1 100644 --- a/indra/newview/skins/default/xui/de/floater_about.xml +++ b/indra/newview/skins/default/xui/de/floater_about.xml @@ -65,6 +65,7 @@ PCRE Copyright (c) 1997-2012 University of Cambridge. SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga. SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com). xmlrpc-epi Copyright (C) 2000 Epinions, Inc. +xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2012 Jean-loup Gailly und Mark Adler. Second Life Viewer verwendet Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (und Lizenzgeber). Alle Rechte vorbehalten. Details siehe www.havok.com. diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index ad13ffcc07..f784f7322d 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -260,6 +260,7 @@ PCRE Copyright (c) 1997-2012 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) xmlrpc-epi Copyright (C) 2000 Epinions, Inc. +xxHash Copyright (C) 2012-2020 Yann Collet. zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. Some icons by Joseph Wain / glyphish.com diff --git a/indra/newview/skins/default/xui/en/panel_gltf_material.xml b/indra/newview/skins/default/xui/en/panel_gltf_material.xml index 2936b3cb63..6975525b3d 100644 --- a/indra/newview/skins/default/xui/en/panel_gltf_material.xml +++ b/indra/newview/skins/default/xui/en/panel_gltf_material.xml @@ -37,7 +37,8 @@ layout="topleft" left="10" top="5" - width="128"> + width="128" + name="base_color_lbl"> Base Color: + top="8" + name="base_color_tint_lbl"> Tint + width="96" + name="base_color_transparency_lbl"> Transparency + width="90" + name="alpha_mode_lbl"> Alpha mode + width="96" + name="alpha_cutoff_lbl"> Alpha Cutoff + top="5" + name="metallic_roughness_lbl"> Metallic-Roughness: + top="8" + name="metallic_factor_lbl"> Metallic Factor + width="96" + name="roughness_factor_lbl"> Roughness Factor + width="64" + name="emissive_lbl"> Emissive: + top="8" + name="emissive_tint_lbl"> Tint + width="64" + name="normal_lbl"> Normal: