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
+
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: