# Conflicts:
#	indra/llcommon/llprofiler.h
#	indra/llcommon/lluuid.cpp
#	indra/llprimitive/llmodel.cpp
#	indra/llrender/llrendertarget.cpp
#	indra/newview/app_settings/settings.xml
#	indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
#	indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
#	indra/newview/llviewerwindow.cpp
#	indra/newview/pipeline.cpp
#	indra/newview/skins/default/xui/da/floater_about.xml
#	indra/newview/skins/default/xui/de/floater_about.xml
#	indra/newview/skins/default/xui/en/floater_about.xml
#	indra/newview/skins/default/xui/es/floater_about.xml
#	indra/newview/skins/default/xui/fr/floater_about.xml
#	indra/newview/skins/default/xui/it/floater_about.xml
#	indra/newview/skins/default/xui/pt/floater_about.xml
#	indra/newview/skins/default/xui/ru/floater_about.xml
#	indra/newview/skins/default/xui/tr/floater_about.xml
#	indra/newview/skins/default/xui/zh/floater_about.xml
master
Ansariel 2023-02-01 11:40:17 +01:00
commit 6cbca4da71
90 changed files with 2566 additions and 2104 deletions

View File

@ -3465,6 +3465,36 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>version</key>
<string>0.54.1.555529</string>
</map>
<key>xxhash</key>
<map>
<key>copyright</key>
<string>Copyright 2012-2020 Yann Collet</string>
<key>description</key>
<string>xxHash Extremely fast hash algorithm</string>
<key>license</key>
<string>bsd</string>
<key>license_file</key>
<string>LICENSES/xxhash.txt</string>
<key>name</key>
<string>xxhash</string>
<key>platforms</key>
<map>
<key>common</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>e4f77ba0a9b8ec3cc3fabc51c4da81d2</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/110070/956941/xxhash-0.8.1.578006-windows-578006.tar.bz2</string>
</map>
<key>name</key>
<string>common</string>
</map>
</map>
<key>version</key>
<string>0.8.1</string>
</map>
<key>zlib-ng</key>
<map>
<key>canonical_repo</key>

View File

@ -588,6 +588,8 @@ Henri Beauchamp
VWR-1320
VWR-1406
VWR-4157
SL-15175
SL-19110
herina Bode
Hikkoshi Sakai
VWR-429

View File

@ -96,6 +96,7 @@ set(cmake_SOURCE_FILES
VisualLeakDetector.cmake
LibVLCPlugin.cmake
XmlRpcEpi.cmake
xxHash.cmake
ZLIBNG.cmake
)

View File

@ -4,6 +4,7 @@ include(APR)
include(Boost)
include(EXPAT)
include(Tracy)
include(xxHash)
include(ZLIBNG)
set(LLCOMMON_INCLUDE_DIRS

8
indra/cmake/xxHash.cmake Normal file
View File

@ -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)

View File

@ -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

377
indra/llcommon/hbxxh.cpp Normal file
View File

@ -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;
}

259
indra/llcommon/hbxxh.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
iter != sStateMap.end(); ++iter)

View File

@ -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;

View File

@ -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;

View File

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

View File

@ -376,7 +376,7 @@ void LLPostProcess::doEffects(void)
checkError();
applyShaders();
LLGLSLShader::bindNoShader();
LLGLSLShader::unbind();
checkError();
/// Change to a perspective view

View File

@ -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<std::size_t, LLVBCache> sVBCache;
static std::unordered_map<U64, LLVBCache> 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<std::size_t, LLVBCache>::iterator cache = sVBCache.find(vhash[0]);
std::unordered_map<U64, LLVBCache>::iterator cache = sVBCache.find(vhash);
LLPointer<LLVertexBuffer> 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<std::size_t, LLVBCache>::iterator iter = sVBCache.begin(); iter != sVBCache.end(); )
for (std::unordered_map<U64, LLVBCache>::iterator iter = sVBCache.begin(); iter != sVBCache.end(); )
{
if (now - iter->second.touched > 1s)
{

View File

@ -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;

View File

@ -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;
}

View File

@ -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<U32> mTex;
std::vector<U32> mInternalFormat;
U32 mFBO;
U32 mPreviousFBO;
U32 mPreviousResX;
U32 mPreviousResY;
LLRenderTarget* mPreviousRT = nullptr;
U32 mDepth;
U32 mDepth;
bool mUseDepth;
bool mSampleDepth;
LLTexUnit::eTextureType mUsage;

View File

@ -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");

View File

@ -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"

View File

@ -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));
}
}
}

View File

@ -12716,18 +12716,6 @@ Change of this parameter will affect the layout of buttons in notification toast
<integer>0</integer>
</map>
<key>RenderPBR</key>
<map>
<key>Comment</key>
<string>DEPRECATED - only true supported - Use PBR rendering pipeline (Physically Based Rendering).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>RenderDeferred</key>
<map>
<key>Comment</key>
@ -13480,6 +13468,28 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>256</integer>
</map>
<key>RenderReflectionProbeResolution</key>
<map>
<key>Comment</key>
<string>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.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>256</integer>
</map>
<key>RenderReflectionProbeAmbianceScale</key>
<map>
<key>Comment</key>
<string>Scaler to apply to reflection probes to over-brighten sky contributions to indirect light</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<integer>8</integer>
</map>
<key>RenderReflectionProbeDrawDistance</key>
<map>

View File

@ -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;

View File

@ -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; // <FS:Beq/> 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);
}

View File

@ -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;
// <FS:Beq> Colour space and shader fixes for BUG-228586 (Rye)
//uniform sampler2D normalMap;
// </FS:Beq>
uniform sampler2D noiseMap;
uniform sampler2D lightFunc;
//uniform sampler2D depthMap;// <FS:Beq/> 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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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
}

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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
//

View File

@ -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

View File

@ -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)

View File

@ -689,7 +689,7 @@ void LLDrawPoolBump::renderBump(U32 pass)
//static
void LLDrawPoolBump::endBump(U32 pass)
{
gObjectBumpProgram.unbind();
LLGLSLShader::unbind();
gGL.setSceneBlendType(LLRender::BT_ALPHA);
}

View File

@ -358,7 +358,7 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass)
else
{
gGL.flush();
LLGLSLShader::bindNoShader();
LLGLSLShader::unbind();
}
}

View File

@ -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<LLVOWater *>(face->getViewerObject());
water = static_cast<LLVOWater*>(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()

View File

@ -195,7 +195,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
gPipeline.mBake.clear();
}
LLGLSLShader::bindNoShader();
LLGLSLShader::unbind();
LLVertexBuffer::unbind();
BOOL result = FALSE;

View File

@ -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;

View File

@ -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;

View File

@ -661,6 +661,10 @@ void LLFeatureManager::applyBaseMasks()
{
maskFeatures("VRAMGT512");
}
if (gGLManager.mVRAM < 2048)
{
maskFeatures("VRAMLT2GB");
}
if (gGLManager.mGLVersion < 3.99f)
{
maskFeatures("GL3");

View File

@ -115,3 +115,35 @@ void LLFetchedGLTFMaterial::bind()
}
}
void LLFetchedGLTFMaterial::materialBegin()
{
llassert(!mFetching);
mFetching = true;
}
void LLFetchedGLTFMaterial::onMaterialComplete(std::function<void()> 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<void()> material_complete : materialCompleteCallbacks)
{
material_complete();
}
materialCompleteCallbacks.clear();
materialCompleteCallbacks.shrink_to_fit();
}

View File

@ -39,6 +39,9 @@ public:
LLFetchedGLTFMaterial();
virtual ~LLFetchedGLTFMaterial();
// If this material is loaded, fire the given function
void onMaterialComplete(std::function<void()> material_complete);
// bind this material for rendering
void bind();
@ -49,9 +52,14 @@ public:
LLPointer<LLViewerFetchedTexture> mEmissiveTexture;
protected:
//Lifetime management
// Lifetime management
void materialBegin();
void materialComplete();
F64 mExpectedFlusTime; // since epoch in seconds
bool mActive;
bool mFetching;
std::vector<std::function<void()>> materialCompleteCallbacks;
};

View File

@ -905,6 +905,8 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
{
*(index_strider++) = vf.mIndices[i];
}
mVertexBuffer->unmapBuffer();
}

View File

@ -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<LLCheckBoxCtrl>("UseSSAO");
LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF");

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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++;
}

View File

@ -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;
}

View File

@ -152,7 +152,7 @@ void LLPanelFace::updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*
new_override = *tep->getGLTFMaterialOverride();
}
mFunc(&new_override);
LLGLTFMaterialList::queueModify(object->getID(), face, &new_override);
LLGLTFMaterialList::queueModify(object, face, &new_override);
return true;
}

View File

@ -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<F32> 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);

View File

@ -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<LLReflectionMap> 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;
};

View File

@ -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);
}

View File

@ -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
{

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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<LLViewerObject> this_ptr = this;
new_material->onMaterialComplete([this_ptr]() mutable {
if (this_ptr->isDead()) { return; }
this_ptr->rebuildMaterial();
});
}
if (update_server)
{

View File

@ -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);

View File

@ -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));

View File

@ -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;
// </FS:Ansariel>
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))
{

View File

@ -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(); // <FS:CR> 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(); // <FS:CR> 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(); // <FS:CR> 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
// <FS:Ansariel> 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
// <FS:Ansariel>
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<F32> 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(); // <FS:Ansariel> 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();
// <FS:Ansariel> Reset VB during TP
updateRenderDeferred(); // Moved further down because of exoPostProcess creating a new VB
// </FS:Ansariel>
exoPostProcess::instance().ExodusRenderPostUpdate(); // <FS:CR> 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<F32> 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)
{

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -37,7 +37,8 @@
layout="topleft"
left="10"
top="5"
width="128">
width="128"
name="base_color_lbl">
Base Color:
</text>
<texture_picker
@ -73,7 +74,8 @@
height="10"
layout="topleft"
left_pad="5"
top="8">
top="8"
name="base_color_tint_lbl">
Tint
</text>
<color_swatch
@ -94,7 +96,8 @@
layout="topleft"
left_delta="0"
top_pad="5"
width="96">
width="96"
name="base_color_transparency_lbl">
Transparency
</text>
<spinner
@ -117,10 +120,10 @@
height="10"
layout="topleft"
left_delta="0"
name="label alphamode"
text_readonly_color="LabelDisabledColor"
top_pad="5"
width="90">
width="90"
name="alpha_mode_lbl">
Alpha mode
</text>
<combo_box
@ -151,7 +154,8 @@
layout="topleft"
left_delta="0"
top_pad="5"
width="96">
width="96"
name="alpha_cutoff_lbl">
Alpha Cutoff
</text>
<spinner
@ -186,7 +190,8 @@
height="10"
layout="topleft"
left="10"
top="5">
top="5"
name="metallic_roughness_lbl">
Metallic-Roughness:
</text>
<texture_picker
@ -222,7 +227,8 @@
height="10"
layout="topleft"
left_pad="5"
top="8">
top="8"
name="metallic_factor_lbl">
Metallic Factor
</text>
<spinner
@ -246,7 +252,8 @@
layout="topleft"
left_delta="0"
top_pad="5"
width="96">
width="96"
name="roughness_factor_lbl">
Roughness Factor
</text>
<spinner
@ -282,7 +289,8 @@
layout="topleft"
left="10"
top="5"
width="64">
width="64"
name="emissive_lbl">
Emissive:
</text>
<texture_picker
@ -317,7 +325,8 @@
height="10"
layout="topleft"
left_pad="5"
top="8">
top="8"
name="emissive_tint_lbl">
Tint
</text>
<color_swatch
@ -350,7 +359,8 @@
layout="topleft"
left="10"
top="5"
width="64">
width="64"
name="normal_lbl">
Normal:
</text>
<texture_picker

View File

@ -104,6 +104,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 y Mark Adler.
Algunos iconos por Joseph Wain / glyphish.com

View File

@ -85,6 +85,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.
Il Viewer Second Life utilizza Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (e licenziatari). Tutti i diritti riservati. Per informazioni dettagliate, vedere www.havok.com.

View File

@ -30,6 +30,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.
Second Life ビューワでは Havok (TM) Physics が使用されています。(c)Copyright 1999-2010 Havok.com Inc. (and its Licensors).無断複写・複製・転載を禁じます。詳細については www.havok.com をご参照ください。

View File

@ -85,6 +85,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.
O Visualizador do Second Life usa Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (e seus Licenciantes). Todos os direitos reservados. Consulte www.havok.com para obter detalhes.

View File

@ -78,6 +78,7 @@ PCRE Telif Hakkı (c) 1997-2012 University of Cambridge
SDL Telif Hakkı (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Telif Hakkı (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Telif Hakkı (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Telif Hakkı (C) 1995-2012 Jean-loup Gailly ve Mark Adler.
Second Life Görüntüleyicisi Havok (TM) Fizik motorunu kullanmaktadır. (c)Telif Hakkı 1999-2010 Havok.com Inc. (ve Lisans Verenleri). Tüm Hakları Saklıdır. Ayrıntılı bilgi için bkz. www.havok.com

View File

@ -72,6 +72,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.
第二人生 Viewer 採用 Havok (TM) 物理引擎。 (c)Copyright 1999-2010 Havok.com Inc.(及其放照人)。 保留一切權利。 詳情見 www.havok.com。