Merge branch 'FirestormViewer:master' into FIRE-34884

master
Angeldark Raymaker 2024-12-19 09:09:16 +00:00 committed by GitHub
commit f885734ed5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
429 changed files with 32201 additions and 8378 deletions

View File

@ -2,7 +2,7 @@
# clang-format version 10.0.0+
Language: Cpp
# BasedOnStyle: Microsoft
AccessModifierOffset: -2
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: true
@ -15,14 +15,14 @@ AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortLambdasOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: None
@ -67,7 +67,7 @@ IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
IndentWrappedFunctionNames: true
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
@ -91,9 +91,9 @@ PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
@ -102,8 +102,8 @@ SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false

View File

@ -5,7 +5,11 @@
a0b3021bdcf76859054fda8e30abb3ed47749e83
8444cd9562a6a7b755fcb075864e205122354192
863c541ce0b2e3e1e566cc88423d3e87aaedb6ca
743a1a6d8eabf069d95777c96e5b657cb8702593
4a00da1ada89af6f313cee30f5177634b0b180a9
# Wrong line endings
1b67dd855c41f5a0cda7ec2a68d98071986ca703
6cc7dd09d5e69cf57e6de7fb568a0ad2693f9c9a
e2e37cced861b98de8c1a7c9c0d3a50d2d90e433
# multiple problems
5370a6d323e14d7b4e32a3f41ef78f7744e361c5

View File

@ -42,7 +42,7 @@ jobs:
needs: setup
strategy:
matrix:
runner: [windows-large, macos-12-xl]
runner: [windows-large, macos-12-large]
configuration: ${{ fromJSON(needs.setup.outputs.configurations) }}
runs-on: ${{ matrix.runner }}
outputs:

View File

@ -13,7 +13,7 @@ jobs:
steps:
- name: CLA Assistant
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
uses: secondlife-3p/contributor-assistant@v2
uses: secondlife-3p/contributor-assistant@v2.6.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PERSONAL_ACCESS_TOKEN: ${{ secrets.SHARED_CLA_TOKEN }}

View File

@ -2386,11 +2386,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>c16deaf773cb2a5d001732122ee3ec74db1dceeb</string>
<string>76444e37be0cfccdbb5921370ba150ded2bf3c59</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-darwin64-ea12248.tar.zst</string>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r1/openjpeg-2.5.2.10604495243-darwin64-10604495243.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -2400,11 +2400,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>8c277dde6076fb682cb07264dd70f6f2298b633f</string>
<string>6bd289a9c4564b80369ce40ecbb24a213c2732ff</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-linux64-ea12248.tar.zst</string>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r1/openjpeg-2.5.2.10604495243-linux64-10604495243.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@ -2414,11 +2414,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>2abf9535adf21ebdf2295f8a680300432abe6280</string>
<string>5e6e0180adc01e07438cb98daec96543b5d85019</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.0.ea12248/openjpeg-2.5.0.ea12248-windows64-ea12248.tar.zst</string>
<string>https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r1/openjpeg-2.5.2.10604495243-windows64-10604495243.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@ -2497,6 +2497,68 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>description</key>
<string>Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) Library</string>
</map>
<key>openxr</key>
<map>
<key>platforms</key>
<map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>3cccc3e3f3137066c286270b35abc00ee0c0bb0c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openxr/releases/download/v1.1.40-r1/openxr-1.1.40-r1-windows64-10710818432.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>f0ad0418a98fb8cb6e158fca3902c15ac1de9d2a</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openxr/releases/download/v1.1.40-r1/openxr-1.1.40-r1-linux64-10710818432.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>a9bfabec63a987bd34bcfdc295b928bd0696e1d7</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openxr/releases/download/v1.1.40-r1/openxr-1.1.40-r1-darwin64-10710818432.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
</map>
<key>license</key>
<string>Apache 2.0</string>
<key>license_file</key>
<string>LICENSES/openxr.txt</string>
<key>copyright</key>
<string>Copyright 2017-2024, The Khronos Group Inc.</string>
<key>version</key>
<string>1.1.40-r1</string>
<key>name</key>
<string>openxr</string>
<key>canonical_repo</key>
<string>https://github.com/secondlife/3p-openxr</string>
<key>description</key>
<string>Generated headers and sources for OpenXR loader.</string>
</map>
<key>pcre</key>
<map>
<key>platforms</key>

View File

@ -514,15 +514,6 @@ then
fi
fi
# Some of the uploads takes a long time to finish in the codeticket backend,
# causing the next codeticket upload attempt to fail.
# Inserting this after each potentially large upload may prevent those errors.
# JJ is making changes to Codeticket that we hope will eliminate this failure, then this can be removed
wait_for_codeticket()
{
sleep $(( 60 * 6 ))
}
# check status and upload results to S3
if $succeeded
then

View File

@ -1216,6 +1216,7 @@ PanteraPolnocy
SL-18937
SL-19207
SL-19681
secondlife/viewer#2483
Parvati Silverweb
Patric Mills
VWR-2645

View File

@ -84,9 +84,12 @@ if (WINDOWS)
/NODEFAULTLIB:LIBCMT
/IGNORE:4099)
add_definitions(
-DNOMINMAX
# /DDOM_DYNAMIC # For shared library colladadom
add_compile_definitions(
WIN32_LEAN_AND_MEAN
NOMINMAX
# DOM_DYNAMIC # For shared library colladadom
_CRT_SECURE_NO_WARNINGS # Allow use of sprintf etc
_WINSOCK_DEPRECATED_NO_WARNINGS # Disable deprecated WinSock API warnings
)
add_compile_options(
/Zo
@ -132,9 +135,6 @@ if (WINDOWS)
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
endif()
# Allow use of sprintf etc
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif (WINDOWS)

View File

@ -27,6 +27,7 @@ set(cmake_SOURCE_FILES
FreeType.cmake
GLEXT.cmake
GLH.cmake
GLM.cmake
GLOD.cmake # <FS:Ansariel> Bring back GLOD
Havok.cmake
Hunspell.cmake

22
indra/cmake/OpenXR.cmake Normal file
View File

@ -0,0 +1,22 @@
# -*- cmake -*-
include(Prebuilt)
include_guard()
add_library( ll::openxr INTERFACE IMPORTED )
if(USE_CONAN )
target_link_libraries( ll::openxr INTERFACE CONAN_PKG::openxr )
return()
endif()
use_prebuilt_binary(openxr)
if (WINDOWS)
target_link_libraries( ll::openxr INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/openxr_loader.lib )
else()
target_link_libraries( ll::openxr INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libopenxr_loader.a )
endif (WINDOWS)
if( NOT LINUX )
target_include_directories( ll::openxr SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
endif()

View File

@ -6,7 +6,7 @@ add_library( ll::tracy INTERFACE IMPORTED )
# default Tracy profiling on for test builds, but off for all others
string(TOLOWER ${VIEWER_CHANNEL} channel_lower)
if(WINDOWS AND channel_lower MATCHES "^second life test")
if(channel_lower MATCHES "^second life test")
option(USE_TRACY "Use Tracy profiler." ON)
else()
option(USE_TRACY "Use Tracy profiler." OFF)
@ -30,6 +30,11 @@ if (USE_TRACY)
target_compile_definitions(ll::tracy INTERFACE -DTRACY_NO_BROADCAST=1 -DTRACY_ONLY_LOCALHOST=1)
endif ()
# GHA runners don't always provide invariant TSC support, but always build with LL_TESTS enabled
if (DARWIN AND LL_TESTS)
target_compile_definitions(ll::tracy INTERFACE -DTRACY_TIMER_FALLBACK=1)
endif ()
# See: indra/llcommon/llprofiler.h
add_compile_definitions(LL_PROFILER_CONFIGURATION=3)
endif (USE_TRACY)

View File

@ -656,7 +656,7 @@ class LLManifest(object, metaclass=LLManifestRegistry):
'vers':'_'.join(self.args['version'])}
print("Creating unpacked file:", unpacked_file_name)
# could add a gz here but that doubles the time it takes to do this step
tf = tarfile.open(self.src_path_of(unpacked_file_name), 'w:')
tf = tarfile.open(self.build_path_of(unpacked_file_name), 'w:')
# add the entire installation package, at the very top level
tf.add(self.get_dst_prefix(), "")
tf.close()

View File

@ -28,8 +28,8 @@
#include "llavatarappearancedefines.h"
#include "indra_constants.h"
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 1024;
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 1024;
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 2048;
const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 2048;
using namespace LLAvatarAppearanceDefines;

View File

@ -2429,9 +2429,15 @@ void LLKeyframeMotion::onLoadComplete(const LLUUID& asset_uuid,
LLCharacter* character = *char_iter;
// look for an existing instance of this motion
LLKeyframeMotion* motionp = static_cast<LLKeyframeMotion*> (character->findMotion(asset_uuid));
if (motionp)
if (LLMotion* asset = character->findMotion(asset_uuid))
{
LLKeyframeMotion* motionp = dynamic_cast<LLKeyframeMotion*>(asset);
if (!motionp)
{
// This motion is not LLKeyframeMotion (e.g., LLEmote)
return;
}
if (0 == status)
{
if (motionp->mAssetStatus == ASSET_LOADED)

View File

@ -119,6 +119,7 @@ set(llcommon_HEADER_FILES
commoncontrol.h
ctype_workaround.h
fix_macros.h
fsyspath.h
function_types.h
indra_constants.h
lazyeventapi.h
@ -240,7 +241,6 @@ set(llcommon_HEADER_FILES
lluriparser.h
lluuid.h
llwin32headers.h
llwin32headerslean.h
llworkerthread.h
hbxxh.h
lockstatic.h

79
indra/llcommon/fsyspath.h Normal file
View File

@ -0,0 +1,79 @@
/**
* @file fsyspath.h
* @author Nat Goodspeed
* @date 2024-04-03
* @brief Adapt our UTF-8 std::strings for std::filesystem::path
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Copyright (c) 2024, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_FSYSPATH_H)
#define LL_FSYSPATH_H
#include <filesystem>
// While std::filesystem::path can be directly constructed from std::string on
// both Posix and Windows, that's not what we want on Windows. Per
// https://en.cppreference.com/w/cpp/filesystem/path/path:
// ... the method of conversion to the native character set depends on the
// character type used by source.
//
// * If the source character type is char, the encoding of the source is
// assumed to be the native narrow encoding (so no conversion takes place on
// POSIX systems).
// * If the source character type is char8_t, conversion from UTF-8 to native
// filesystem encoding is used. (since C++20)
// * If the source character type is wchar_t, the input is assumed to be the
// native wide encoding (so no conversion takes places on Windows).
// The trouble is that on Windows, from std::string ("source character type is
// char"), the "native narrow encoding" isn't UTF-8, so file paths containing
// non-ASCII characters get mangled.
//
// Once we're building with C++20, we could pass a UTF-8 std::string through a
// vector<char8_t> to engage std::filesystem::path's own UTF-8 conversion. But
// sigh, as of 2024-04-03 we're not yet there.
//
// Anyway, encapsulating the important UTF-8 conversions in our own subclass
// allows us to migrate forward to C++20 conventions without changing
// referencing code.
class fsyspath: public std::filesystem::path
{
using super = std::filesystem::path;
public:
// default
fsyspath() {}
// construct from UTF-8 encoded std::string
fsyspath(const std::string& path): super(std::filesystem::u8path(path)) {}
// construct from UTF-8 encoded const char*
fsyspath(const char* path): super(std::filesystem::u8path(path)) {}
// construct from existing path
fsyspath(const super& path): super(path) {}
fsyspath& operator=(const super& p) { super::operator=(p); return *this; }
fsyspath& operator=(const std::string& p)
{
super::operator=(std::filesystem::u8path(p));
return *this;
}
fsyspath& operator=(const char* p)
{
super::operator=(std::filesystem::u8path(p));
return *this;
}
// shadow base-class string() method with UTF-8 aware method
std::string string() const { return super::u8string(); }
// On Posix systems, where value_type is already char, this operator
// std::string() method shadows the base class operator string_type()
// method. But on Windows, where value_type is wchar_t, the base class
// doesn't have operator std::string(). Provide it.
operator std::string() const { return string(); }
};
#endif /* ! defined(LL_FSYSPATH_H) */

106
indra/llcommon/hexdump.h Executable file
View File

@ -0,0 +1,106 @@
/**
* @file hexdump.h
* @author Nat Goodspeed
* @date 2023-10-03
* @brief iostream manipulators to stream hex, or string with nonprinting chars
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Copyright (c) 2023, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_HEXDUMP_H)
#define LL_HEXDUMP_H
#include <cctype>
#include <iomanip>
#include <iostream>
#include <string_view>
namespace LL
{
// Format a given byte string as 2-digit hex values, no separators
// Usage: std::cout << hexdump(somestring) << ...
class hexdump
{
public:
hexdump(const std::string_view& data):
hexdump(data.data(), data.length())
{}
hexdump(const char* data, size_t len):
hexdump(reinterpret_cast<const unsigned char*>(data), len)
{}
hexdump(const std::vector<unsigned char>& data):
hexdump(data.data(), data.size())
{}
hexdump(const unsigned char* data, size_t len):
mData(data, data + len)
{}
friend std::ostream& operator<<(std::ostream& out, const hexdump& self)
{
auto oldfmt{ out.flags() };
auto oldfill{ out.fill() };
out.setf(std::ios_base::hex, std::ios_base::basefield);
out.fill('0');
for (auto c : self.mData)
{
out << std::setw(2) << unsigned(c);
}
out.setf(oldfmt, std::ios_base::basefield);
out.fill(oldfill);
return out;
}
private:
std::vector<unsigned char> mData;
};
// Format a given byte string as a mix of printable characters and, for each
// non-printable character, "\xnn"
// Usage: std::cout << hexmix(somestring) << ...
class hexmix
{
public:
hexmix(const std::string_view& data):
mData(data)
{}
hexmix(const char* data, size_t len):
mData(data, len)
{}
friend std::ostream& operator<<(std::ostream& out, const hexmix& self)
{
auto oldfmt{ out.flags() };
auto oldfill{ out.fill() };
out.setf(std::ios_base::hex, std::ios_base::basefield);
out.fill('0');
for (auto c : self.mData)
{
// std::isprint() must be passed an unsigned char!
if (std::isprint(static_cast<unsigned char>(c)))
{
out << c;
}
else
{
out << "\\x" << std::setw(2) << unsigned(c);
}
}
out.setf(oldfmt, std::ios_base::basefield);
out.fill(oldfill);
return out;
}
private:
std::string mData;
};
} // namespace LL
#endif /* ! defined(LL_HEXDUMP_H) */

View File

@ -88,10 +88,6 @@ LLApp* LLApp::sApplication = NULL;
// and disables crashlogger
bool LLApp::sDisableCrashlogger = false;
// Local flag for whether or not to do logging in signal handlers.
//static
bool LLApp::sLogInSignal = true;
// static
// Keeps track of application status
LLScalarCond<LLApp::EAppStatus> LLApp::sStatus{LLApp::APP_STATUS_STOPPED};
@ -226,7 +222,7 @@ bool LLApp::parseCommandOptions(int argc, wchar_t** wargv)
if(wargv[ii][0] != '-')
{
LL_INFOS() << "Did not find option identifier while parsing token: "
<< wargv[ii] << LL_ENDL;
<< (intptr_t)wargv[ii] << LL_ENDL;
return false;
}
int offset = 1;
@ -602,6 +598,10 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
// We do the somewhat sketchy operation of blocking in here until the error handler
// has gracefully stopped the app.
// FIXME(brad) - we are using this handler for asynchronous signals as well, so sLogInSignal is currently
// disabled for safety. we need to find a way to selectively reenable it when it is safe.
// see issue secondlife/viewer#2566
if (LLApp::sLogInSignal)
{
LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL;

View File

@ -339,8 +339,12 @@ private:
friend void default_unix_signal_handler(int signum, siginfo_t *info, void *);
#endif
public:
static bool sLogInSignal;
private:
#ifdef LL_RELEASE_FOR_DOWNLOAD
static constexpr bool sLogInSignal = false;
#else
static constexpr bool sLogInSignal = true;
#endif
};
#endif // LL_LLAPP_H

View File

@ -34,7 +34,7 @@
#endif
#include <boost/noncopyable.hpp>
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#include "apr_thread_proc.h"
#include "apr_getopt.h"
#include "apr_signal.h"

View File

@ -55,7 +55,7 @@ void* ll_tracy_new(size_t size)
{
throw std::bad_alloc();
}
TracyAlloc(ptr, size);
LL_PROFILE_ALLOC(ptr, size);
return ptr;
}
@ -71,7 +71,7 @@ void* operator new[](std::size_t count)
void ll_tracy_delete(void* ptr)
{
TracyFree(ptr);
LL_PROFILE_FREE(ptr);
if (gProfilerEnabled)
{
//LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
@ -103,13 +103,13 @@ void operator delete[](void* ptr) noexcept
void *tracy_aligned_malloc(size_t size, size_t alignment)
{
auto ptr = ll_aligned_malloc_fallback(size, alignment);
if (ptr) TracyAlloc(ptr, size);
if (ptr) LL_PROFILE_ALLOC(ptr, size);
return ptr;
}
void tracy_aligned_free(void *memblock)
{
TracyFree(memblock);
LL_PROFILE_FREE(memblock);
ll_aligned_free_fallback(memblock);
}

View File

@ -110,7 +110,7 @@ namespace {
virtual void recordMessage(LLError::ELevel level,
const std::string& message) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING;
int syslogPriority = LOG_CRIT;
switch (level) {
case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break;

View File

@ -34,7 +34,7 @@
#include "stringize.h"
#if LL_WINDOWS
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#include <stdlib.h> // Windows errno
#include <vector>
#else

View File

@ -89,10 +89,10 @@ private:
}
// Given arbitrary CALLABLE, which might be a lambda, how are we
// supposed to obtain its signature for std::packaged_task? It seems
// redundant to have to add an argument list to engage result_of, then
// redundant to have to add an argument list to engage invoke_result_t, then
// add the argument list again to complete the signature. At least we
// only support a nullary CALLABLE.
std::packaged_task<typename std::result_of<CALLABLE()>::type()> mTask;
std::packaged_task<std::invoke_result_t<CALLABLE>()> mTask;
};
};

View File

@ -68,10 +68,6 @@ documentation and/or software.
*/
#include "linden_common.h"
#include "llmd5.h"
@ -81,232 +77,203 @@ documentation and/or software.
// how many bytes to grab at a time when checking files
const int LLMD5::BLOCK_LEN = 4096;
// LLMD5 simple initialization method
LLMD5::LLMD5()
{
init();
init();
}
// MD5 block update operation. Continues an MD5 message-digest
// operation, processing another message block, and updating the
// context.
void LLMD5::update(const uint8_t* input, const size_t input_length)
{
size_t input_index, buffer_index;
size_t buffer_space; // how much space is left in buffer
void LLMD5::update (const uint8_t *input, const size_t input_length) {
if (finalized)
{ // so we can't update!
std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl;
return;
}
size_t input_index, buffer_index;
size_t buffer_space; // how much space is left in buffer
// Compute number of bytes mod 64
buffer_index = size_t((count >> 3) & 0x3F);
if (finalized){ // so we can't update!
std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl;
return;
}
// Update number of bits
count += input_length << 3;
// Compute number of bytes mod 64
buffer_index = size_t((count >> 3) & 0x3F);
buffer_space = 64 - buffer_index; // how much space is left in buffer
// Update number of bits
count += input_length << 3;
// now, transform each 64-byte piece of the input, bypassing the buffer
if (input == NULL || input_length == 0)
{
std::cerr << "LLMD5::update: Invalid input!" << std::endl;
return;
}
buffer_space = 64 - buffer_index; // how much space is left in buffer
// Transform as many times as possible.
if (input_length >= buffer_space) // ie. we have enough to fill the buffer
{
// fill the rest of the buffer and transform
memcpy(/* Flawfinder: ignore */
buffer + buffer_index,
input,
buffer_space);
transform(buffer);
// now, transform each 64-byte piece of the input, bypassing the buffer
if (input == NULL || input_length == 0){
std::cerr << "LLMD5::update: Invalid input!" << std::endl;
return;
}
for (input_index = buffer_space; input_index + 63 < input_length; input_index += 64)
transform(input + input_index);
// Transform as many times as possible.
if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
// fill the rest of the buffer and transform
memcpy( /* Flawfinder: ignore */
buffer + buffer_index,
input,
buffer_space);
transform (buffer);
buffer_index = 0; // so we can buffer remaining
}
else
input_index = 0; // so we can buffer the whole input
for (input_index = buffer_space; input_index + 63 < input_length;
input_index += 64)
transform (input+input_index);
buffer_index = 0; // so we can buffer remaining
}
else
input_index=0; // so we can buffer the whole input
// and here we do the buffering:
memcpy(buffer+buffer_index, input+input_index, input_length-input_index); /* Flawfinder: ignore */
// and here we do the buffering:
memcpy(buffer + buffer_index, input + input_index, input_length - input_index); /* Flawfinder: ignore */
}
// MD5 update for files.
// Like above, except that it works on files (and uses above as a primitive.)
void LLMD5::update(FILE* file)
{
unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */
int len;
void LLMD5::update(FILE* file){
unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */
int len;
while ( (len=(int)fread(buffer, 1, BLOCK_LEN, file)) )
update(buffer, len);
fclose (file);
while ((len = (int)fread(buffer, 1, BLOCK_LEN, file)))
update(buffer, len);
fclose(file);
}
// MD5 update for istreams.
// Like update for files; see above.
void LLMD5::update(std::istream& stream)
{
unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */
int len;
void LLMD5::update(std::istream& stream){
unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */
int len;
while (stream.good()){
stream.read( (char*)buffer, BLOCK_LEN); /* Flawfinder: ignore */ // note that return value of read is unusable.
len=(int)stream.gcount();
update(buffer, len);
}
while (stream.good())
{
stream.read((char*)buffer, BLOCK_LEN); /* Flawfinder: ignore */ // note that return value of read is unusable.
len = (int)stream.gcount();
update(buffer, len);
}
}
void LLMD5::update(const std::string& s)
void LLMD5::update(const std::string& s)
{
update((unsigned char *)s.c_str(),s.length());
update((unsigned char*)s.c_str(), s.length());
}
// MD5 finalization. Ends an MD5 message-digest operation, writing the
// the message digest and zeroizing the context.
void LLMD5::finalize (){
unsigned char bits[8]; /* Flawfinder: ignore */
size_t index, padLen;
static uint8_t PADDING[64]={
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
void LLMD5::finalize()
{
unsigned char bits[8]; /* Flawfinder: ignore */
size_t index, padLen;
static uint8_t PADDING[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
if (finalized){
std::cerr << "LLMD5::finalize: Already finalized this digest!" << std::endl;
return;
}
if (finalized)
{
std::cerr << "LLMD5::finalize: Already finalized this digest!" << std::endl;
return;
}
// Save number of bits.
// Treat count, a uint64_t, as uint32_t[2].
encode (bits, reinterpret_cast<uint32_t*>(&count), 8);
// Save number of bits.
// Treat count, a uint64_t, as uint32_t[2].
encode(bits, reinterpret_cast<uint32_t*>(&count), 8);
// Pad out to 56 mod 64.
index = size_t((count >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
update (PADDING, padLen);
// Pad out to 56 mod 64.
index = size_t((count >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
update(PADDING, padLen);
// Append length (before padding)
update (bits, 8);
// Append length (before padding)
update(bits, 8);
// Store state in digest
encode (digest, state, 16);
// Store state in digest
encode(digest, state, 16);
// Zeroize sensitive information
memset (buffer, 0, sizeof(*buffer));
finalized=1;
// Zeroize sensitive information
memset(buffer, 0, sizeof(buffer));
finalized = true;
}
LLMD5::LLMD5(FILE *file){
init(); // must be called be all constructors
update(file);
finalize ();
LLMD5::LLMD5(FILE* file)
{
init(); // must be called be all constructors
update(file);
finalize();
}
LLMD5::LLMD5(std::istream& stream){
init(); // must called by all constructors
update (stream);
finalize();
LLMD5::LLMD5(std::istream& stream)
{
init(); // must called by all constructors
update(stream);
finalize();
}
// Digest a string of the format ("%s:%i" % (s, number))
LLMD5::LLMD5(const unsigned char *string, const unsigned int number)
LLMD5::LLMD5(const unsigned char* string, const unsigned int number)
{
const char *colon = ":";
char tbuf[16]; /* Flawfinder: ignore */
const char* colon = ":";
char tbuf[16]; /* Flawfinder: ignore */
init();
update(string, (U32)strlen((const char *) string)); /* Flawfinder: ignore */
update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */
snprintf(tbuf, sizeof(tbuf), "%i", number); /* Flawfinder: ignore */
update((const unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */
update(string, (U32)strlen((const char*)string)); /* Flawfinder: ignore */
update((const unsigned char*)colon, (U32)strlen(colon)); /* Flawfinder: ignore */
snprintf(tbuf, sizeof(tbuf), "%i", number); /* Flawfinder: ignore */
update((const unsigned char*)tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */
finalize();
}
// Digest a string
LLMD5::LLMD5(const unsigned char *s)
LLMD5::LLMD5(const unsigned char* s)
{
init();
update(s, (U32)strlen((const char *) s)); /* Flawfinder: ignore */
update(s, (U32)strlen((const char*)s)); /* Flawfinder: ignore */
finalize();
}
void LLMD5::raw_digest(unsigned char *s) const
void LLMD5::raw_digest(unsigned char* s) const
{
if (!finalized)
{
std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "<<
"finalized the digest!" << std::endl;
std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "
<< "finalized the digest!" << std::endl;
s[0] = '\0';
return;
}
memcpy(s, digest, 16); /* Flawfinder: ignore */
return;
memcpy(s, digest, 16); /* Flawfinder: ignore */
}
void LLMD5::hex_digest(char *s) const
void LLMD5::hex_digest(char* s) const
{
int i;
if (!finalized)
{
std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "<<
"finalized the digest!" <<std::endl;
std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "
<< "finalized the digest!" << std::endl;
s[0] = '\0';
return;
}
for (i=0; i<16; i++)
for (int i = 0; i < 16; i++)
{
sprintf(s+i*2, "%02x", digest[i]); /* Flawfinder: ignore */
sprintf(s + i * 2, "%02x", digest[i]); /* Flawfinder: ignore */
}
s[32]='\0';
return;
s[32] = '\0';
}
std::ostream& operator<<(std::ostream &stream, LLMD5 context)
std::ostream& operator<<(std::ostream& stream, const LLMD5& context)
{
char s[33]; /* Flawfinder: ignore */
context.hex_digest(s);
@ -320,7 +287,7 @@ bool operator==(const LLMD5& a, const LLMD5& b)
unsigned char b_guts[16];
a.raw_digest(a_guts);
b.raw_digest(b_guts);
if (memcmp(a_guts,b_guts,16)==0)
if (memcmp(a_guts, b_guts, 16) == 0)
return true;
else
return false;
@ -328,30 +295,27 @@ bool operator==(const LLMD5& a, const LLMD5& b)
bool operator!=(const LLMD5& a, const LLMD5& b)
{
return !(a==b);
return !(a == b);
}
// PRIVATE METHODS:
void LLMD5::init()
{
finalized = false; // we just started!
void LLMD5::init(){
finalized=0; // we just started!
// Nothing counted, so count=0
count = 0;
// Nothing counted, so count=0
count = 0;
// Load magic initialization constants.
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
// Load magic initialization constants.
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
}
// Constants for MD5Transform routine.
// Although we could use C++ style constants, defines are actually better,
// since they let us easily evade scope clashes.
#define S11 7
#define S12 12
#define S13 17
@ -381,153 +345,144 @@ void LLMD5::init(){
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define FF(a, b, c, d, x, s, ac) \
{ \
(a) += F((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) \
{ \
(a) += G((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) \
{ \
(a) += H((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) \
{ \
(a) += I((b), (c), (d)) + (x) + (U32)(ac); \
(a) = ROTATE_LEFT((a), (s)); \
(a) += (b); \
}
// LLMD5 basic transformation. Transforms state based on block.
void LLMD5::transform (const U8 block[64]){
void LLMD5::transform(const U8 block[64])
{
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
decode(x, block, 64);
decode (x, block, 64);
assert(!finalized); // not just a user error, since the method is private
assert(!finalized); // not just a user error, since the method is private
/* Round 1 */
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
// Zeroize sensitive information.
memset ( (uint8_t *) x, 0, sizeof(x));
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
// Zeroize sensitive information.
memset(x, 0, sizeof(x));
}
// Encodes input (uint32_t) into output (unsigned char). Assumes len is
// a multiple of 4.
void LLMD5::encode (uint8_t *output, const uint32_t *input, const size_t len) {
size_t i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (uint8_t) (input[i] & 0xff);
output[j+1] = (uint8_t) ((input[i] >> 8) & 0xff);
output[j+2] = (uint8_t) ((input[i] >> 16) & 0xff);
output[j+3] = (uint8_t) ((input[i] >> 24) & 0xff);
}
void LLMD5::encode(uint8_t* output, const uint32_t* input, const size_t len)
{
for (size_t i = 0, j = 0; j < len; i++, j += 4)
{
output[j] = (uint8_t)(input[i] & 0xff);
output[j + 1] = (uint8_t)((input[i] >> 8) & 0xff);
output[j + 2] = (uint8_t)((input[i] >> 16) & 0xff);
output[j + 3] = (uint8_t)((input[i] >> 24) & 0xff);
}
}
// Decodes input (unsigned char) into output (uint32_t). Assumes len is
// a multiple of 4.
void LLMD5::decode (uint32_t *output, const uint8_t *input, const size_t len){
size_t i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
(((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
void LLMD5::decode(uint32_t* output, const uint8_t* input, const size_t len)
{
for (size_t i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
(((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
}

View File

@ -67,59 +67,57 @@ documentation and/or software.
*/
#include <cstdint> // uint32_t et al.
#include <cstdint> // uint32_t et al.
// use for the raw digest output
const int MD5RAW_BYTES = 16;
// use for outputting hex digests
const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null
const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null
const int MD5HEX_STR_BYTES = 32; // message system fixed size
class LL_COMMON_API LLMD5 {
// how many bytes to grab at a time when checking files
static const int BLOCK_LEN;
class LL_COMMON_API LLMD5
{
// how many bytes to grab at a time when checking files
static const int BLOCK_LEN;
public:
// methods for controlled operation:
LLMD5 (); // simple initializer
void update (const uint8_t *input, const size_t input_length);
void update (std::istream& stream);
void update (FILE *file);
void update (const std::string& str);
void finalize ();
// methods for controlled operation:
LLMD5(); // simple initializer
void update(const uint8_t* input, const size_t input_length);
void update(std::istream& stream);
void update(FILE* file);
void update(const std::string& str);
void finalize();
// constructors for special circumstances. All these constructors finalize
// the MD5 context.
LLMD5 (const unsigned char *string); // digest string, finalize
LLMD5 (std::istream& stream); // digest stream, finalize
LLMD5 (FILE *file); // digest file, close, finalize
LLMD5 (const unsigned char *string, const unsigned int number);
// constructors for special circumstances. All these constructors finalize
// the MD5 context.
LLMD5(const unsigned char* string); // digest string, finalize
LLMD5(std::istream& stream); // digest stream, finalize
LLMD5(FILE* file); // digest file, close, finalize
LLMD5(const unsigned char* string, const unsigned int number);
// methods to acquire finalized result
void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data
void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string
// methods to acquire finalized result
void raw_digest(unsigned char* array) const; // provide 16-byte array for binary data
void hex_digest(char* string) const; // provide 33-byte array for ascii-hex string
friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 context);
friend LL_COMMON_API std::ostream& operator<<(std::ostream&, const LLMD5& context);
private:
// next, the private data:
uint32_t state[4];
uint64_t count; // number of *bits*, mod 2^64
uint8_t buffer[64]; // input buffer
uint8_t digest[16];
bool finalized;
// last, the private methods, mostly static:
void init(); // called by all constructors
void transform(const uint8_t* buffer); // does the real update work. Note
// that length is implied to be 64.
// next, the private data:
uint32_t state[4];
uint64_t count; // number of *bits*, mod 2^64
uint8_t buffer[64]; // input buffer
uint8_t digest[16];
uint8_t finalized;
// last, the private methods, mostly static:
void init (); // called by all constructors
void transform (const uint8_t *buffer); // does the real update work. Note
// that length is implied to be 64.
static void encode (uint8_t *dest, const uint32_t *src, const size_t length);
static void decode (uint32_t *dest, const uint8_t *src, const size_t length);
static void encode(uint8_t* dest, const uint32_t* src, const size_t length);
static void decode(uint32_t* dest, const uint8_t* src, const size_t length);
};
LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b);

View File

@ -222,7 +222,7 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r
ll_aligned_free_16(ptr);
}
#endif
LL_PROFILE_ALLOC(ptr, size);
LL_PROFILE_ALLOC(ret, size);
return ret;
}

View File

@ -194,6 +194,18 @@ public:
mSharedMutex->unlock<SHARED>();
}
void lock()
{
if (mSharedMutex)
mSharedMutex->lock<SHARED>();
}
void unlock()
{
if (mSharedMutex)
mSharedMutex->unlock<SHARED>();
}
private:
LLSharedMutex* mSharedMutex;
};

View File

@ -418,6 +418,17 @@ private:
bool mStayUnique;
};
template<typename Type>
bool operator!=(Type* lhs, const LLPointer<Type>& rhs)
{
return (lhs != rhs.get());
}
template<typename Type>
bool operator==(Type* lhs, const LLPointer<Type>& rhs)
{
return (lhs == rhs.get());
}
// boost hash adapter
template <class Type>

View File

@ -139,7 +139,7 @@ namespace LLPredicate
Rule()
{}
void require(ENUM e, bool match)
void mandate(ENUM e, bool match)
{
mRule.set(e, match);
}
@ -154,7 +154,7 @@ namespace LLPredicate
return (mRule && value).someSet();
}
bool requires(const Value<ENUM> value) const
bool mandates(const Value<ENUM> value) const
{
return (mRule && value).someSet() && (!mRule && value).noneSet();
}

View File

@ -114,15 +114,6 @@
# define LL_THREAD_LOCAL __thread
#endif
// Static linking with apr on windows needs to be declared.
#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
#ifndef APR_DECLARE_STATIC
#define APR_DECLARE_STATIC // For APR on Windows
#endif
#ifndef APU_DECLARE_STATIC
#define APU_DECLARE_STATIC // For APR util on Windows
#endif
#endif
#if defined(LL_WINDOWS)
#define BOOST_REGEX_NO_LIB 1
@ -135,13 +126,6 @@
// Deal with VC++ problems
#if LL_MSVC
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS // disable warnings for methods considered unsafe
#endif
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS // disable deprecated WinSock API warnings
#endif
// level 4 warnings that we need to disable:
#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class
#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class

View File

@ -29,7 +29,6 @@
#include "llinitparam.h"
#include "llsdparam.h"
#include "llwin32headerslean.h"
#include "llexception.h"
#include "apr_thread_proc.h"
#include <boost/ptr_container/ptr_vector.hpp>
@ -38,7 +37,7 @@
#include <iosfwd> // std::ostream
#if LL_WINDOWS
#include "llwin32headerslean.h" // for HANDLE
#include "llwin32headers.h" // for HANDLE
#elif LL_LINUX
#if defined(Status)
#undef Status

View File

@ -34,7 +34,7 @@
//#include <memory>
#if LL_WINDOWS
# include "llwin32headerslean.h"
# include "llwin32headers.h"
# define _interlockedbittestandset _renamed_interlockedbittestandset
# define _interlockedbittestandreset _renamed_interlockedbittestandreset
# include <intrin.h>
@ -692,7 +692,8 @@ private:
memset(cpu_vendor, 0, len);
sysctlbyname("machdep.cpu.vendor", (void*)cpu_vendor, &len, NULL, 0);
cpu_vendor[0x1f] = 0;
setInfo(eVendor, cpu_vendor);
// M series CPUs don't provide this field so if empty, just fall back to Apple.
setInfo(eVendor, (cpu_vendor[0] != '\0') ? cpu_vendor : "Apple");
setInfo(eStepping, getSysctlInt("machdep.cpu.stepping"));
setInfo(eModel, getSysctlInt("machdep.cpu.model"));

View File

@ -61,12 +61,21 @@ LLSD LlsdFromJson(const boost::json::value& val)
result = LLSD(val.as_bool());
break;
case boost::json::kind::array:
{
result = LLSD::emptyArray();
for (const auto &element : val.as_array())
const boost::json::array& array = val.as_array();
size_t size = array.size();
// allocate elements 0 .. (size() - 1) to avoid incremental allocation
if (! array.empty())
{
result.append(LlsdFromJson(element));
result[size - 1] = LLSD();
}
for (size_t i = 0; i < size; i++)
{
result[i] = (LlsdFromJson(array[i]));
}
break;
}
case boost::json::kind::object:
result = LLSD::emptyMap();
for (const auto& element : val.as_object())
@ -106,6 +115,7 @@ boost::json::value LlsdToJson(const LLSD &val)
case LLSD::TypeMap:
{
boost::json::object& obj = result.emplace_object();
obj.reserve(val.size());
for (const auto& llsd_dat : llsd::inMap(val))
{
obj[llsd_dat.first] = LlsdToJson(llsd_dat.second);
@ -115,6 +125,7 @@ boost::json::value LlsdToJson(const LLSD &val)
case LLSD::TypeArray:
{
boost::json::array& json_array = result.emplace_array();
json_array.reserve(val.size());
for (const auto& llsd_dat : llsd::inArray(val))
{
json_array.push_back(LlsdToJson(llsd_dat));
@ -123,7 +134,8 @@ boost::json::value LlsdToJson(const LLSD &val)
}
case LLSD::TypeBinary:
default:
LL_ERRS("LlsdToJson") << "Unsupported conversion to JSON from LLSD type (" << val.type() << ")." << LL_ENDL;
LL_ERRS("LlsdToJson") << "Unsupported conversion to JSON from LLSD type ("
<< val.type() << ")." << LL_ENDL;
break;
}

View File

@ -32,8 +32,7 @@
#include <sstream>
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h> // for htonl
# include "llwin32headers.h" // for htonl
#elif LL_LINUX
# include <netinet/in.h>
#elif LL_DARWIN

View File

@ -32,7 +32,7 @@
#include <iostream>
#include <sstream>
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#include <dbghelp.h>
typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(

View File

@ -41,6 +41,13 @@ public:
LLStrider(Object* first) { mObjectp = first; mSkip = sizeof(Object); }
~LLStrider() { }
const LLStrider<Object>& operator=(const LLStrider<Object>& rhs)
{
mBytep = rhs.mBytep;
mSkip = rhs.mSkip;
return *this;
}
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}

View File

@ -33,8 +33,7 @@
#include <vector>
#if LL_WINDOWS
#include "llwin32headerslean.h"
#include <winnls.h> // for WideCharToMultiByte
#include "llwin32headers.h"
#endif
std::string ll_safe_string(const char* in)
@ -1482,6 +1481,14 @@ bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token
template<>
void LLStringUtil::setLocale(std::string inLocale)
{
if(startsWith(inLocale, "MissingString"))
{
// it seems this hasn't been working for some time, and I'm not sure how it is intentded to
// properly discover the correct locale. early out now to avoid failures later in
// formatNumber()
LL_WARNS() << "Failed attempting to set invalid locale: " << inLocale << LL_ENDL;
return;
}
sLocale = inLocale;
};

View File

@ -59,7 +59,7 @@
using namespace llsd;
#if LL_WINDOWS
# include "llwin32headerslean.h"
# include "llwin32headers.h"
# include <psapi.h> // GetPerformanceInfo() et al.
# include <VersionHelpers.h>
#elif LL_DARWIN

View File

@ -34,7 +34,7 @@
#include <thread>
#if LL_WINDOWS
# include "llwin32headerslean.h"
# include "llwin32headers.h"
#elif LL_LINUX || LL_DARWIN
# include <errno.h>
# include <sys/time.h>

View File

@ -25,11 +25,8 @@
#include "linden_common.h"
// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
#if LL_WINDOWS
#include "llwin32headers.h"
// ugh, this is ugly. We need to straighten out our linking for this library
#pragma comment(lib, "IPHLPAPI.lib")
#include <iphlpapi.h>
#include <nb30.h>
#endif

View File

@ -28,15 +28,8 @@
#define LL_LLWINDOWS_H
#ifdef LL_WINDOWS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#undef WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
// reset to default, which is lean
#define WIN32_LEAN_AND_MEAN
#undef NOMINMAX
#include <windows.h> // Does not include winsock.h because WIN32_LEAN_AND_MEAN is defined
#include <winsock2.h> // Requires windows.h
#endif
#endif

View File

@ -1085,7 +1085,27 @@ namespace tut
return false;
}
std::list<LLSD> mHistory;
template <typename CALLABLE>
void checkHistory(CALLABLE&& code)
{
try
{
// we expect this lambda to contain tut::ensure() calls
std::forward<CALLABLE>(code)(mHistory);
}
catch (const failure&)
{
LL_INFOS() << "event history:" << LL_ENDL;
for (const LLSD& item : mHistory)
{
LL_INFOS() << item << LL_ENDL;
}
throw;
}
}
using Listory = std::list<LLSD>;
Listory mHistory;
LLTempBoundListener mConnection;
};
@ -1136,23 +1156,26 @@ namespace tut
// finish out the run
waitfor(*py.mPy);
// now verify history
std::list<LLSD>::const_iterator li(listener.mHistory.begin()),
lend(listener.mHistory.end());
ensure("no events", li != lend);
ensure_equals("history[0]", (*li)["data"].asString(), "abc");
ensure_equals("history[0] len", (*li)["len"].asInteger(), 3);
++li;
ensure("only 1 event", li != lend);
ensure_equals("history[1]", (*li)["data"].asString(), "abcdef");
ensure_equals("history[0] len", (*li)["len"].asInteger(), 6);
++li;
ensure("only 2 events", li != lend);
ensure_equals("history[2]", (*li)["data"].asString(), "abcdefghi" EOL);
ensure_equals("history[0] len", (*li)["len"].asInteger(), 9 + sizeof(EOL) - 1);
++li;
// We DO NOT expect a whole new event for the second line because we
// disconnected.
ensure("more than 3 events", li == lend);
listener.checkHistory(
[](const EventListener::Listory& history)
{
auto li(history.begin()), lend(history.end());
ensure("no events", li != lend);
ensure_equals("history[0]", (*li)["data"].asString(), "abc");
ensure_equals("history[0] len", (*li)["len"].asInteger(), 3);
++li;
ensure("only 1 event", li != lend);
ensure_equals("history[1]", (*li)["data"].asString(), "abcdef");
ensure_equals("history[0] len", (*li)["len"].asInteger(), 6);
++li;
ensure("only 2 events", li != lend);
ensure_equals("history[2]", (*li)["data"].asString(), "abcdefghi" EOL);
ensure_equals("history[0] len", (*li)["len"].asInteger(), 9 + sizeof(EOL) - 1);
++li;
// We DO NOT expect a whole new event for the second line because we
// disconnected.
ensure("more than 3 events", li == lend);
});
}
template<> template<>
@ -1172,14 +1195,17 @@ namespace tut
// (or any other intervening layer) does crazy buffering. What we want
// to ensure is that there was exactly ONE event with "eof" true, and
// that it was the LAST event.
std::list<LLSD>::const_reverse_iterator rli(listener.mHistory.rbegin()),
rlend(listener.mHistory.rend());
ensure("no events", rli != rlend);
ensure("last event not \"eof\"", (*rli)["eof"].asBoolean());
while (++rli != rlend)
{
ensure("\"eof\" event not last", ! (*rli)["eof"].asBoolean());
}
listener.checkHistory(
[](const EventListener::Listory& history)
{
auto rli(history.rbegin()), rlend(history.rend());
ensure("no events", rli != rlend);
ensure("last event not \"eof\"", (*rli)["eof"].asBoolean());
while (++rli != rlend)
{
ensure("\"eof\" event not last", ! (*rli)["eof"].asBoolean());
}
});
}
template<> template<>
@ -1202,13 +1228,17 @@ namespace tut
ensure_equals("getLimit() after setlimit(10)", childout.getLimit(), 10);
// okay, pump I/O to pick up output from child
waitfor(*py.mPy);
ensure("no events", ! listener.mHistory.empty());
// For all we know, that data could have arrived in several different
// bursts... probably not, but anyway, only check the last one.
ensure_equals("event[\"len\"]",
listener.mHistory.back()["len"].asInteger(), abc.length());
ensure_equals("length of setLimit(10) data",
listener.mHistory.back()["data"].asString().length(), 10);
listener.checkHistory(
[abc](const EventListener::Listory& history)
{
ensure("no events", ! history.empty());
// For all we know, that data could have arrived in several different
// bursts... probably not, but anyway, only check the last one.
ensure_equals("event[\"len\"]",
history.back()["len"].asInteger(), abc.length());
ensure_equals("length of setLimit(10) data",
history.back()["data"].asString().length(), 10);
});
}
template<> template<>
@ -1275,18 +1305,22 @@ namespace tut
params.postend = pumpname;
LLProcessPtr child = LLProcess::create(params);
ensure("shouldn't have launched", ! child);
ensure_equals("number of postend events", listener.mHistory.size(), 1);
LLSD postend(listener.mHistory.front());
ensure("has id", ! postend.has("id"));
ensure_equals("desc", postend["desc"].asString(), std::string(params.desc));
ensure_equals("state", postend["state"].asInteger(), LLProcess::UNSTARTED);
ensure("has data", ! postend.has("data"));
std::string error(postend["string"]);
// All we get from canned parameter validation is a bool, so the
// "validation failed" message we ourselves generate can't mention
// "executable" by name. Just check that it's nonempty.
//ensure_contains("error", error, "executable");
ensure("string", ! error.empty());
listener.checkHistory(
[&params](const EventListener::Listory& history)
{
ensure_equals("number of postend events", history.size(), 1);
LLSD postend(history.front());
ensure("has id", ! postend.has("id"));
ensure_equals("desc", postend["desc"].asString(), std::string(params.desc));
ensure_equals("state", postend["state"].asInteger(), LLProcess::UNSTARTED);
ensure("has data", ! postend.has("data"));
std::string error(postend["string"]);
// All we get from canned parameter validation is a bool, so the
// "validation failed" message we ourselves generate can't mention
// "executable" by name. Just check that it's nonempty.
//ensure_contains("error", error, "executable");
ensure("string", ! error.empty());
});
}
template<> template<>
@ -1308,16 +1342,20 @@ namespace tut
{
yield();
}
ensure("no postend event", i < timeout);
ensure_equals("number of postend events", listener.mHistory.size(), 1);
LLSD postend(listener.mHistory.front());
ensure_equals("id", postend["id"].asInteger(), childid);
ensure("desc empty", ! postend["desc"].asString().empty());
ensure_equals("state", postend["state"].asInteger(), LLProcess::EXITED);
ensure_equals("data", postend["data"].asInteger(), 35);
std::string str(postend["string"]);
ensure_contains("string", str, "exited");
ensure_contains("string", str, "35");
listener.checkHistory(
[i, timeout, childid](const EventListener::Listory& history)
{
ensure("no postend event", i < timeout);
ensure_equals("number of postend events", history.size(), 1);
LLSD postend(history.front());
ensure_equals("id", postend["id"].asInteger(), childid);
ensure("desc empty", ! postend["desc"].asString().empty());
ensure_equals("state", postend["state"].asInteger(), LLProcess::EXITED);
ensure_equals("data", postend["data"].asInteger(), 35);
std::string str(postend["string"]);
ensure_contains("string", str, "exited");
ensure_contains("string", str, "35");
});
}
struct PostendListener

View File

@ -92,7 +92,7 @@ namespace tut
op->setReplyPath(LLCore::HttpOperation::HttpReplyQueuePtr_t(), h1);
// Check ref count
ensure(op.unique() == 1);
ensure(op.use_count() == 1);
// release the reference, releasing the operation but
// not the handlers.

View File

@ -786,6 +786,8 @@ std::vector<std::string> LLDir::findSkinnedFilenames(const std::string& subdir,
const std::string& filename,
ESkinConstraint constraint) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
// Recognize subdirs that have no localization.
static const std::set<std::string> sUnlocalized = list_of
("") // top-level directory not localized

View File

@ -179,7 +179,7 @@ private:
public:
template<bool SHARED>
class DataLock : LLSharedMutexLockTemplate<SHARED>
class DataLock : public LLSharedMutexLockTemplate<SHARED>
{
public:
DataLock(const LLImageBase* image)

View File

@ -276,16 +276,20 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r
// Estimate the number of layers. This is consistent with what's done for j2c encoding in LLImageJ2CKDU::encodeImpl().
constexpr S32 precision = 8; // assumed bitrate per component channel, might change in future for HDR support
constexpr S32 max_components = 4; // assumed the file has four components; three color and alpha
S32 nb_layers = 1;
const S32 surface = w*h;
S32 s = 64*64;
S32 totalbytes = (S32)(s * max_components * precision * rate); // first level computed before loop
while (surface > s)
// Use MAX_IMAGE_SIZE_DEFAULT (currently 2048) if either dimension is unknown (zero)
S32 width = (w > 0) ? w : 2048;
S32 height = (h > 0) ? h : 2048;
S32 max_dimension = llmax(width, height); // Find largest dimension
S32 block_area = MAX_BLOCK_SIZE * MAX_BLOCK_SIZE; // Calculated initial block area from established max block size (currently 64)
block_area *= llmax((max_dimension / MAX_BLOCK_SIZE / max_components), 1); // Adjust initial block area by ratio of largest dimension to block size per component
S32 totalbytes = (S32) (block_area * max_components * precision); // First block layer computed before loop without compression rate
S32 block_layers = 1; // Start at layer 1 since first block layer is computed outside loop
while (block_layers < 6) // Walk five layers for the five discards in JPEG2000
{
if (nb_layers <= (5 - discard_level))
totalbytes += (S32)(s * max_components * precision * rate);
nb_layers++;
s *= 4;
if (block_layers <= (5 - discard_level)) // Walk backwards from discard 5 to required discard layer.
totalbytes += (S32) (block_area * max_components * precision * rate); // Add each block layer reduced by assumed compression rate
block_layers++; // Move to next layer
block_area *= 4; // Increase block area by power of four
}
totalbytes /= 8; // to bytes

View File

@ -37,52 +37,52 @@ typedef U32 PermissionBit;
// Do you have permission to transfer ownership of the object or
// item. Fair use rules dictate that if you cannot copy, you can
// always transfer.
const PermissionBit PERM_TRANSFER = (1 << 13); // 0x00002000
constexpr PermissionBit PERM_TRANSFER = (1 << 13); // 0x00002000
// objects, scale or change textures
// parcels, allow building on it
const PermissionBit PERM_MODIFY = (1 << 14); // 0x00004000
constexpr PermissionBit PERM_MODIFY = (1 << 14); // 0x00004000
// objects, allow copy
const PermissionBit PERM_COPY = (1 << 15); // 0x00008000
constexpr PermissionBit PERM_COPY = (1 << 15); // 0x00008000
// <FS:CR> OpenSim export permission
const PermissionBit PERM_EXPORT = (1 << 16); // 0x00010000
// </FS:CR>
// parcels, allow entry, deprecated
//const PermissionBit PERM_ENTER = (1 << 16); // 0x00010000
//constexpr PermissionBit PERM_ENTER = (1 << 16); // 0x00010000
// parcels, allow terraform, deprecated
//const PermissionBit PERM_TERRAFORM = (1 << 17); // 0x00020000
//constexpr PermissionBit PERM_TERRAFORM = (1 << 17); // 0x00020000
// NOTA BENE: This flag is NO LONGER USED!!! However, it is possible that some
// objects in the universe have it set so DON"T USE IT going forward.
//const PermissionBit PERM_OWNER_DEBIT = (1 << 18); // 0x00040000
//constexpr PermissionBit PERM_OWNER_DEBIT = (1 << 18); // 0x00040000
// objects, can grab/translate/rotate
const PermissionBit PERM_MOVE = (1 << 19); // 0x00080000
constexpr PermissionBit PERM_MOVE = (1 << 19); // 0x00080000
// parcels, avatars take damage, deprecated
//const PermissionBit PERM_DAMAGE = (1 << 20); // 0x00100000
// don't use bit 31 -- printf/scanf with "%x" assume signed numbers
const PermissionBit PERM_RESERVED = ((U32)1) << 31;
constexpr PermissionBit PERM_RESERVED = ((U32)1) << 31;
const PermissionMask PERM_NONE = 0x00000000;
const PermissionMask PERM_ALL = 0x7FFFFFFF;
//const PermissionMask PERM_ALL_PARCEL = PERM_MODIFY | PERM_ENTER | PERM_TERRAFORM | PERM_DAMAGE;
const PermissionMask PERM_ITEM_UNRESTRICTED = PERM_MODIFY | PERM_COPY | PERM_TRANSFER;
constexpr PermissionMask PERM_NONE = 0x00000000;
constexpr PermissionMask PERM_ALL = 0x7FFFFFFF;
//constexpr PermissionMask PERM_ALL_PARCEL = PERM_MODIFY | PERM_ENTER | PERM_TERRAFORM | PERM_DAMAGE;
constexpr PermissionMask PERM_ITEM_UNRESTRICTED = PERM_MODIFY | PERM_COPY | PERM_TRANSFER;
// Useful stuff for transmission.
// Which permissions field are we trying to change?
const U8 PERM_BASE = 0x01;
constexpr U8 PERM_BASE = 0x01;
// TODO: Add another PERM_OWNER operation type for allowOperationBy DK 04/03/06
const U8 PERM_OWNER = 0x02;
const U8 PERM_GROUP = 0x04;
const U8 PERM_EVERYONE = 0x08;
const U8 PERM_NEXT_OWNER = 0x10;
constexpr U8 PERM_OWNER = 0x02;
constexpr U8 PERM_GROUP = 0x04;
constexpr U8 PERM_EVERYONE = 0x08;
constexpr U8 PERM_NEXT_OWNER = 0x10;
// This is just a quickie debugging key
// no modify: PERM_ALL & ~PERM_MODIFY = 0x7fffbfff

View File

@ -69,25 +69,99 @@ const U32 LLSettingsBase::Validator::VALIDATION_PARTIAL(0x01 << 0);
LLSettingsBase::LLSettingsBase():
mSettings(LLSD::emptyMap()),
mDirty(true),
mBlendedFactor(0.0)
mLLSDDirty(true),
mReplaced(false),
mBlendedFactor(0.0),
mSettingFlags(0)
{
}
LLSettingsBase::LLSettingsBase(const LLSD setting) :
mSettings(setting),
mLLSDDirty(true),
mDirty(true),
mBlendedFactor(0.0)
mReplaced(false),
mBlendedFactor(0.0),
mSettingFlags(0)
{
}
//virtual
void LLSettingsBase::loadValuesFromLLSD()
{
mLLSDDirty = false;
mAssetId = mSettings[SETTING_ASSETID].asUUID();
mSettingId = getValue(SETTING_ID).asUUID();
mSettingName = getValue(SETTING_NAME).asString();
if (mSettings.has(SETTING_FLAGS))
{
mSettingFlags = (U32)mSettings[SETTING_FLAGS].asInteger();
}
else
{
mSettingFlags = 0;
}
}
//virtual
void LLSettingsBase::saveValuesToLLSD()
{
mLLSDDirty = false;
mSettings[SETTING_NAME] = mSettingName;
if (mAssetId.isNull())
{
mSettings.erase(SETTING_ASSETID);
}
else
{
mSettings[SETTING_ASSETID] = mAssetId;
}
mSettings[SETTING_FLAGS] = LLSD::Integer(mSettingFlags);
}
void LLSettingsBase::saveValuesIfNeeded()
{
if (mLLSDDirty)
{
saveValuesToLLSD();
}
}
//=========================================================================
void LLSettingsBase::lerpSettings(const LLSettingsBase &other, F64 mix)
void LLSettingsBase::lerpSettings(LLSettingsBase &other, F64 mix)
{
mSettings = interpolateSDMap(mSettings, other.mSettings, other.getParameterMap(), mix);
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
saveValuesIfNeeded();
stringset_t skip = getSkipInterpolateKeys();
stringset_t slerps = getSlerpKeys();
mSettings = interpolateSDMap(mSettings, other.getSettings(), other.getParameterMap(), mix, skip, slerps);
setDirtyFlag(true);
loadValuesFromLLSD();
}
LLSD LLSettingsBase::combineSDMaps(const LLSD &settings, const LLSD &other) const
void LLSettingsBase::lerpVector2(LLVector2& a, const LLVector2& b, F32 mix)
{
a.mV[0] = lerp(a.mV[0], b.mV[0], mix);
a.mV[1] = lerp(a.mV[1], b.mV[1], mix);
}
void LLSettingsBase::lerpVector3(LLVector3& a, const LLVector3& b, F32 mix)
{
a.mV[0] = lerp(a.mV[0], b.mV[0], mix);
a.mV[1] = lerp(a.mV[1], b.mV[1], mix);
a.mV[2] = lerp(a.mV[2], b.mV[2], mix);
}
void LLSettingsBase::lerpColor(LLColor3& a, const LLColor3& b, F32 mix)
{
a.mV[0] = lerp(a.mV[0], b.mV[0], mix);
a.mV[1] = lerp(a.mV[1], b.mV[1], mix);
a.mV[2] = lerp(a.mV[2], b.mV[2], mix);
}
LLSD LLSettingsBase::combineSDMaps(const LLSD &settings, const LLSD &other)
{
LLSD newSettings;
@ -161,13 +235,10 @@ LLSD LLSettingsBase::combineSDMaps(const LLSD &settings, const LLSD &other) cons
return newSettings;
}
LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, F64 mix) const
LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, F64 mix, const stringset_t& skip, const stringset_t& slerps)
{
LLSD newSettings;
stringset_t skip = getSkipInterpolateKeys();
stringset_t slerps = getSlerpKeys();
llassert(mix >= 0.0f && mix <= 1.0f);
for (LLSD::map_const_iterator it = settings.beginMap(); it != settings.endMap(); ++it)
@ -204,7 +275,7 @@ LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, c
}
}
newSettings[key_name] = interpolateSDValue(key_name, value, other_value, defaults, mix, slerps);
newSettings[key_name] = interpolateSDValue(key_name, value, other_value, defaults, mix, skip, slerps);
}
// Special handling cases
@ -233,12 +304,12 @@ LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, c
if (def_iter != defaults.end())
{
// Blend against default value
newSettings[key_name] = interpolateSDValue(key_name, def_iter->second.getDefaultValue(), (*it).second, defaults, mix, slerps);
newSettings[key_name] = interpolateSDValue(key_name, def_iter->second.getDefaultValue(), (*it).second, defaults, mix, skip, slerps);
}
else if ((*it).second.type() == LLSD::TypeMap)
{
// interpolate in case there are defaults inside (part of legacy)
newSettings[key_name] = interpolateSDValue(key_name, LLSDMap(), (*it).second, defaults, mix, slerps);
newSettings[key_name] = interpolateSDValue(key_name, LLSDMap(), (*it).second, defaults, mix, skip, slerps);
}
// else do nothing when no known defaults
// TODO: Should I blend this out instead?
@ -260,7 +331,7 @@ LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, c
return newSettings;
}
LLSD LLSettingsBase::interpolateSDValue(const std::string& key_name, const LLSD &value, const LLSD &other_value, const parammapping_t& defaults, BlendFactor mix, const stringset_t& slerps) const
LLSD LLSettingsBase::interpolateSDValue(const std::string& key_name, const LLSD &value, const LLSD &other_value, const parammapping_t& defaults, BlendFactor mix, const stringset_t& skip, const stringset_t& slerps)
{
LLSD new_value;
@ -286,7 +357,7 @@ LLSD LLSettingsBase::interpolateSDValue(const std::string& key_name, const LLSD
break;
case LLSD::TypeMap:
// deep copy.
new_value = interpolateSDMap(value, other_value, defaults, mix);
new_value = interpolateSDMap(value, other_value, defaults, mix, skip, slerps);
break;
case LLSD::TypeArray:
@ -348,21 +419,24 @@ LLSettingsBase::stringset_t LLSettingsBase::getSkipInterpolateKeys() const
return skipSet;
}
LLSD LLSettingsBase::getSettings() const
LLSD& LLSettingsBase::getSettings()
{
saveValuesIfNeeded();
return mSettings;
}
LLSD LLSettingsBase::cloneSettings() const
LLSD LLSettingsBase::cloneSettings()
{
U32 flags = getFlags();
LLSD settings (combineSDMaps(getSettings(), LLSD()));
if (flags)
saveValuesIfNeeded();
LLSD settings(combineSDMaps(getSettings(), LLSD()));
if (U32 flags = getFlags())
{
settings[SETTING_FLAGS] = LLSD::Integer(flags);
}
return settings;
}
size_t LLSettingsBase::getHash() const
size_t LLSettingsBase::getHash()
{ // get a shallow copy of the LLSD filtering out values to not include in the hash
LLSD hash_settings = llsd_shallow(getSettings(),
LLSDMap(SETTING_NAME, false)(SETTING_ID, false)(SETTING_HASH, false)("*", true));
@ -380,7 +454,9 @@ bool LLSettingsBase::validate()
mSettings[SETTING_TYPE] = getSettingsType();
}
saveValuesIfNeeded();
LLSD result = LLSettingsBase::settingValidation(mSettings, validations);
loadValuesFromLLSD();
if (result["errors"].size() > 0)
{
@ -710,7 +786,7 @@ F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_
if (mTarget)
{
mTarget->replaceSettings(mInitial->getSettings());
mTarget->replaceSettings(mInitial);
mTarget->blend(mFinal, blendf);
}
else
@ -725,7 +801,7 @@ void LLSettingsBlender::triggerComplete()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
if (mTarget)
mTarget->replaceSettings(mFinal->getSettings());
mTarget->replaceSettings(mFinal);
LLSettingsBlender::ptr_t hold = shared_from_this(); // prevents this from deleting too soon
mTarget->update();
mOnFinished(shared_from_this());

View File

@ -109,72 +109,59 @@ public:
virtual bool isDirty() const { return mDirty; }
virtual bool isVeryDirty() const { return mReplaced; }
inline void setDirtyFlag(bool dirty) { mDirty = dirty; clearAssetId(); }
inline void setReplaced() { mReplaced = true; }
size_t getHash() const; // Hash will not include Name, ID or a previously stored Hash
size_t getHash(); // Hash will not include Name, ID or a previously stored Hash
inline LLUUID getId() const
{
return getValue(SETTING_ID).asUUID();
return mSettingId;
}
inline std::string getName() const
{
return getValue(SETTING_NAME).asString();
return mSettingName;
}
inline void setName(std::string val)
{
setValue(SETTING_NAME, val);
mSettingName = val;
setDirtyFlag(true);
setLLSDDirty();
}
inline LLUUID getAssetId() const
{
if (mSettings.has(SETTING_ASSETID))
return mSettings[SETTING_ASSETID].asUUID();
return LLUUID();
return mAssetId;
}
inline U32 getFlags() const
{
if (mSettings.has(SETTING_FLAGS))
return static_cast<U32>(mSettings[SETTING_FLAGS].asInteger());
return 0;
return mSettingFlags;
}
inline void setFlags(U32 value)
{
setLLSD(SETTING_FLAGS, LLSD::Integer(value));
mSettingFlags = value;
setDirtyFlag(true);
setLLSDDirty();
}
inline bool getFlag(U32 flag) const
{
if (mSettings.has(SETTING_FLAGS))
return ((U32)mSettings[SETTING_FLAGS].asInteger() & flag) == flag;
return false;
return (mSettingFlags & flag) == flag;
}
inline void setFlag(U32 flag)
{
U32 flags((mSettings.has(SETTING_FLAGS)) ? (U32)mSettings[SETTING_FLAGS].asInteger() : 0);
flags |= flag;
if (flags)
mSettings[SETTING_FLAGS] = LLSD::Integer(flags);
else
mSettings.erase(SETTING_FLAGS);
mSettingFlags |= flag;
setLLSDDirty();
}
inline void clearFlag(U32 flag)
{
U32 flags((mSettings.has(SETTING_FLAGS)) ? (U32)mSettings[SETTING_FLAGS].asInteger() : 0);
flags &= ~flag;
if (flags)
mSettings[SETTING_FLAGS] = LLSD::Integer(flags);
else
mSettings.erase(SETTING_FLAGS);
mSettingFlags &= ~flag;
setLLSDDirty();
}
virtual void replaceSettings(LLSD settings)
@ -183,14 +170,41 @@ public:
setDirtyFlag(true);
mReplaced = true;
mSettings = settings;
loadValuesFromLLSD();
}
virtual LLSD getSettings() const;
virtual void replaceSettings(const ptr_t& other)
{
mBlendedFactor = 0.0;
setDirtyFlag(true);
mReplaced = true;
mSettingFlags = other->getFlags();
mSettingName = other->getName();
mSettingId = other->getId();
mAssetId = other->getAssetId();
setLLSDDirty();
}
void setSettings(LLSD settings)
{
setDirtyFlag(true);
mSettings = settings;
loadValuesFromLLSD();
}
// if you are using getSettings to edit them, call setSettings(settings),
// replaceSettings(settings) or loadValuesFromLLSD() afterwards
virtual LLSD& getSettings();
virtual void setLLSDDirty()
{
mLLSDDirty = true;
}
//---------------------------------------------------------------------
//
inline void setLLSD(const std::string &name, const LLSD &value)
{
saveValuesIfNeeded();
mSettings[name] = value;
mDirty = true;
if (name != SETTING_ASSETID)
@ -202,8 +216,9 @@ public:
setLLSD(name, value);
}
inline LLSD getValue(const std::string &name, const LLSD &deflt = LLSD()) const
inline LLSD getValue(const std::string &name, const LLSD &deflt = LLSD())
{
saveValuesIfNeeded();
if (!mSettings.has(name))
return deflt;
return mSettings[name];
@ -259,11 +274,11 @@ public:
(const_cast<LLSettingsBase *>(this))->updateSettings();
}
virtual void blend(const ptr_t &end, BlendFactor blendf) = 0;
virtual void blend(ptr_t &end, BlendFactor blendf) = 0;
virtual bool validate();
virtual ptr_t buildDerivedClone() const = 0;
virtual ptr_t buildDerivedClone() = 0;
class Validator
{
@ -310,17 +325,24 @@ public:
inline void setAssetId(LLUUID value)
{ // note that this skips setLLSD
mSettings[SETTING_ASSETID] = value;
mAssetId = value;
mLLSDDirty = true;
}
inline void clearAssetId()
{
if (mSettings.has(SETTING_ASSETID))
mSettings.erase(SETTING_ASSETID);
mAssetId.setNull();
mLLSDDirty = true;
}
// Calculate any custom settings that may need to be cached.
virtual void updateSettings() { mDirty = false; mReplaced = false; }
LLSD cloneSettings();
static void lerpVector2(LLVector2& a, const LLVector2& b, F32 mix);
static void lerpVector3(LLVector3& a, const LLVector3& b, F32 mix);
static void lerpColor(LLColor3& a, const LLColor3& b, F32 mix);
protected:
LLSettingsBase();
@ -331,7 +353,7 @@ protected:
typedef std::set<std::string> stringset_t;
// combining settings objects. Customize for specific setting types
virtual void lerpSettings(const LLSettingsBase &other, BlendFactor mix);
virtual void lerpSettings(LLSettingsBase &other, BlendFactor mix);
// combining settings maps where it can based on mix rate
// @settings initial value (mix==0)
@ -339,8 +361,8 @@ protected:
// @defaults list of default values for legacy fields and (re)setting shaders
// @mix from 0 to 1, ratio or rate of transition from initial 'settings' to 'other'
// return interpolated and combined LLSD map
LLSD interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, BlendFactor mix) const;
LLSD interpolateSDValue(const std::string& name, const LLSD &value, const LLSD &other, const parammapping_t& defaults, BlendFactor mix, const stringset_t& slerps) const;
static LLSD interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, BlendFactor mix, const stringset_t& skip, const stringset_t& slerps);
static LLSD interpolateSDValue(const std::string& name, const LLSD &value, const LLSD &other, const parammapping_t& defaults, BlendFactor mix, const stringset_t& skip, const stringset_t& slerps);
/// when lerping between settings, some may require special handling.
/// Get a list of these key to be skipped by the default settings lerp.
@ -353,32 +375,40 @@ protected:
virtual validation_list_t getValidationList() const = 0;
// Apply any settings that need special handling.
virtual void applySpecial(void *, bool force = false) { };
// Apply settings.
virtual void applyToUniforms(void *) { };
virtual void applySpecial(void*, bool force = false) { };
virtual parammapping_t getParameterMap() const { return parammapping_t(); }
LLSD mSettings;
LLSD cloneSettings() const;
inline void setBlendFactor(BlendFactor blendfactor)
{
mBlendedFactor = blendfactor;
}
void replaceWith(LLSettingsBase::ptr_t other)
virtual void replaceWith(const LLSettingsBase::ptr_t other)
{
replaceSettings(other->cloneSettings());
replaceSettings(other);
setBlendFactor(other->getBlendFactor());
}
virtual void loadValuesFromLLSD();
virtual void saveValuesToLLSD();
void saveValuesIfNeeded();
LLUUID mAssetId;
LLUUID mSettingId;
std::string mSettingName;
U32 mSettingFlags;
private:
bool mLLSDDirty;
bool mDirty;
bool mReplaced; // super dirty!
LLSD combineSDMaps(const LLSD &first, const LLSD &other) const;
static LLSD combineSDMaps(const LLSD &first, const LLSD &other);
LLSD mSettings;
BlendFactor mBlendedFactor;
};

View File

@ -125,33 +125,38 @@ static const F32 DEFAULT_MULTISLIDER_INCREMENT(0.005f);
//=========================================================================
LLSettingsDay::LLSettingsDay(const LLSD &data) :
LLSettingsBase(data),
mInitialized(false)
mInitialized(false),
mDaySettings(LLSD::emptyMap())
{
mDayTracks.resize(TRACK_MAX);
loadValuesFromLLSD();
}
LLSettingsDay::LLSettingsDay() :
LLSettingsBase(),
mInitialized(false)
mInitialized(false),
mDaySettings(LLSD::emptyMap())
{
mDayTracks.resize(TRACK_MAX);
replaceSettings(defaults());
}
//=========================================================================
LLSD LLSettingsDay::getSettings() const
LLSD& LLSettingsDay::getSettings()
{
LLSD settings(LLSD::emptyMap());
mDaySettings = LLSD::emptyMap();
LLSD& settings = LLSettingsBase::getSettings();
if (mSettings.has(SETTING_NAME))
settings[SETTING_NAME] = mSettings[SETTING_NAME];
if (settings.has(SETTING_NAME))
mDaySettings[SETTING_NAME] = settings[SETTING_NAME];
if (mSettings.has(SETTING_ID))
settings[SETTING_ID] = mSettings[SETTING_ID];
if (settings.has(SETTING_ID))
mDaySettings[SETTING_ID] = settings[SETTING_ID];
if (mSettings.has(SETTING_ASSETID))
settings[SETTING_ASSETID] = mSettings[SETTING_ASSETID];
if (settings.has(SETTING_ASSETID))
mDaySettings[SETTING_ASSETID] = settings[SETTING_ASSETID];
settings[SETTING_TYPE] = getSettingsType();
mDaySettings[SETTING_TYPE] = getSettingsType();
std::map<std::string, LLSettingsBase::ptr_t> in_use;
@ -175,7 +180,7 @@ LLSD LLSettingsDay::getSettings() const
}
tracks.append(trackout);
}
settings[SETTING_TRACKS] = tracks;
mDaySettings[SETTING_TRACKS] = tracks;
LLSD frames(LLSD::emptyMap());
for (std::map<std::string, LLSettingsBase::ptr_t>::iterator itFrame = in_use.begin(); itFrame != in_use.end(); ++itFrame)
@ -185,9 +190,15 @@ LLSD LLSettingsDay::getSettings() const
frames[(*itFrame).first] = framesettings;
}
settings[SETTING_FRAMES] = frames;
mDaySettings[SETTING_FRAMES] = frames;
return settings;
return mDaySettings;
}
void LLSettingsDay::setLLSDDirty()
{
mDaySettings = LLSD::emptyMap();
LLSettingsBase::setLLSDDirty();
}
bool LLSettingsDay::initialize(bool validate_frames)
@ -393,6 +404,8 @@ bool LLSettingsDay::initialize(bool validate_frames)
mSettings[SETTING_ASSETID] = assetid;
}
loadValuesFromLLSD();
mInitialized = true;
return true;
}
@ -450,7 +463,7 @@ LLSD LLSettingsDay::defaults()
return dfltsetting;
}
void LLSettingsDay::blend(const LLSettingsBase::ptr_t &other, F64 mix)
void LLSettingsDay::blend(LLSettingsBase::ptr_t &other, F64 mix)
{
LL_ERRS("DAYCYCLE") << "Day cycles are not blendable!" << LL_ENDL;
}

View File

@ -82,9 +82,10 @@ public:
bool initialize(bool validate_frames = false);
virtual ptr_t buildClone() const = 0;
virtual ptr_t buildDeepCloneAndUncompress() const = 0;
virtual LLSD getSettings() const SETTINGS_OVERRIDE;
virtual ptr_t buildClone() = 0;
virtual ptr_t buildDeepCloneAndUncompress() = 0;
virtual LLSD& getSettings() SETTINGS_OVERRIDE;
virtual void setLLSDDirty() override;
virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_DAYCYCLE; }
@ -92,7 +93,7 @@ public:
virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("daycycle"); }
// Settings status
virtual void blend(const LLSettingsBase::ptr_t &other, F64 mix) SETTINGS_OVERRIDE;
virtual void blend(LLSettingsBase::ptr_t &other, F64 mix) SETTINGS_OVERRIDE;
static LLSD defaults();
@ -128,7 +129,7 @@ public:
virtual validation_list_t getValidationList() const SETTINGS_OVERRIDE;
static validation_list_t validationList();
virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); }
virtual LLSettingsBase::ptr_t buildDerivedClone() SETTINGS_OVERRIDE { return buildClone(); }
LLSettingsBase::TrackPosition getUpperBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe);
LLSettingsBase::TrackPosition getLowerBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe);
@ -144,6 +145,7 @@ protected:
private:
CycleList_t mDayTracks;
LLSD mDaySettings;
LLSettingsBase::Seconds mLastUpdateTime;

File diff suppressed because it is too large Load Diff

View File

@ -111,20 +111,24 @@ public:
LLSettingsSky(const LLSD &data);
virtual ~LLSettingsSky() { };
virtual ptr_t buildClone() const = 0;
virtual ptr_t buildClone() = 0;
//---------------------------------------------------------------------
virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("sky"); }
virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_SKY; }
// Settings status
virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE;
virtual void blend(LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE;
virtual void replaceSettings(LLSD settings) SETTINGS_OVERRIDE;
virtual void replaceSettings(const LLSettingsBase::ptr_t& other_sky) override;
void replaceWithSky(LLSettingsSky::ptr_t pother);
void replaceWithSky(const LLSettingsSky::ptr_t& pother);
static LLSD defaults(const LLSettingsBase::TrackPosition& position = 0.0f);
void loadValuesFromLLSD() override;
void saveValuesToLLSD() override;
F32 getPlanetRadius() const;
F32 getSkyBottomRadius() const;
F32 getSkyTopRadius() const;
@ -205,6 +209,12 @@ public:
F32 getGamma() const;
F32 getHDRMin() const;
F32 getHDRMax() const;
F32 getHDROffset() const;
F32 getTonemapMix() const;
void setTonemapMix(F32 mix);
void setGamma(F32 val);
LLColor3 getGlow() const;
@ -306,7 +316,7 @@ public:
LLColor3 getSunlightColorClamped() const;
LLColor3 getAmbientColorClamped() const;
virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); }
virtual LLSettingsBase::ptr_t buildDerivedClone() SETTINGS_OVERRIDE { return buildClone(); }
static LLUUID GetDefaultAssetId();
static LLUUID GetDefaultSunTextureId();
@ -348,6 +358,12 @@ protected:
virtual stringset_t getSlerpKeys() const SETTINGS_OVERRIDE;
virtual stringset_t getSkipInterpolateKeys() const SETTINGS_OVERRIDE;
LLUUID mSunTextureId;
LLUUID mMoonTextureId;
LLUUID mCloudTextureId;
LLUUID mBloomTextureId;
LLUUID mRainbowTextureId;
LLUUID mHaloTextureId;
LLUUID mNextSunTextureId;
LLUUID mNextMoonTextureId;
LLUUID mNextCloudTextureId;
@ -355,17 +371,68 @@ protected:
LLUUID mNextRainbowTextureId;
LLUUID mNextHaloTextureId;
bool mCanAutoAdjust;
LLQuaternion mSunRotation;
LLQuaternion mMoonRotation;
LLColor3 mSunlightColor;
LLColor3 mGlow;
F32 mReflectionProbeAmbiance;
F32 mSunScale;
F32 mStarBrightness;
F32 mMoonBrightness;
F32 mMoonScale;
F32 mMaxY;
F32 mGamma;
F32 mCloudVariance;
F32 mCloudShadow;
F32 mCloudScale;
F32 mTonemapMix;
F32 mHDROffset;
F32 mHDRMax;
F32 mHDRMin;
LLVector2 mScrollRate;
LLColor3 mCloudPosDensity1;
LLColor3 mCloudPosDensity2;
LLColor3 mCloudColor;
LLSD mAbsorptionConfigs;
LLSD mMieConfigs;
LLSD mRayleighConfigs;
F32 mSunArcRadians;
F32 mSkyTopRadius;
F32 mSkyBottomRadius;
F32 mSkyMoistureLevel;
F32 mSkyDropletRadius;
F32 mSkyIceLevel;
F32 mPlanetRadius;
F32 mHazeHorizon;
F32 mHazeDensity;
F32 mDistanceMultiplier;
F32 mDensityMultiplier;
LLColor3 mBlueHorizon;
LLColor3 mBlueDensity;
LLColor3 mAmbientColor;
bool mHasLegacyHaze;
bool mLegacyHazeHorizon;
bool mLegacyHazeDensity;
bool mLegacyDistanceMultiplier;
bool mLegacyDensityMultiplier;
bool mLegacyBlueHorizon;
bool mLegacyBlueDensity;
bool mLegacyAmbientColor;
private:
static LLSD rayleighConfigDefault();
static LLSD absorptionConfigDefault();
static LLSD mieConfigDefault();
LLColor3 getColor(const std::string& key, const LLColor3& default_value) const;
F32 getFloat(const std::string& key, F32 default_value) const;
LLColor3 getColor(const std::string& key, const LLColor3& default_value);
F32 getFloat(const std::string& key, F32 default_value);
void calculateHeavenlyBodyPositions() const;
void calculateLightSettings() const;
void clampColor(LLColor3& color, F32 gamma, const F32 scale = 1.0f) const;
static void clampColor(LLColor3& color, F32 gamma, const F32 scale = 1.0f);
mutable LLVector3 mSunDirection;
mutable LLVector3 mMoonDirection;

View File

@ -68,14 +68,18 @@ static const LLUUID DEFAULT_OPAQUE_WATER_TEXTURE("43c32285-d658-1793-c123-bf8631
//=========================================================================
LLSettingsWater::LLSettingsWater(const LLSD &data) :
LLSettingsBase(data),
mNextNormalMapID()
mNextNormalMapID(),
mNextTransparentTextureID()
{
loadValuesFromLLSD();
}
LLSettingsWater::LLSettingsWater() :
LLSettingsBase(),
mNextNormalMapID()
mNextNormalMapID(),
mNextTransparentTextureID()
{
replaceSettings(defaults());
}
//=========================================================================
@ -109,6 +113,53 @@ LLSD LLSettingsWater::defaults(const LLSettingsBase::TrackPosition& position)
return dfltsetting;
}
void LLSettingsWater::loadValuesFromLLSD()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
LLSettingsBase::loadValuesFromLLSD();
LLSD& settings = getSettings();
mBlurMultiplier = (F32)settings[SETTING_BLUR_MULTIPLIER].asReal();
mWaterFogColor = LLColor3(settings[SETTING_FOG_COLOR]);
mWaterFogDensity = (F32)settings[SETTING_FOG_DENSITY].asReal();
mFogMod = (F32)settings[SETTING_FOG_MOD].asReal();
mFresnelOffset = (F32)settings[SETTING_FRESNEL_OFFSET].asReal();
mFresnelScale = (F32)settings[SETTING_FRESNEL_SCALE].asReal();
mNormalScale = LLVector3(settings[SETTING_NORMAL_SCALE]);
mScaleAbove = (F32)settings[SETTING_SCALE_ABOVE].asReal();
mScaleBelow = (F32)settings[SETTING_SCALE_BELOW].asReal();
mWave1Dir = LLVector2(settings[SETTING_WAVE1_DIR]);
mWave2Dir = LLVector2(settings[SETTING_WAVE2_DIR]);
mNormalMapID = settings[SETTING_NORMAL_MAP].asUUID();
mTransparentTextureID = settings[SETTING_TRANSPARENT_TEXTURE].asUUID();
}
void LLSettingsWater::saveValuesToLLSD()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
LLSettingsBase::saveValuesToLLSD();
LLSD & settings = getSettings();
settings[SETTING_BLUR_MULTIPLIER] = LLSD::Real(mBlurMultiplier);
settings[SETTING_FOG_COLOR] = mWaterFogColor.getValue();
settings[SETTING_FOG_DENSITY] = LLSD::Real(mWaterFogDensity);
settings[SETTING_FOG_MOD] = LLSD::Real(mFogMod);
settings[SETTING_FRESNEL_OFFSET] = LLSD::Real(mFresnelOffset);
settings[SETTING_FRESNEL_SCALE] = LLSD::Real(mFresnelScale);
settings[SETTING_NORMAL_SCALE] = mNormalScale.getValue();
settings[SETTING_SCALE_ABOVE] = LLSD::Real(mScaleAbove);
settings[SETTING_SCALE_BELOW] = LLSD::Real(mScaleBelow);
settings[SETTING_WAVE1_DIR] = mWave1Dir.getValue();
settings[SETTING_WAVE2_DIR] = mWave2Dir.getValue();
settings[SETTING_NORMAL_MAP] = mNormalMapID;
settings[SETTING_TRANSPARENT_TEXTURE] = mTransparentTextureID;
}
LLSD LLSettingsWater::translateLegacySettings(LLSD legacy)
{
bool converted_something(false);
@ -180,13 +231,30 @@ LLSD LLSettingsWater::translateLegacySettings(LLSD legacy)
return newsettings;
}
void LLSettingsWater::blend(const LLSettingsBase::ptr_t &end, F64 blendf)
void LLSettingsWater::blend(LLSettingsBase::ptr_t &end, F64 blendf)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
LLSettingsWater::ptr_t other = PTR_NAMESPACE::static_pointer_cast<LLSettingsWater>(end);
if (other)
{
LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, other->getParameterMap(), blendf);
replaceSettings(blenddata);
mSettingFlags |= other->mSettingFlags;
mBlurMultiplier = lerp(mBlurMultiplier, other->mBlurMultiplier, (F32)blendf);
lerpColor(mWaterFogColor, other->mWaterFogColor, (F32)blendf);
mWaterFogDensity = lerp(mWaterFogDensity, other->mWaterFogDensity, (F32)blendf);
mFogMod = lerp(mFogMod, other->mFogMod, (F32)blendf);
mFresnelOffset = lerp(mFresnelOffset, other->mFresnelOffset, (F32)blendf);
mFresnelScale = lerp(mFresnelScale, other->mFresnelScale, (F32)blendf);
lerpVector3(mNormalScale, other->mNormalScale, (F32)blendf);
mScaleAbove = lerp(mScaleAbove, other->mScaleAbove, (F32)blendf);
mScaleBelow = lerp(mScaleBelow, other->mScaleBelow, (F32)blendf);
lerpVector2(mWave1Dir, other->mWave1Dir, (F32)blendf);
lerpVector2(mWave2Dir, other->mWave2Dir, (F32)blendf);
setDirtyFlag(true);
setReplaced();
setLLSDDirty();
mNextNormalMapID = other->getNormalMapID();
mNextTransparentTextureID = other->getTransparentTextureID();
}
@ -204,7 +272,34 @@ void LLSettingsWater::replaceSettings(LLSD settings)
mNextTransparentTextureID.setNull();
}
void LLSettingsWater::replaceWithWater(LLSettingsWater::ptr_t other)
void LLSettingsWater::replaceSettings(const LLSettingsBase::ptr_t& other_water)
{
LLSettingsBase::replaceSettings(other_water);
llassert(getSettingsType() == other_water->getSettingsType());
LLSettingsWater::ptr_t other = PTR_NAMESPACE::dynamic_pointer_cast<LLSettingsWater>(other_water);
mBlurMultiplier = other->mBlurMultiplier;
mWaterFogColor = other->mWaterFogColor;
mWaterFogDensity = other->mWaterFogDensity;
mFogMod = other->mFogMod;
mFresnelOffset = other->mFresnelOffset;
mFresnelScale = other->mFresnelScale;
mNormalScale = other->mNormalScale;
mScaleAbove = other->mScaleAbove;
mScaleBelow = other->mScaleBelow;
mWave1Dir = other->mWave1Dir;
mWave2Dir = other->mWave2Dir;
mNormalMapID = other->mNormalMapID;
mTransparentTextureID = other->mTransparentTextureID;
mNextNormalMapID.setNull();
mNextTransparentTextureID.setNull();
}
void LLSettingsWater::replaceWithWater(const LLSettingsWater::ptr_t& other)
{
replaceWith(other);

View File

@ -55,151 +55,181 @@ public:
LLSettingsWater(const LLSD &data);
virtual ~LLSettingsWater() { };
virtual ptr_t buildClone() const = 0;
virtual ptr_t buildClone() = 0;
//---------------------------------------------------------------------
virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("water"); }
virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_WATER; }
// Settings status
virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE;
virtual void blend(LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE;
virtual void replaceSettings(LLSD settings) SETTINGS_OVERRIDE;
void replaceWithWater(LLSettingsWater::ptr_t other);
virtual void replaceSettings(const LLSettingsBase::ptr_t& other_water) override;
void replaceWithWater(const LLSettingsWater::ptr_t& other);
static LLSD defaults(const LLSettingsBase::TrackPosition& position = 0.0f);
void loadValuesFromLLSD() override;
void saveValuesToLLSD() override;
//---------------------------------------------------------------------
F32 getBlurMultiplier() const
{
return (F32)mSettings[SETTING_BLUR_MULTIPLIER].asReal();
return mBlurMultiplier;
}
void setBlurMultiplier(F32 val)
{
setValue(SETTING_BLUR_MULTIPLIER, val);
mBlurMultiplier = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLColor3 getWaterFogColor() const
{
return LLColor3(mSettings[SETTING_FOG_COLOR]);
return mWaterFogColor;
}
void setWaterFogColor(LLColor3 val)
{
setValue(SETTING_FOG_COLOR, val);
mWaterFogColor = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getWaterFogDensity() const
{
return (F32)mSettings[SETTING_FOG_DENSITY].asReal();
return mWaterFogDensity;
}
F32 getModifiedWaterFogDensity(bool underwater) const;
void setWaterFogDensity(F32 val)
{
setValue(SETTING_FOG_DENSITY, val);
mWaterFogDensity = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getFogMod() const
{
return (F32)mSettings[SETTING_FOG_MOD].asReal();
return mFogMod;
}
void setFogMod(F32 val)
{
setValue(SETTING_FOG_MOD, val);
mFogMod = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getFresnelOffset() const
{
return (F32)mSettings[SETTING_FRESNEL_OFFSET].asReal();
return mFresnelOffset;
}
void setFresnelOffset(F32 val)
{
setValue(SETTING_FRESNEL_OFFSET, val);
mFresnelOffset = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getFresnelScale() const
{
return (F32)mSettings[SETTING_FRESNEL_SCALE].asReal();
return mFresnelScale;
}
void setFresnelScale(F32 val)
{
setValue(SETTING_FRESNEL_SCALE, val);
mFresnelScale = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLUUID getTransparentTextureID() const
{
return mSettings[SETTING_TRANSPARENT_TEXTURE].asUUID();
return mTransparentTextureID;
}
void setTransparentTextureID(LLUUID val)
{
setValue(SETTING_TRANSPARENT_TEXTURE, val);
mTransparentTextureID = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLUUID getNormalMapID() const
{
return mSettings[SETTING_NORMAL_MAP].asUUID();
return mNormalMapID;
}
void setNormalMapID(LLUUID val)
{
setValue(SETTING_NORMAL_MAP, val);
mNormalMapID = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLVector3 getNormalScale() const
{
return LLVector3(mSettings[SETTING_NORMAL_SCALE]);
return mNormalScale;
}
void setNormalScale(LLVector3 val)
{
setValue(SETTING_NORMAL_SCALE, val);
mNormalScale = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getScaleAbove() const
{
return (F32)mSettings[SETTING_SCALE_ABOVE].asReal();
return mScaleAbove;
}
void setScaleAbove(F32 val)
{
setValue(SETTING_SCALE_ABOVE, val);
mScaleAbove = val;
setDirtyFlag(true);
setLLSDDirty();
}
F32 getScaleBelow() const
{
return (F32)mSettings[SETTING_SCALE_BELOW].asReal();
return mScaleBelow;
}
void setScaleBelow(F32 val)
{
setValue(SETTING_SCALE_BELOW, val);
mScaleBelow = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLVector2 getWave1Dir() const
{
return LLVector2(mSettings[SETTING_WAVE1_DIR]);
return mWave1Dir;
}
void setWave1Dir(LLVector2 val)
{
setValue(SETTING_WAVE1_DIR, val);
mWave1Dir = val;
setDirtyFlag(true);
setLLSDDirty();
}
LLVector2 getWave2Dir() const
{
return LLVector2(mSettings[SETTING_WAVE2_DIR]);
return mWave2Dir;
}
void setWave2Dir(LLVector2 val)
{
setValue(SETTING_WAVE2_DIR, val);
mWave2Dir = val;
setDirtyFlag(true);
setLLSDDirty();
}
//-------------------------------------------
@ -218,7 +248,7 @@ public:
static LLSD translateLegacySettings(LLSD legacy);
virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); }
virtual LLSettingsBase::ptr_t buildDerivedClone() SETTINGS_OVERRIDE { return buildClone(); }
static LLUUID GetDefaultAssetId();
static LLUUID GetDefaultWaterNormalAssetId();
@ -241,9 +271,22 @@ protected:
LLSettingsWater();
LLUUID mTransparentTextureID;
LLUUID mNormalMapID;
LLUUID mNextTransparentTextureID;
LLUUID mNextNormalMapID;
F32 mBlurMultiplier;
LLColor3 mWaterFogColor;
F32 mWaterFogDensity;
F32 mFogMod;
F32 mFresnelOffset;
F32 mFresnelScale;
LLVector3 mNormalScale;
F32 mScaleAbove;
F32 mScaleBelow;
LLVector2 mWave1Dir;
LLVector2 mWave2Dir;
};
#endif

View File

@ -66,6 +66,10 @@ public:
const LLJointRiggingInfo& operator[](S32 i) const { return mRigInfoPtr[i]; };
bool needsUpdate() { return mNeedsUpdate; }
void setNeedsUpdate(bool val) { mNeedsUpdate = val; }
LLJointRiggingInfo* begin() { return mRigInfoPtr; }
LLJointRiggingInfo* end() { return mRigInfoPtr + mSize; }
private:
// Not implemented
LLJointRiggingInfoTab& operator=(const LLJointRiggingInfoTab& src);

View File

@ -38,8 +38,7 @@
#include "v4color.h"
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h> // for htonl
# include "llwin32headers.h" // for htonl
#elif LL_LINUX
# include <netinet/in.h>
#elif LL_DARWIN

View File

@ -2730,7 +2730,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
}
bool LLVolume::isMeshAssetLoaded()
bool LLVolume::isMeshAssetLoaded() const
{
return mIsMeshAssetLoaded;
}
@ -2753,7 +2753,7 @@ void LLVolume::setMeshAssetUnavaliable(bool unavaliable)
}
}
bool LLVolume::isMeshAssetUnavaliable()
bool LLVolume::isMeshAssetUnavaliable() const
{
return mIsMeshAssetUnavaliable;
}
@ -3779,6 +3779,207 @@ S32 LLVolume::getNumTriangles(S32* vcount) const
return triangle_count;
}
void LLVolumeFace::generateSilhouetteEdge(const LLVolume* volume, std::vector<S32>& edge) const
{
llassert(edge.empty()); // edge is supposed to be a scratch array
if (volume->isMeshAssetLoaded()) { return; }
if (mTypeMask & CAP_MASK)
{
// Logic copied from LLVolumeFace::createCap - indicates a face created via
// createUnCutCubeCap.
if (!(mTypeMask & HOLLOW_MASK) &&
!(mTypeMask & OPEN_MASK) &&
((volume->getParams().getPathParams().getBegin()==0.0f)&&
(volume->getParams().getPathParams().getEnd()==1.0f))&&
(volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE &&
volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE)
)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfgse - CAP_MASK");
const LLAlignedArray<LLVector4a,64>& profile = volume->getProfile().mProfile;
S32 grid_size = (profile.size()-1)/4;
edge.resize(mNumIndices);
llassert(edge.size() == 6*grid_size*grid_size);
S32 cur_edge = 0;
for(S32 gx = 0;gx<grid_size;gx++)
{
for(S32 gy = 0;gy<grid_size;gy++)
{
if (mTypeMask & TOP_MASK)
{
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gx > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1; // Mark face to higlight it
}
if (gy < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
if (gx < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
if (gy > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
}
else
{
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gy > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
if (gx < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
if (gy < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
if (gx > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
}
}
}
}
}
else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfgse - END_MASK or SIDE_MASK");
edge.resize(mNumIndices);
llassert(edge.size() == 6*(mNumS-1)*(mNumT-1));
S32 cur_edge = 0;
const bool flat_face = mTypeMask & FLAT_MASK;
for (S32 t = 0; t < (mNumT-1); t++)
{
for (S32 s = 0; s < (mNumS-1); s++)
{
// bottom left/top right neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+s*2+1;
if (t < mNumT-2)
{ // top right/top left neighbor face
edge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on T
edge[cur_edge++] = s*2+1;
}
if (s > 0)
{ // top left/bottom left neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on S
edge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
}
if (t > 0)
{ // bottom left/bottom right neighbor face
edge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on T
edge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
}
if (s < mNumS-2)
{ // bottom right/top right neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on S
edge[cur_edge++] = (mNumS-1)*2*t;
}
// top right/bottom left neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+s*2;
}
}
}
else
{
LL_ERRS() << "Unknown/uninitialized face type!" << LL_ENDL;
}
}
//-----------------------------------------------------------------------------
// generateSilhouetteVertices()
@ -3810,6 +4011,13 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
}
S32 cur_index = 0;
// Scratch array for per-face silhouette edge information. This also has a
// lot of dev-only debug information that we might not care about anymore.
// (see DEBUG_SILHOUETTE_EDGE_MAP)
// *TODO: Consider removing the debug associated with
// DEBUG_SILHOUETTE_EDGE_MAP, and remove its associated computational
// overhead in generateSilhouetteEdge.
std::vector<S32> edge;
//for each face
for (face_list_t::iterator iter = mVolumeFaces.begin();
iter != mVolumeFaces.end(); ++iter)
@ -3817,7 +4025,16 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
LLVolumeFace& face = *iter;
if (!(face_mask & (0x1 << cur_index++)) ||
face.mNumIndices == 0 || face.mEdge.empty())
face.mNumIndices == 0)
{
continue;
}
// Attempt to generate "edge" info for this silhouette, which is used
// for some prims. If the edge array remains empty, then this
// silhouette generation method is not supported for this face.
edge.clear();
face.generateSilhouetteEdge(this, edge);
if (edge.empty())
{
continue;
}
@ -3831,7 +4048,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
{
for (S32 k = 0; k < 3; k++)
{
S32 index = face.mEdge[j * 3 + k];
S32 index = edge[j * 3 + k];
if (index == -1)
{
@ -3883,7 +4100,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
//for each edge
for (S32 k = 0; k < 3; k++) {
S32 nIndex = face.mEdge[j*3+k];
S32 nIndex = edge[j*3+k];
if (nIndex <= -1) {
continue;
}
@ -3998,7 +4215,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
// *FIX IF NEEDED: this does not deal with neighboring degenerate faces
for (S32 k = 0; k < 3; k++)
{
S32 index = face.mEdge[j*3+k];
S32 index = edge[j*3+k];
if (index != -1)
{
fFacing[j] = fFacing[index];
@ -4010,10 +4227,10 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
//for each edge
for (S32 k = 0; k < 3; k++) {
S32 index = face.mEdge[j*3+k];
S32 index = edge[j*3+k];
if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) {
//our neighbor is degenerate, make him face our direction
fFacing[face.mEdge[j*3+k]] = fFacing[j];
fFacing[edge[j*3+k]] = fFacing[j];
continue;
}
@ -4991,7 +5208,10 @@ bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a
void LLVolumeFace::remap()
{
// Generate a remap buffer
std::vector<unsigned int> remap(mNumVertices);
// Documentation for meshopt_generateVertexRemapMulti claims that remap should use vertice count
// but all examples use indice count. There are out of bounds crashes when using vertice count.
// To be on the safe side use bigger of the two.
std::vector<unsigned int> remap(llmax(mNumIndices, mNumVertices));
S32 remap_vertices_count = static_cast<S32>(LLMeshOptimizer::generateRemapMultiU16(&remap[0],
mIndices,
mNumIndices,
@ -5833,30 +6053,16 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build)
if (!partial_build)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcuccm - generate indices");
resizeIndices(grid_size*grid_size*6);
if (!volume->isMeshAssetLoaded())
{
S32 size = grid_size * grid_size * 6;
try
{
mEdge.resize(size);
}
catch (std::bad_alloc&)
{
LL_WARNS("LLVOLUME") << "Resize of mEdge to " << size << " failed" << LL_ENDL;
return false;
}
}
U16* out = mIndices;
S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
int cur_edge = 0;
for(S32 gx = 0;gx<grid_size;gx++)
{
for(S32 gy = 0;gy<grid_size;gy++)
{
if (mTypeMask & TOP_MASK)
@ -5866,47 +6072,6 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build)
*out++ = ((gy*(grid_size+1))+gx+idxs[i]);
}
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gx > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1; // Mark face to higlight it
}
if (gy < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
if (gx < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
if (gy > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
}
else
{
@ -5914,48 +6079,6 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build)
{
*out++ = ((gy*(grid_size+1))+gx+idxs[i]);
}
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gy > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
if (gx < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
if (gy < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
if (gx > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
}
}
}
@ -6435,6 +6558,8 @@ void LLVolumeFace::createTangents()
void LLVolumeFace::resizeVertices(S32 num_verts)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
ll_aligned_free<64>(mPositions);
//DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
ll_aligned_free_16(mTangents);
@ -6557,6 +6682,8 @@ void LLVolumeFace::allocateJointIndices(S32 num_verts)
void LLVolumeFace::resizeIndices(S32 num_indices)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
ll_aligned_free_16(mIndices);
llassert(num_indices % 3 == 0);
@ -6649,19 +6776,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
{
resizeVertices(num_vertices);
resizeIndices(num_indices);
if (!volume->isMeshAssetLoaded())
{
try
{
mEdge.resize(num_indices);
}
catch (std::bad_alloc&)
{
LL_WARNS("LLVOLUME") << "Resize of mEdge to " << num_indices << " failed" << LL_ENDL;
return false;
}
}
}
LL_CHECK_MEMORY
@ -6676,6 +6790,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
bool test = (mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2;
// Copy the vertices into the array
{ LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcs - copy verts");
for (t = mBeginT; t < end_t; t++)
{
tt = path_data[t].mTexT;
@ -6760,6 +6875,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
cur_vertex++;
}
}
}
LL_CHECK_MEMORY
mCenter->clear();
@ -6813,11 +6929,11 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
mCenter->mul(0.5f);
S32 cur_index = 0;
S32 cur_edge = 0;
bool flat_face = mTypeMask & FLAT_MASK;
if (!partial_build)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcs - generate indices");
// Now we generate the indices.
for (t = 0; t < (mNumT-1); t++)
{
@ -6829,64 +6945,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
mIndices[cur_index++] = s + mNumS*t; //bottom left
mIndices[cur_index++] = s+1 + mNumS*t; //bottom right
mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right
// bottom left/top right neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1;
if (t < mNumT-2)
{ // top right/top left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on T
mEdge[cur_edge++] = s*2+1;
}
if (s > 0)
{ // top left/bottom left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on S
mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
}
if (t > 0)
{ // bottom left/bottom right neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on T
mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
}
if (s < mNumS-2)
{ // bottom right/top right neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on S
mEdge[cur_edge++] = (mNumS-1)*2*t;
}
// top right/bottom left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2;
}
}
}

View File

@ -921,6 +921,15 @@ public:
// Get a reference to the octree, which may be null
const LLVolumeOctree* getOctree() const;
// Part of silhouette generation (used by selection outlines)
// Populates the provided edge array with numbers corresponding to
// *partial* logic of whether a particular index should be rendered
// as a silhouette edge. -1 indicates the index should be rendered as a
// silhouette edge. See generateSilhouetteVertices for the full logic.
// Silhouette edges can only be generated for some types of prims. If a
// silhouette edge cannot be generated, the edge array will be left empty.
void generateSilhouetteEdge(const LLVolume* volume, std::vector<S32>& edge) const;
enum
{
SINGLE_MASK = 0x0001,
@ -966,8 +975,6 @@ public:
// indexes for mPositions/mNormals/mTexCoords
U16* mIndices;
std::vector<S32> mEdge;
//list of skin weights for rigged volumes
// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
// mWeights.size() should be empty or match mVertices.size()
@ -1125,9 +1132,9 @@ private:
public:
virtual void setMeshAssetLoaded(bool loaded);
virtual bool isMeshAssetLoaded();
virtual bool isMeshAssetLoaded() const;
virtual void setMeshAssetUnavaliable(bool unavaliable);
virtual bool isMeshAssetUnavaliable();
virtual bool isMeshAssetUnavaliable() const;
protected:
bool mUnique;

View File

@ -31,8 +31,7 @@
#include "llerror.h"
#if LL_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <llwin32headers.h>
#else
#include <netdb.h>
#include <netinet/in.h> // ntonl()

View File

@ -30,7 +30,7 @@
#define LL_LLIOPIPE_H
#include <boost/intrusive_ptr.hpp>
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#include "apr_poll.h"
#include "llsd.h"

View File

@ -38,7 +38,7 @@
*/
#include "lliopipe.h"
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#include "apr_pools.h"
#include "apr_network_io.h"
#include "llchainio.h"

View File

@ -28,7 +28,6 @@
#include "llmail.h"
// APR on Windows needs full windows headers
#include "llwin32headers.h"
#include <string>
#include <sstream>

View File

@ -32,7 +32,7 @@
#include <stdexcept>
#if LL_WINDOWS
#include "llwin32headerslean.h"
#include "llwin32headers.h"
#else
#include <sys/types.h>
#include <sys/socket.h>

View File

@ -50,7 +50,7 @@ LLPluginProcessParentOwner::~LLPluginProcessParentOwner()
bool LLPluginProcessParent::sUseReadThread = false;
apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
LLCoros::Mutex *LLPluginProcessParent::sInstancesMutex;
LLCoros::Mutex *LLPluginProcessParent::sInstancesMutex = nullptr;
LLPluginProcessParent::mapInstances_t LLPluginProcessParent::sInstances;
LLThread *LLPluginProcessParent::sReadThread = NULL;
@ -157,18 +157,14 @@ LLPluginProcessParent::ptr_t LLPluginProcessParent::create(LLPluginProcessParent
/*static*/
void LLPluginProcessParent::shutdown()
{
// <FS:Beq> FIRE-34497 - lock maybe be null during shutdown due to fiber shutdown race condition
// LLCoros::LockType lock(*sInstancesMutex);
std::unique_ptr<LLCoros::LockType> lock;
if (sInstancesMutex)
if (!sInstancesMutex)
{
lock = std::make_unique<LLCoros::LockType>(*sInstancesMutex);
// setup was not complete, skip shutdown
return;
}
else
{
LL_WARNS("Plugin") << "shutdown called but no instances mutex available" << LL_ENDL;
}
// </FS:Beq>
LLCoros::LockType lock(*sInstancesMutex);
mapInstances_t::iterator it;
for (it = sInstances.begin(); it != sInstances.end(); ++it)
{

View File

@ -7,7 +7,6 @@ include(LLCommon)
include(LLCoreHttp)
include(LLPhysicsExtensions)
include(LLPrimitive)
include(GLH)
include(GLM)
include(TinyGLTF)
include(ColladaDom)
@ -71,7 +70,7 @@ target_link_libraries(llprimitive
llrender
llphysicsextensions_impl
ll::colladadom
ll::glh_linear
ll::glm
)
if(LINUX)

View File

@ -53,20 +53,10 @@
#include "llsdserialize.h"
#include "lljoint.h"
#if LL_LINUX && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) >= 70000
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmisleading-indentation"
#endif
#include "glh/glh_linear.h"
#if LL_LINUX && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) >= 70000
#pragma GCC diagnostic push
#endif
#include "glm/mat4x4.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "llmatrix4a.h"
#include <boost/regex.hpp>
#include <boost/algorithm/string/replace.hpp>
@ -1178,19 +1168,17 @@ bool LLDAELoader::OpenFile(const std::string& filename)
if (skin)
{
domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement());
if (geom)
if (domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement()))
{
domMesh* mesh = geom->getMesh();
if (mesh)
if (domMesh* mesh = geom->getMesh())
{
std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin();
while (i != mModelsMap[mesh].end())
dae_model_map::const_iterator it = mModelsMap.find(mesh);
if (it != mModelsMap.end())
{
LLPointer<LLModel> mdl = *i;
LLDAELoader::processDomModel(mdl, &dae, root, mesh, skin);
i++;
for (const LLPointer<LLModel>& model : it->second)
{
LLDAELoader::processDomModel(model, &dae, root, mesh, skin);
}
}
}
}
@ -1282,9 +1270,9 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
mesh_scale *= normalized_transformation;
normalized_transformation = mesh_scale;
glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix);
inv_mat = inv_mat.inverse();
LLMatrix4 inverse_normalized_transformation(inv_mat.m);
glm::mat4 inv_mat = glm::make_mat4((F32*)normalized_transformation.mMatrix);
inv_mat = glm::inverse(inv_mat);
LLMatrix4 inverse_normalized_transformation(glm::value_ptr(inv_mat));
domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix();
@ -1360,6 +1348,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
}
}
else
{
//Has one or more skeletons
for (std::vector<domInstance_controller::domSkeleton*>::iterator skel_it = skeletons.begin();
skel_it != skeletons.end(); ++skel_it)
@ -1444,6 +1433,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
}
}//got skeleton?
}
}
domSkin::domJoints* joints = skin->getJoints();
@ -1760,7 +1750,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
materials[model->mMaterialList[i]] = LLImportMaterial();
}
mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials));
stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
stretch_extents(model, transformation);
}
}
@ -2153,102 +2143,99 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
mTransform.condition();
}
domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element);
if (instance_geo)
if (domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element))
{
domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement());
if (geo)
if (domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement()))
{
domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID())));
if (mesh)
if (domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID()))))
{
std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin();
while (i != mModelsMap[mesh].end())
dae_model_map::iterator it = mModelsMap.find(mesh);
if (it != mModelsMap.end())
{
LLModel* model = *i;
LLMatrix4 transformation = mTransform;
if (mTransform.determinant() < 0)
{ //negative scales are not supported
LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
LLSD args;
args["Message"] = "NegativeScaleTrans";
args["LABEL"] = getElementLabel(instance_geo);
mWarningsArray.append(args);
badElement = true;
}
LLModelLoader::material_map materials = getMaterials(model, instance_geo, dae);
// adjust the transformation to compensate for mesh normalization
LLVector3 mesh_scale_vector;
LLVector3 mesh_translation_vector;
model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
LLMatrix4 mesh_translation;
mesh_translation.setTranslation(mesh_translation_vector);
mesh_translation *= transformation;
transformation = mesh_translation;
LLMatrix4 mesh_scale;
mesh_scale.initScale(mesh_scale_vector);
mesh_scale *= transformation;
transformation = mesh_scale;
if (transformation.determinant() < 0)
{ //negative scales are not supported
LL_INFOS() << "Negative scale detected, unsupported post-normalization transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
LLSD args;
args["Message"] = "NegativeScaleNormTrans";
args["LABEL"] = getElementLabel(instance_geo);
mWarningsArray.append(args);
badElement = true;
}
std::string label;
if (model->mLabel.empty())
for (LLModel* model : it->second)
{
label = getLodlessLabel(instance_geo);
LLMatrix4 transformation = mTransform;
llassert(!label.empty());
if (mTransform.determinant() < 0)
{ //negative scales are not supported
LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
LLSD args;
args["Message"] = "NegativeScaleTrans";
args["LABEL"] = getElementLabel(instance_geo);
mWarningsArray.append(args);
if (model->mSubmodelID)
{
label += (char)((int)'a' + model->mSubmodelID);
badElement = true;
}
// <FS:Beq> Support altenate LOD naming conventions
// model->mLabel = label + sLODSuffix[mLod];
if ( sLODSuffix[mLod].size() > 0 )
LLModelLoader::material_map materials = getMaterials(model, instance_geo, dae);
// adjust the transformation to compensate for mesh normalization
LLVector3 mesh_scale_vector;
LLVector3 mesh_translation_vector;
model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
LLMatrix4 mesh_translation;
mesh_translation.setTranslation(mesh_translation_vector);
mesh_translation *= transformation;
transformation = mesh_translation;
LLMatrix4 mesh_scale;
mesh_scale.initScale(mesh_scale_vector);
mesh_scale *= transformation;
transformation = mesh_scale;
if (transformation.determinant() < 0)
{ //negative scales are not supported
LL_INFOS() << "Negative scale detected, unsupported post-normalization transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
LLSD args;
args["Message"] = "NegativeScaleNormTrans";
args["LABEL"] = getElementLabel(instance_geo);
mWarningsArray.append(args);
badElement = true;
}
std::string label;
if (model->mLabel.empty())
{
model->mLabel = label + '_' + sLODSuffix[mLod];
label = getLodlessLabel(instance_geo);
llassert(!label.empty());
if (model->mSubmodelID)
{
label += (char)((int)'a' + model->mSubmodelID);
}
// <FS:Beq> Support altenate LOD naming conventions
//model->mLabel = label + lod_suffix[mLod];
if (sLODSuffix[mLod].size() > 0)
{
model->mLabel = label + '_' + sLODSuffix[mLod];
}
else
{
model->mLabel = label;
}
// </FS:Beq>
}
else
{
model->mLabel = label;
// Don't change model's name if possible, it will play havoc with scenes that already use said model.
size_t ext_pos = getSuffixPosition(model->mLabel);
if (ext_pos != -1)
{
label = model->mLabel.substr(0, ext_pos);
}
else
{
label = model->mLabel;
}
}
// </FS:Beq>
}
else
{
// Don't change model's name if possible, it will play havoc with scenes that already use said model.
size_t ext_pos = getSuffixPosition(model->mLabel);
if (ext_pos != -1)
{
label = model->mLabel.substr(0, ext_pos);
}
else
{
label = model->mLabel;
}
}
mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials));
stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform);
i++;
mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials));
stretch_extents(model, transformation);
}
}
}
}

View File

@ -51,7 +51,6 @@
#include "llsdserialize.h"
#include "lljoint.h"
#include "glh/glh_linear.h"
#include "llmatrix4a.h"
#include <boost/regex.hpp>

View File

@ -94,19 +94,15 @@ std::string LLModel::getStatusString(U32 status)
}
void LLModel::offsetMesh( const LLVector3& pivotPoint )
void LLModel::offsetMesh(const LLVector3& pivotPoint)
{
LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] );
LLVector4a pivot(pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ]);
for (std::vector<LLVolumeFace>::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); )
for (LLVolumeFace& face : mVolumeFaces)
{
std::vector<LLVolumeFace>:: iterator currentFaceIt = faceIt++;
LLVolumeFace& face = *currentFaceIt;
LLVector4a *pos = (LLVector4a*) face.mPositions;
for (S32 i=0; i<face.mNumVertices; ++i )
for (S32 i = 0; i < face.mNumVertices; ++i)
{
pos[i].add( pivot );
face.mPositions[i].add(pivot);
}
}
}
@ -350,7 +346,7 @@ void LLModel::normalizeVolumeFaces()
}
}
void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out)
void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) const
{
scale_out = mNormalizedScale;
translation_out = mNormalizedTranslation;
@ -1577,6 +1573,13 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
mLockScaleIfJointPosition = false;
}
// combine mBindShapeMatrix and mInvBindMatrix into mBindPoseMatrix
mBindPoseMatrix.resize(mInvBindMatrix.size());
for (U32 i = 0; i < mInvBindMatrix.size(); ++i)
{
matMul(mBindShapeMatrix, mInvBindMatrix[i], mBindPoseMatrix[i]);
}
updateHash();
}

View File

@ -61,12 +61,15 @@ public:
std::vector< JointKey > mJointNames;
// </FS:ND>
mutable std::vector<S32> mJointNums;
typedef std::vector<LLMatrix4a, boost::alignment::aligned_allocator<LLMatrix4a, 16>> matrix_list_t;
typedef std::vector<LLMatrix4a> matrix_list_t;
matrix_list_t mInvBindMatrix;
// bones/joints position overrides
matrix_list_t mAlternateBindMatrix;
// cached multiply of mBindShapeMatrix and mInvBindMatrix
matrix_list_t mBindPoseMatrix;
LL_ALIGN_16(LLMatrix4a mBindShapeMatrix);
float mPelvisOffset;
@ -208,7 +211,7 @@ public:
void remapVolumeFaces();
void optimizeVolumeFaces();
void offsetMesh( const LLVector3& pivotPoint );
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) const;
LLVector3 getTransformedCenter(const LLMatrix4& mat);
//reorder face list based on mMaterialList in this and reference so

View File

@ -31,17 +31,6 @@
#include "lljoint.h"
#include "llcallbacklist.h"
#if LL_LINUX && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) >= 70000
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmisleading-indentation"
#endif
#include "glh/glh_linear.h"
#if LL_LINUX && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) >= 70000
#pragma GCC diagnostic push
#endif
#include "llmatrix4a.h"
#include <boost/bind.hpp>
@ -49,7 +38,7 @@
std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform)
static void stretch_extents(const LLModel* model, const LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform)
{
LLVector4a box[] =
{
@ -97,19 +86,19 @@ void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4
}
}
void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, bool& first_transform)
void LLModelLoader::stretch_extents(const LLModel* model, const LLMatrix4& mat)
{
LLVector4a mina, maxa;
LLMatrix4a mata;
mata.loadu(mat);
mina.load3(min.mV);
maxa.load3(max.mV);
mina.load3(mExtents[0].mV);
maxa.load3(mExtents[1].mV);
stretch_extents(model, mata, mina, maxa, first_transform);
::stretch_extents(model, mata, mina, maxa, mFirstTransform);
min.set(mina.getF32ptr());
max.set(maxa.getF32ptr());
mExtents[0].set(mina.getF32ptr());
mExtents[1].set(maxa.getF32ptr());
}
//-----------------------------------------------------------------------------
@ -307,14 +296,7 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)
{
if (idx >= model[lod].size())
{
if (model[lod].size())
{
instance_list[i].mLOD[lod] = model[lod][0];
}
else
{
instance_list[i].mLOD[lod] = NULL;
}
instance_list[i].mLOD[lod] = model[lod].front();
continue;
}
@ -360,7 +342,7 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)
{
LLModelInstance& cur_instance = instance_list[i];
mScene[cur_instance.mTransform].push_back(cur_instance);
stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform);
stretch_extents(cur_instance.mModel, cur_instance.mTransform);
}
setLoadState( DONE );

View File

@ -34,13 +34,13 @@
class LLJoint;
typedef std::map<std::string, LLMatrix4> JointTransformMap;
typedef std::map<std::string, LLMatrix4>::iterator JointTransformMapIt;
typedef std::map<std::string, std::string> JointMap;
typedef std::deque<std::string> JointNameSet;
typedef std::map<std::string, LLMatrix4> JointTransformMap;
typedef std::map<std::string, LLMatrix4>::iterator JointTransformMapIt;
typedef std::map<std::string, std::string> JointMap;
typedef std::deque<std::string> JointNameSet;
const S32 SLM_SUPPORTED_VERSION = 3;
const S32 NUM_LOD = 4;
const S32 NUM_LOD = 4;
const U32 LEGACY_RIG_OK = 0;
const U32 LEGACY_RIG_FLAG_TOO_MANY_JOINTS = 1;
@ -50,32 +50,32 @@ class LLModelLoader : public LLThread
{
public:
typedef std::map<std::string, LLImportMaterial> material_map;
typedef std::vector<LLPointer<LLModel > > model_list;
typedef std::vector<LLModelInstance> model_instance_list;
typedef std::map<LLMatrix4, model_instance_list > scene;
typedef std::map<std::string, LLImportMaterial> material_map;
typedef std::vector<LLPointer<LLModel>> model_list;
typedef std::vector<LLModelInstance> model_instance_list;
typedef std::map<LLMatrix4, model_instance_list> scene;
// Callback with loaded model data and loaded LoD
//
typedef boost::function<void (scene&,model_list&,S32,void*) > load_callback_t;
typedef boost::function<void (scene&, model_list&, S32, void*)> load_callback_t;
// Function to provide joint lookup by name
// (within preview avi skeleton, for example)
//
typedef boost::function<LLJoint* (const std::string&,void*) > joint_lookup_func_t;
typedef boost::function<LLJoint* (const std::string&, void*)> joint_lookup_func_t;
// Func to load and associate material with all it's textures,
// returned value is the number of textures loaded
// intentionally non-const so func can modify material to
// store platform-specific data
//
typedef boost::function<U32 (LLImportMaterial&,void*) > texture_load_func_t;
typedef boost::function<U32 (LLImportMaterial&, void*)> texture_load_func_t;
// Callback to inform client of state changes
// during loading process (errors will be reported
// as state changes here as well)
//
typedef boost::function<void (U32,void*) > state_callback_t;
typedef boost::function<void (U32, void*)> state_callback_t;
typedef enum
{
@ -138,7 +138,7 @@ public:
JointNameSet& jointsFromNodes,
JointMap& legalJointNamesMap,
U32 maxJointsPerMesh);
virtual ~LLModelLoader() ;
virtual ~LLModelLoader();
virtual void setNoNormalize() { mNoNormalize = true; }
virtual void setNoOptimize() { mNoOptimize = true; }
@ -158,13 +158,13 @@ public:
bool loadFromSLM(const std::string& filename);
void loadModelCallback();
void loadTextures() ; //called in the main thread.
void loadTextures() ; // called in the main thread.
void setLoadState(U32 state);
void stretch_extents(const LLModel* model, const LLMatrix4& mat);
S32 mNumOfFetchingTextures ; //updated in the main thread
bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread.
S32 mNumOfFetchingTextures ; // updated in the main thread
bool areTexturesReady() { return !mNumOfFetchingTextures; } // called in the main thread.
bool verifyCount( int expected, int result );
@ -225,10 +225,7 @@ protected:
LLSD mWarningsArray; // preview floater will pull logs from here
static std::list<LLModelLoader*> sActiveLoaderList;
static bool isAlive(LLModelLoader* loader) ;
static bool isAlive(LLModelLoader* loader);
};
class LLMatrix4a;
void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform);
void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, bool& first_transform);
#endif // LL_LLMODELLOADER_H

View File

@ -17,6 +17,7 @@ set(llrender_SOURCE_FILES
llfontfreetype.cpp
llfontfreetypesvg.cpp
llfontgl.cpp
llfontvertexbuffer.cpp
llfontregistry.cpp
llgl.cpp
llglslshader.cpp
@ -43,6 +44,7 @@ set(llrender_HEADER_FILES
llcubemap.h
llcubemaparray.h
llfontgl.h
llfontvertexbuffer.h
llfontfreetype.h
llfontfreetypesvg.h
llfontbitmapcache.h

View File

@ -125,27 +125,25 @@ void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool us
mImage->setHasMipMaps(use_mips);
bind(0);
U32 format = components == 4 ? GL_RGBA16F : GL_RGB16F;
U32 mip = 0;
free_cur_tex_image();
while (resolution >= 1)
U32 format = components == 4 ? GL_RGBA16F : GL_RGB16F;
U32 mip = 0;
U32 mip_resolution = resolution;
while (mip_resolution >= 1)
{
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, format, resolution, resolution, count * 6, 0,
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, format, mip_resolution, mip_resolution, count * 6, 0,
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
if (!use_mips)
{
break;
}
resolution /= 2;
mip_resolution /= 2;
++mip;
}
alloc_tex_image(resolution * 6, resolution, format);
alloc_tex_image(resolution, resolution, format, count * 6);
mImage->setAddressMode(LLTexUnit::TAM_CLAMP);

View File

@ -117,7 +117,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp
}
// Make corresponding GL image.
mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false));
mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false, false));
LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num);
// Start at beginning of the new image.

View File

@ -270,15 +270,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
const LLFontGlyphInfo* next_glyph = NULL;
const S32 GLYPH_BATCH_SIZE = 30;
// <FS:Ansariel> Remove QUADS rendering mode
//LLVector3 vertices[GLYPH_BATCH_SIZE * 4];
//LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
//LLColor4U colors[GLYPH_BATCH_SIZE * 4];
LLVector3 vertices[GLYPH_BATCH_SIZE * 6];
LLVector2 uvs[GLYPH_BATCH_SIZE * 6];
LLColor4U colors[GLYPH_BATCH_SIZE * 6];
// </FS:Ansariel>
static constexpr S32 GLYPH_BATCH_SIZE = 30;
static thread_local LLVector4a vertices[GLYPH_BATCH_SIZE * 6];
static thread_local LLVector2 uvs[GLYPH_BATCH_SIZE * 6];
static thread_local LLColor4U colors[GLYPH_BATCH_SIZE * 6];
LLColor4U text_color(color);
// Preserve the transparency to render fading emojis in fading text (e.g.
@ -310,12 +305,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
// otherwise the queued glyphs will be taken from wrong textures.
if (glyph_count > 0)
{
// <FS:Ansariel> Remove QUADS rendering mode
//gGL.begin(LLRender::QUADS);
//{
// gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
//}
//gGL.end();
gGL.begin(LLRender::TRIANGLES);
{
gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 6);
@ -350,18 +339,11 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
if (glyph_count >= GLYPH_BATCH_SIZE)
{
// <FS:Ansariel> Remove QUADS rendering mode
//gGL.begin(LLRender::QUADS);
//{
// gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
//}
//gGL.end();
gGL.begin(LLRender::TRIANGLES);
{
gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 6);
}
gGL.end();
// </FS:Ansariel>
glyph_count = 0;
}
@ -395,18 +377,11 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
cur_render_y = cur_y;
}
// <FS:Ansariel> Remove QUADS rendering mode
//gGL.begin(LLRender::QUADS);
//{
// gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
//}
//gGL.end();
gGL.begin(LLRender::TRIANGLES);
{
gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 6);
}
gGL.end();
// </FS:Ansariel>
if (right_x)
@ -428,10 +403,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
if (draw_ellipses)
{
// recursively render ellipses at end of string
// we've already reserved enough room
gGL.pushUIMatrix();
static LLWString elipses_wstr(utf8string_to_wstring(std::string("...")));
render(elipses_wstr,
0,
@ -444,7 +417,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
right_x,
false,
use_color);
gGL.popUIMatrix();
}
gGL.popUIMatrix();
@ -530,6 +502,7 @@ F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max
F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars, bool no_padding) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
F32 cur_x = 0;
@ -1359,67 +1332,42 @@ LLFontGL &LLFontGL::operator=(const LLFontGL &source)
return *this;
}
// <FS:Ansariel> Remove QUADS rendering mode
//void LLFontGL::renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const
//{
// S32 index = 0;
//
// vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mTop, 0.f);
// uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
// colors_out[index] = color;
// index++;
//
// vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 0.f);
// uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
// colors_out[index] = color;
// index++;
//
// vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 0.f);
// uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
// colors_out[index] = color;
// index++;
//
// vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 0.f);
// uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
// colors_out[index] = color;
//}
void LLFontGL::renderTriangle(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const
void LLFontGL::renderTriangle(LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const
{
S32 index = 0;
vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mTop, 0.f);
uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
vertex_out[index].set(screen_rect.mRight, screen_rect.mTop, 0.f);
uv_out[index].set(uv_rect.mRight, uv_rect.mTop);
colors_out[index] = color;
index++;
vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 0.f);
uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
vertex_out[index].set(screen_rect.mLeft, screen_rect.mTop, 0.f);
uv_out[index].set(uv_rect.mLeft, uv_rect.mTop);
colors_out[index] = color;
index++;
vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 0.f);
uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
vertex_out[index].set(screen_rect.mLeft, screen_rect.mBottom, 0.f);
uv_out[index].set(uv_rect.mLeft, uv_rect.mBottom);
colors_out[index] = color;
index++;
vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mTop, 0.f);
uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
vertex_out[index].set(screen_rect.mRight, screen_rect.mTop, 0.f);
uv_out[index].set(uv_rect.mRight, uv_rect.mTop);
colors_out[index] = color;
index++;
vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 0.f);
uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
vertex_out[index].set(screen_rect.mLeft, screen_rect.mBottom, 0.f);
uv_out[index].set(uv_rect.mLeft, uv_rect.mBottom);
colors_out[index] = color;
index++;
vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 0.f);
uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
vertex_out[index].set(screen_rect.mRight, screen_rect.mBottom, 0.f);
uv_out[index].set(uv_rect.mRight, uv_rect.mBottom);
colors_out[index] = color;
}
// </FS:Ansariel>
void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
void LLFontGL::drawGlyph(S32& glyph_count, LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
{
F32 slant_offset;
slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f);
@ -1433,10 +1381,7 @@ void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_
LLRectf screen_rect_offset = screen_rect;
screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
// <FS:Ansariel> Remove QUADS rendering mode
//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect_offset, uv_rect, color, slant_offset);
// </FS:Ansariel>
glyph_count++;
}
}
@ -1467,16 +1412,10 @@ void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_
break;
}
// <FS:Ansariel> Remove QUADS rendering mode
//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, shadow_color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect_offset, uv_rect, shadow_color, slant_offset);
// </FS:Ansariel>
glyph_count++;
}
// <FS:Ansariel> Remove QUADS rendering mode
//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect, uv_rect, color, slant_offset);
// </FS:Ansariel>
glyph_count++;
}
else if (shadow == DROP_SHADOW)
@ -1485,22 +1424,14 @@ void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_
shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength);
LLRectf screen_rect_shadow = screen_rect;
screen_rect_shadow.translate(1.f, -1.f);
// <FS:Ansariel> Remove QUADS rendering mode
//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_shadow, uv_rect, shadow_color, slant_offset);
//glyph_count++;
//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect_shadow, uv_rect, shadow_color, slant_offset);
glyph_count++;
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect, uv_rect, color, slant_offset);
// </FS:Ansariel>
glyph_count++;
}
else // normal rendering
{
// <FS:Ansariel> Remove QUADS rendering mode
//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect, uv_rect, color, slant_offset);
// </FS:Ansariel>
glyph_count++;
}
}

View File

@ -249,11 +249,8 @@ private:
LLFontDescriptor mFontDescriptor;
LLPointer<LLFontFreetype> mFontFreetype;
// <FS:Ansariel> Remove QUADS rendering mode
//void renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const;
void renderTriangle(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const;
// </FS:Ansariel>
void drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const;
void renderTriangle(LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const;
void drawGlyph(S32& glyph_count, LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const;
// Registry holds all instantiated fonts.
static LLFontRegistry* sFontRegistry;

View File

@ -0,0 +1,233 @@
/**
* @file llfontvertexbuffer.cpp
* @brief Buffer storage for font rendering.
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llfontvertexbuffer.h"
#include "llvertexbuffer.h"
bool LLFontVertexBuffer::sEnableBufferCollection = true;
LLFontVertexBuffer::LLFontVertexBuffer()
{
}
LLFontVertexBuffer::~LLFontVertexBuffer()
{
reset();
}
void LLFontVertexBuffer::reset()
{
// Todo: some form of debug only frequecy check&assert to see if this is happening too often.
// Regenerating this list is expensive
mBufferList.clear();
}
S32 LLFontVertexBuffer::render(
const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
LLRect rect,
const LLColor4& color,
LLFontGL::HAlign halign, LLFontGL::VAlign valign,
U8 style,
LLFontGL::ShadowType shadow,
S32 max_chars, S32 max_pixels,
F32* right_x,
bool use_ellipses,
bool use_color)
{
LLRectf rect_float((F32)rect.mLeft, (F32)rect.mTop, (F32)rect.mRight, (F32)rect.mBottom);
return render(fontp, text, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses, use_color);
}
S32 LLFontVertexBuffer::render(
const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
LLRectf rect,
const LLColor4& color,
LLFontGL::HAlign halign, LLFontGL::VAlign valign,
U8 style,
LLFontGL::ShadowType shadow,
S32 max_chars,
F32* right_x,
bool use_ellipses,
bool use_color)
{
F32 x = rect.mLeft;
F32 y = 0.f;
switch (valign)
{
case LLFontGL::TOP:
y = rect.mTop;
break;
case LLFontGL::VCENTER:
y = rect.getCenterY();
break;
case LLFontGL::BASELINE:
case LLFontGL::BOTTOM:
y = rect.mBottom;
break;
default:
y = rect.mBottom;
break;
}
return render(fontp, text, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, (S32)rect.getWidth(), right_x, use_ellipses, use_color);
}
S32 LLFontVertexBuffer::render(
const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
F32 x, F32 y,
const LLColor4& color,
LLFontGL::HAlign halign, LLFontGL::VAlign valign,
U8 style,
LLFontGL::ShadowType shadow,
S32 max_chars , S32 max_pixels,
F32* right_x,
bool use_ellipses,
bool use_color )
{
if (!LLFontGL::sDisplayFont) //do not display texts
{
return static_cast<S32>(text.length());
}
if (!sEnableBufferCollection)
{
// For debug purposes and performance testing
return fontp->render(text, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
}
if (mBufferList.empty())
{
genBuffers(fontp, text, begin_offset, x, y, color, halign, valign,
style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
}
else if (mLastX != x
|| mLastY != y
|| mLastFont != fontp
|| mLastColor != color // alphas change often
|| mLastHalign != halign
|| mLastValign != valign
|| mLastOffset != begin_offset
|| mLastMaxChars != max_chars
|| mLastMaxPixels != max_pixels
|| mLastStyle != style
|| mLastShadow != shadow // ex: buttons change shadow state
|| mLastScaleX != LLFontGL::sScaleX
|| mLastScaleY != LLFontGL::sScaleY
|| mLastVertDPI != LLFontGL::sVertDPI
|| mLastHorizDPI != LLFontGL::sHorizDPI
|| mLastOrigin != LLFontGL::sCurOrigin)
{
genBuffers(fontp, text, begin_offset, x, y, color, halign, valign,
style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
}
else
{
renderBuffers();
if (right_x)
{
*right_x = mLastRightX;
}
}
return mChars;
}
void LLFontVertexBuffer::genBuffers(
const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
F32 x, F32 y,
const LLColor4& color,
LLFontGL::HAlign halign, LLFontGL::VAlign valign,
U8 style, LLFontGL::ShadowType shadow,
S32 max_chars, S32 max_pixels,
F32* right_x,
bool use_ellipses,
bool use_color)
{
// todo: add a debug build assert if this triggers too often for to long?
mBufferList.clear();
gGL.beginList(&mBufferList);
mChars = fontp->render(text, begin_offset, x, y, color, halign, valign,
style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
gGL.endList();
mLastFont = fontp;
mLastOffset = begin_offset;
mLastMaxChars = max_chars;
mLastMaxPixels = max_pixels;
mLastX = x;
mLastY = y;
mLastColor = color;
mLastHalign = halign;
mLastValign = valign;
mLastStyle = style;
mLastShadow = shadow;
mLastScaleX = LLFontGL::sScaleX;
mLastScaleY = LLFontGL::sScaleY;
mLastVertDPI = LLFontGL::sVertDPI;
mLastHorizDPI = LLFontGL::sHorizDPI;
mLastOrigin = LLFontGL::sCurOrigin;
if (right_x)
{
mLastRightX = *right_x;
}
}
void LLFontVertexBuffer::renderBuffers()
{
gGL.flush(); // deliberately empty pending verts
gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
gGL.pushUIMatrix();
gGL.loadUIIdentity();
// Depth translation, so that floating text appears 'in-world'
// and is correctly occluded.
gGL.translatef(0.f, 0.f, LLFontGL::sCurDepth);
gGL.setSceneBlendType(LLRender::BT_ALPHA);
// Note: ellipses should technically be covered by push/load/translate of their own
// but it's more complexity, values do not change, skipping doesn't appear to break
// anything, so we can skip that until it proves to cause issues.
for (LLVertexBufferData& buffer : mBufferList)
{
buffer.draw();
}
gGL.popUIMatrix();
}

View File

@ -0,0 +1,125 @@
/**
* @file llfontgl.h
* @author Andrii Kleshchev
* @brief Buffer storage for font rendering.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLFONTVERTEXBUFFER_H
#define LL_LLFONTVERTEXBUFFER_H
#include "llfontgl.h"
class LLVertexBufferData;
class LLFontVertexBuffer
{
public:
LLFontVertexBuffer();
~LLFontVertexBuffer();
void reset();
S32 render(const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
LLRect rect,
const LLColor4& color,
LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE,
U8 style = LLFontGL::NORMAL,
LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW,
S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX,
F32* right_x = NULL,
bool use_ellipses = false,
bool use_color = true);
S32 render(const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
LLRectf rect,
const LLColor4& color,
LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE,
U8 style = LLFontGL::NORMAL,
LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW,
S32 max_chars = S32_MAX,
F32* right_x = NULL,
bool use_ellipses = false,
bool use_color = true);
S32 render(const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
F32 x, F32 y,
const LLColor4& color,
LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE,
U8 style = LLFontGL::NORMAL,
LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW,
S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX,
F32* right_x = NULL,
bool use_ellipses = false,
bool use_color = true);
static void enableBufferCollection(bool enable) { sEnableBufferCollection = enable; }
private:
void genBuffers(const LLFontGL* fontp,
const LLWString& text,
S32 begin_offset,
F32 x, F32 y,
const LLColor4& color,
LLFontGL::HAlign halign, LLFontGL::VAlign valign,
U8 style,
LLFontGL::ShadowType shadow,
S32 max_chars, S32 max_pixels,
F32* right_x,
bool use_ellipses,
bool use_color);
void renderBuffers();
std::list<LLVertexBufferData> mBufferList;
S32 mChars = 0;
const LLFontGL *mLastFont = nullptr;
S32 mLastOffset = 0;
S32 mLastMaxChars = 0;
S32 mLastMaxPixels = 0;
F32 mLastX = 0.f;
F32 mLastY = 0.f;
LLColor4 mLastColor;
LLFontGL::HAlign mLastHalign = LLFontGL::LEFT;
LLFontGL::VAlign mLastValign = LLFontGL::BASELINE;
U8 mLastStyle = LLFontGL::NORMAL;
LLFontGL::ShadowType mLastShadow = LLFontGL::NO_SHADOW;
F32 mLastRightX = 0.f;
// LLFontGL's statics
F32 mLastScaleX = 1.f;
F32 mLastScaleY = 1.f;
F32 mLastVertDPI = 0.f;
F32 mLastHorizDPI = 0.f;
LLCoordGL mLastOrigin;
static bool sEnableBufferCollection;
};
#endif

View File

@ -50,6 +50,10 @@
#include "llglheaders.h"
#include "llglslshader.h"
#include "glm/glm.hpp"
#include <glm/gtc/matrix_access.hpp>
#include "glm/gtc/type_ptr.hpp"
#if LL_WINDOWS
#include "lldxhardware.h"
#endif
@ -1176,6 +1180,11 @@ bool LLGLManager::initGL()
mGLVendorShort = "INTEL";
mIsIntel = true;
}
else if (mGLVendor.find("APPLE") != std::string::npos)
{
mGLVendorShort = "APPLE";
mIsApple = true;
}
else
{
mGLVendorShort = "MISC";
@ -1315,6 +1324,7 @@ bool LLGLManager::initGL()
glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples);
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
glGetIntegerv(GL_MAX_VARYING_VECTORS, &mMaxVaryingVectors);
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &mMaxUniformBlockSize);
// sanity clamp max uniform block size to 64k just in case
@ -2772,7 +2782,7 @@ void parse_glsl_version(S32& major, S32& minor)
LLStringUtil::convertToS32(minor_str, minor);
}
LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply)
LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glm::mat4& modelview, const glm::mat4& projection, bool apply)
{
mApply = apply;
@ -2799,13 +2809,12 @@ void LLGLUserClipPlane::disable()
void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
{
glh::matrix4f& P = mProjection;
glh::matrix4f& M = mModelview;
const glm::mat4& P = mProjection;
const glm::mat4& M = mModelview;
glh::matrix4f invtrans_MVP = (P * M).inverse().transpose();
glh::vec4f oplane(a,b,c,d);
glh::vec4f cplane;
invtrans_MVP.mult_matrix_vec(oplane, cplane);
glm::mat4 invtrans_MVP = glm::transpose(glm::inverse(P*M));
glm::vec4 oplane(a,b,c,d);
glm::vec4 cplane = invtrans_MVP * oplane;
cplane /= fabs(cplane[2]); // normalize such that depth is not scaled
cplane[3] -= 1;
@ -2813,13 +2822,13 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
if(cplane[2] < 0)
cplane *= -1;
glh::matrix4f suffix;
suffix.set_row(2, cplane);
glh::matrix4f newP = suffix * P;
glm::mat4 suffix;
suffix = glm::row(suffix, 2, cplane);
glm::mat4 newP = suffix * P;
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
gGL.loadMatrix(newP.m);
gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m);
gGL.loadMatrix(glm::value_ptr(newP));
gGLObliqueProjectionInverse = LLMatrix4(glm::value_ptr(glm::transpose(glm::inverse(newP))));
gGL.matrixMode(LLRender::MM_MODELVIEW);
}
@ -2832,7 +2841,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G
: mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled)
{
stop_glerror();
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
checkState();
if (!depth_enabled)
@ -2865,6 +2874,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G
LLGLDepthTest::~LLGLDepthTest()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
checkState();
if (sDepthEnabled != mPrevDepthEnabled )
{
@ -2915,31 +2925,27 @@ void LLGLDepthTest::checkState()
LLGLSquashToFarClip::LLGLSquashToFarClip()
{
glh::matrix4f proj = get_current_projection();
glm::mat4 proj = get_current_projection();
setProjectionMatrix(proj, 0);
}
LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f& P, U32 layer)
LLGLSquashToFarClip::LLGLSquashToFarClip(const glm::mat4& P, U32 layer)
{
setProjectionMatrix(P, layer);
}
void LLGLSquashToFarClip::setProjectionMatrix(glh::matrix4f& projection, U32 layer)
void LLGLSquashToFarClip::setProjectionMatrix(glm::mat4 projection, U32 layer)
{
F32 depth = 0.99999f - 0.0001f * layer;
for (U32 i = 0; i < 4; i++)
{
projection.element(2, i) = projection.element(3, i) * depth;
}
glm::vec4 P_row_3 = glm::row(projection, 3) * depth;
projection = glm::row(projection, 2, P_row_3);
LLRender::eMatrixMode last_matrix_mode = gGL.getMatrixMode();
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
gGL.loadMatrix(projection.m);
gGL.loadMatrix(glm::value_ptr(projection));
gGL.matrixMode(last_matrix_mode);
}

View File

@ -43,17 +43,7 @@
#include "llinstancetracker.h"
#include "llglheaders.h"
#if LL_LINUX && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) >= 70000
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmisleading-indentation"
#endif
#include "glh/glh_linear.h"
#if LL_LINUX && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) >= 70000
#pragma GCC diagnostic push
#endif
#include "glm/mat4x4.hpp"
extern bool gDebugGL;
extern bool gDebugSession;
@ -100,6 +90,7 @@ public:
S32 mGLMaxTextureSize;
F32 mMaxAnisotropy = 0.f;
S32 mMaxUniformBlockSize = 0;
S32 mMaxVaryingVectors = 0;
// GL 4.x capabilities
bool mHasCubeMapArray = false;
@ -115,6 +106,7 @@ public:
bool mIsAMD;
bool mIsNVIDIA;
bool mIsIntel;
bool mIsApple = false;
// hints to the render pipe
U32 mDownScaleMethod = 0; // see settings.xml RenderDownScaleMethod
@ -330,7 +322,7 @@ class LLGLUserClipPlane
{
public:
LLGLUserClipPlane(const LLPlane& plane, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply = true);
LLGLUserClipPlane(const LLPlane& plane, const glm::mat4& modelview, const glm::mat4& projection, bool apply = true);
~LLGLUserClipPlane();
void setPlane(F32 a, F32 b, F32 c, F32 d);
@ -339,8 +331,8 @@ public:
private:
bool mApply;
glh::matrix4f mProjection;
glh::matrix4f mModelview;
glm::mat4 mProjection;
glm::mat4 mModelview;
};
/*
@ -354,9 +346,9 @@ class LLGLSquashToFarClip
{
public:
LLGLSquashToFarClip();
LLGLSquashToFarClip(glh::matrix4f& projection, U32 layer = 0);
LLGLSquashToFarClip(const glm::mat4& projection, U32 layer = 0);
void setProjectionMatrix(glh::matrix4f& projection, U32 layer);
void setProjectionMatrix(glm::mat4 projection, U32 layer);
~LLGLSquashToFarClip();
};

View File

@ -46,7 +46,7 @@
// LL_WINDOWS
// windows gl headers depend on things like APIENTRY, so include windows.
#include "llwin32headerslean.h"
#include "llwin32headers.h"
//----------------------------------------------------------------------------
#include <GL/gl.h>

View File

@ -63,6 +63,7 @@ U64 LLGLSLShader::sTotalTimeElapsed = 0;
U32 LLGLSLShader::sTotalTrianglesDrawn = 0;
U64 LLGLSLShader::sTotalSamplesDrawn = 0;
U32 LLGLSLShader::sTotalBinds = 0;
boost::json::value LLGLSLShader::sDefaultStats;
//UI shader -- declared here so llui_libtest will link properly
LLGLSLShader gUIProgram;
@ -101,9 +102,9 @@ void LLGLSLShader::initProfile()
sTotalSamplesDrawn = 0;
sTotalBinds = 0;
for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
for (auto ptr : sInstances)
{
(*iter)->clearStats();
ptr->clearStats();
}
}
@ -117,45 +118,57 @@ struct LLGLSLShaderCompareTimeElapsed
};
//static
void LLGLSLShader::finishProfile(bool emit_report)
void LLGLSLShader::finishProfile(boost::json::value& statsv)
{
sProfileEnabled = false;
if (emit_report)
if (! statsv.is_null())
{
std::vector<LLGLSLShader*> sorted;
for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
{
sorted.push_back(*iter);
}
std::vector<LLGLSLShader*> sorted(sInstances.begin(), sInstances.end());
std::sort(sorted.begin(), sorted.end(), LLGLSLShaderCompareTimeElapsed());
auto& stats = statsv.as_object();
auto shadersit = stats.emplace("shaders", boost::json::array_kind).first;
auto& shaders = shadersit->value().as_array();
bool unbound = false;
for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
for (auto ptr : sorted)
{
(*iter)->dumpStats();
if ((*iter)->mBinds == 0)
if (ptr->mBinds == 0)
{
unbound = true;
}
else
{
auto& shaderit = shaders.emplace_back(boost::json::object_kind);
ptr->dumpStats(shaderit.as_object());
}
}
constexpr float mega = 1'000'000.f;
float totalTimeMs = sTotalTimeElapsed / mega;
LL_INFOS() << "-----------------------------------" << LL_ENDL;
LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed / 1000000.f) << LL_ENDL;
LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn / 1000000.f) << LL_ENDL;
LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn / 1000000.f) << LL_ENDL;
LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", totalTimeMs) << LL_ENDL;
LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn / mega) << LL_ENDL;
LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn / mega) << LL_ENDL;
LL_INFOS() << "-----------------------------------" << LL_ENDL;
auto totalsit = stats.emplace("totals", boost::json::object_kind).first;
auto& totals = totalsit->value().as_object();
totals.emplace("time", totalTimeMs / 1000.0);
totals.emplace("binds", sTotalBinds);
totals.emplace("samples", sTotalSamplesDrawn);
totals.emplace("triangles", sTotalTrianglesDrawn);
auto unusedit = stats.emplace("unused", boost::json::array_kind).first;
auto& unused = unusedit->value().as_array();
if (unbound)
{
LL_INFOS() << "The following shaders were unused: " << LL_ENDL;
for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
for (auto ptr : sorted)
{
if ((*iter)->mBinds == 0)
if (ptr->mBinds == 0)
{
LL_INFOS() << (*iter)->mName << LL_ENDL;
LL_INFOS() << ptr->mName << LL_ENDL;
unused.emplace_back(ptr->mName);
}
}
}
@ -170,36 +183,43 @@ void LLGLSLShader::clearStats()
mBinds = 0;
}
void LLGLSLShader::dumpStats()
void LLGLSLShader::dumpStats(boost::json::object& stats)
{
if (mBinds > 0)
stats.emplace("name", mName);
auto filesit = stats.emplace("files", boost::json::array_kind).first;
auto& files = filesit->value().as_array();
LL_INFOS() << "=============================================" << LL_ENDL;
LL_INFOS() << mName << LL_ENDL;
for (U32 i = 0; i < mShaderFiles.size(); ++i)
{
LL_INFOS() << "=============================================" << LL_ENDL;
LL_INFOS() << mName << LL_ENDL;
for (U32 i = 0; i < mShaderFiles.size(); ++i)
{
LL_INFOS() << mShaderFiles[i].first << LL_ENDL;
}
LL_INFOS() << "=============================================" << LL_ENDL;
F32 ms = mTimeElapsed / 1000000.f;
F32 seconds = ms / 1000.f;
F32 pct_tris = (F32)mTrianglesDrawn / (F32)sTotalTrianglesDrawn * 100.f;
F32 tris_sec = (F32)(mTrianglesDrawn / 1000000.0);
tris_sec /= seconds;
F32 pct_samples = (F32)((F64)mSamplesDrawn / (F64)sTotalSamplesDrawn) * 100.f;
F32 samples_sec = (F32)(mSamplesDrawn / 1000000000.0);
samples_sec /= seconds;
F32 pct_binds = (F32)mBinds / (F32)sTotalBinds * 100.f;
LL_INFOS() << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec) << LL_ENDL;
LL_INFOS() << "Binds: " << mBinds << " " << llformat("(%.2f pct of total)", pct_binds) << LL_ENDL;
LL_INFOS() << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << LL_ENDL;
LL_INFOS() << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32)((F64)mTimeElapsed / (F64)sTotalTimeElapsed) * 100.f, ms) << LL_ENDL;
LL_INFOS() << mShaderFiles[i].first << LL_ENDL;
files.emplace_back(mShaderFiles[i].first);
}
LL_INFOS() << "=============================================" << LL_ENDL;
constexpr float mega = 1'000'000.f;
constexpr double giga = 1'000'000'000.0;
F32 ms = mTimeElapsed / mega;
F32 seconds = ms / 1000.f;
F32 pct_tris = (F32)mTrianglesDrawn / (F32)sTotalTrianglesDrawn * 100.f;
F32 tris_sec = (F32)(mTrianglesDrawn / mega);
tris_sec /= seconds;
F32 pct_samples = (F32)((F64)mSamplesDrawn / (F64)sTotalSamplesDrawn) * 100.f;
F32 samples_sec = (F32)(mSamplesDrawn / giga);
samples_sec /= seconds;
F32 pct_binds = (F32)mBinds / (F32)sTotalBinds * 100.f;
LL_INFOS() << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec) << LL_ENDL;
LL_INFOS() << "Binds: " << mBinds << " " << llformat("(%.2f pct of total)", pct_binds) << LL_ENDL;
LL_INFOS() << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << LL_ENDL;
LL_INFOS() << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32)((F64)mTimeElapsed / (F64)sTotalTimeElapsed) * 100.f, ms) << LL_ENDL;
stats.emplace("time", seconds);
stats.emplace("binds", mBinds);
stats.emplace("samples", mSamplesDrawn);
stats.emplace("triangles", mTrianglesDrawn);
}
//static
@ -1026,7 +1046,7 @@ void LLGLSLShader::bind()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
llassert(mProgramObject != 0);
llassert_always(mProgramObject != 0);
gGL.flush();
@ -1049,6 +1069,9 @@ void LLGLSLShader::bind()
LLShaderMgr::instance()->updateShaderUniforms(this);
mUniformsDirty = false;
}
llassert_always(sCurBoundShaderPtr != nullptr);
llassert_always(sCurBoundShader == mProgramObject);
}
void LLGLSLShader::bind(U8 variant)
@ -1087,17 +1110,17 @@ void LLGLSLShader::unbind(void)
sCurBoundShaderPtr = NULL;
}
S32 LLGLSLShader::bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
S32 LLGLSLShader::bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
S32 channel = 0;
channel = getUniformLocation(uniform);
return bindTexture(channel, texture, mode, colorspace);
return bindTexture(channel, texture, mode);
}
S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace)
S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@ -1113,7 +1136,6 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextu
if (uniform > -1)
{
gGL.getTexUnit(uniform)->bindFast(texture);
gGL.getTexUnit(uniform)->setTextureColorSpace(colorspace);
}
return uniform;
@ -1194,7 +1216,7 @@ S32 LLGLSLShader::getTextureChannel(S32 uniform) const
return mTexture[uniform];
}
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@ -1211,12 +1233,11 @@ S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTex
{
gGL.getTexUnit(index)->activate();
gGL.getTexUnit(index)->enable(mode);
gGL.getTexUnit(index)->setTextureColorSpace(space);
}
return index;
}
S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space)
S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@ -1229,7 +1250,7 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTe
S32 index = mTexture[uniform];
if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE)
{
if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode && gGL.getTexUnit(index)->getCurrColorSpace() != space)
if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode)
{
if (gDebugSession)
{
@ -1552,6 +1573,34 @@ void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v)
}
}
void LLGLSLShader::uniform4uiv(U32 index, U32 count, const GLuint* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
llassert(sCurBoundShaderPtr == this);
if (mProgramObject)
{
if (mUniform.size() <= index)
{
LL_WARNS_ONCE("Shader") << "Uniform index out of bounds. Size: " << (S32)mUniform.size() << " index: " << index << LL_ENDL;
llassert(false);
return;
}
if (mUniform[index] >= 0)
{
const auto& iter = mValue.find(mUniform[index]);
LLVector4 vec((F32)v[0], (F32)v[1], (F32)v[2], (F32)v[3]);
if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
glUniform4uiv(mUniform[index], count, v);
mValue[mUniform[index]] = vec;
}
}
}
}
void LLGLSLShader::uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@ -1817,6 +1866,23 @@ void LLGLSLShader::uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLf
}
}
void LLGLSLShader::uniform4f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
GLint location = getUniformLocation(uniform);
if (location >= 0)
{
const auto& iter = mValue.find(location);
LLVector4 vec(x, y, z, w);
if (iter == mValue.end() || shouldChange(iter->second, vec))
{
glUniform4f(location, x, y, z, w);
mValue[location] = vec;
}
}
}
void LLGLSLShader::uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
@ -1886,6 +1952,24 @@ void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, co
}
}
void LLGLSLShader::uniform4uiv(const LLStaticHashedString& uniform, U32 count, const GLuint* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
GLint location = getUniformLocation(uniform);
if (location >= 0)
{
LLVector4 vec((F32)v[0], (F32)v[1], (F32)v[2], (F32)v[3]);
const auto& iter = mValue.find(location);
if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
glUniform4uiv(location, count, v);
mValue[location] = vec;
}
}
}
void LLGLSLShader::uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;

View File

@ -30,6 +30,7 @@
#include "llgl.h"
#include "llrender.h"
#include "llstaticstringtable.h"
#include <boost/json.hpp>
#include <unordered_map>
class LLShaderFeatures
@ -51,6 +52,7 @@ public:
bool hasAmbientOcclusion = false;
bool hasSrgb = false;
bool isDeferred = false;
bool hasFullGBuffer = false;
bool hasScreenSpaceReflections = false;
bool hasAlphaMask = false;
bool hasReflectionProbes = false;
@ -169,14 +171,14 @@ public:
static U32 sMaxGLTFNodes;
static void initProfile();
static void finishProfile(bool emit_report = true);
static void finishProfile(boost::json::value& stats=sDefaultStats);
static void startProfile();
static void stopProfile();
void unload();
void clearStats();
void dumpStats();
void dumpStats(boost::json::object& stats);
// place query objects for profiling if profiling is enabled
// if for_runtime is true, will place timer query only whether or not profiling is enabled
@ -208,6 +210,7 @@ public:
void uniform2fv(U32 index, U32 count, const GLfloat* v);
void uniform3fv(U32 index, U32 count, const GLfloat* v);
void uniform4fv(U32 index, U32 count, const GLfloat* v);
void uniform4uiv(U32 index, U32 count, const GLuint* v);
void uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j);
void uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v);
void uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat* v);
@ -219,10 +222,12 @@ public:
void uniform1f(const LLStaticHashedString& uniform, GLfloat v);
void uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y);
void uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z);
void uniform4f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
void uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
void uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
void uniform4fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v);
void uniform4uiv(const LLStaticHashedString& uniform, U32 count, const GLuint* v);
void uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat* v);
void setMinimumAlpha(F32 minimum);
@ -239,6 +244,10 @@ public:
void clearPermutations();
void addPermutation(std::string name, std::string value);
void addPermutations(const std::map<std::string, std::string>& defines)
{
mDefines.insert(defines.begin(), defines.end());
}
void removePermutation(std::string name);
void addConstant(const LLGLSLShader::eShaderConsts shader_const);
@ -247,16 +256,16 @@ public:
//if given texture uniform is active in the shader,
//the corresponding channel will be active upon return
//returns channel texture is enabled in from [0-MAX)
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);
S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
// 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);
S32 bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR);
S32 bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
S32 bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
S32 bindTexture(const std::string& uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR);
S32 bindTexture(S32 uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR, U32 index = 0);
S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
@ -357,6 +366,11 @@ public:
private:
void unloadInternal();
// This must be static because finishProfile() is called at least once
// within a __try block. If we default its stats parameter to a temporary
// json::value, that temporary must be destroyed when the stack is
// unwound, which __try forbids.
static boost::json::value sDefaultStats;
};
//UI shader (declared here so llui_libtest will link properly)

View File

@ -51,6 +51,7 @@ extern LL_COMMON_API bool on_main_thread();
//----------------------------------------------------------------------------
const F32 MIN_TEXTURE_LIFETIME = 10.f;
const F32 CONVERSION_SCRATCH_BUFFER_GL_VERSION = 3.29f;
//which power of 2 is i?
//assumes i is a power of 2 > 0
@ -67,12 +68,13 @@ static U64 sTextureBytes = 0;
// track a texture alloc on the currently bound texture.
// asserts that no currently tracked alloc exists
void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 pixformat)
void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 intformat, U32 count)
{
U32 texUnit = gGL.getCurrentTexUnitIndex();
llassert(texUnit == 0); // allocations should always be done on tex unit 0
U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture();
U64 size = LLImageGL::dataFormatBytes(pixformat, width, height);
U64 size = LLImageGL::dataFormatBytes(intformat, width, height);
size *= count;
llassert(size >= 0);
@ -159,6 +161,7 @@ S32 LLImageGL::sMaxCategories = 1 ;
bool LLImageGL::sSkipAnalyzeAlpha;
U32 LLImageGL::sScratchPBO = 0;
U32 LLImageGL::sScratchPBOSize = 0;
U32* LLImageGL::sManualScratch = nullptr;
//------------------------
@ -256,8 +259,24 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, bool skip_analyz
if (thread_texture_loads || thread_media_updates)
{
LLImageGLThread::createInstance(window);
LLImageGLThread::sEnabledTextures = thread_texture_loads;
LLImageGLThread::sEnabledMedia = thread_media_updates;
LLImageGLThread::sEnabledTextures = gGLManager.mGLVersion > 3.95f ? thread_texture_loads : false;
LLImageGLThread::sEnabledMedia = gGLManager.mGLVersion > 3.95f ? thread_media_updates : false;
}
}
void LLImageGL::allocateConversionBuffer()
{
if (gGLManager.mGLVersion < CONVERSION_SCRATCH_BUFFER_GL_VERSION)
{
try
{
sManualScratch = new U32[MAX_IMAGE_AREA];
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Failed to allocate sManualScratch" << LL_ENDL;
}
}
}
@ -272,6 +291,8 @@ void LLImageGL::cleanupClass()
sScratchPBO = 0;
sScratchPBOSize = 0;
}
delete[] sManualScratch;
}
@ -280,6 +301,15 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
{
switch (dataformat)
{
case GL_COMPRESSED_RED: return 8;
case GL_COMPRESSED_RG: return 16;
case GL_COMPRESSED_RGB: return 24;
case GL_COMPRESSED_SRGB: return 32;
case GL_COMPRESSED_RGBA: return 32;
case GL_COMPRESSED_SRGB_ALPHA: return 32;
case GL_COMPRESSED_LUMINANCE: return 8;
case GL_COMPRESSED_LUMINANCE_ALPHA: return 16;
case GL_COMPRESSED_ALPHA: return 8;
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4;
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 4;
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8;
@ -287,21 +317,36 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8;
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 8;
case GL_LUMINANCE: return 8;
case GL_LUMINANCE8: return 8;
case GL_ALPHA: return 8;
case GL_ALPHA8: return 8;
case GL_RED: return 8;
case GL_R8: return 8;
case GL_COLOR_INDEX: return 8;
case GL_LUMINANCE_ALPHA: return 16;
case GL_LUMINANCE8_ALPHA8: return 16;
case GL_RG: return 16;
case GL_RG8: return 16;
case GL_RGB: return 24;
case GL_SRGB: return 24;
case GL_RGB8: return 24;
case GL_RGBA: return 32;
case GL_RGBA8: return 32;
case GL_RGB10_A2: return 32;
case GL_SRGB_ALPHA: return 32;
case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac
case GL_DEPTH_COMPONENT: return 24;
case GL_DEPTH_COMPONENT24: return 24;
case GL_R16F: return 16;
case GL_RG16F: return 32;
case GL_RGB16F: return 48;
case GL_RGBA16F: return 64;
case GL_R32F: return 32;
case GL_RG32F: return 64;
case GL_RGB32F: return 96;
case GL_RGBA32F: return 128;
default:
LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL;
LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL;
return 0;
}
}
@ -344,13 +389,14 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
case GL_RED: return 1;
case GL_COLOR_INDEX: return 1;
case GL_LUMINANCE_ALPHA: return 2;
case GL_RG: return 2;
case GL_RGB: return 3;
case GL_SRGB: return 3;
case GL_RGBA: return 4;
case GL_SRGB_ALPHA: return 4;
case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac
default:
LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL;
LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL;
return 0;
}
}
@ -411,29 +457,29 @@ bool LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, b
//----------------------------------------------------------------------------
LLImageGL::LLImageGL(bool usemipmaps)
LLImageGL::LLImageGL(bool usemipmaps/* = true*/, bool allow_compression/* = true*/)
: mSaveData(0), mExternalTexture(false)
{
init(usemipmaps);
init(usemipmaps, allow_compression);
setSize(0, 0, 0);
sImageList.insert(this);
sCount++;
}
LLImageGL::LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps)
LLImageGL::LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps/* = true*/, bool allow_compression/* = true*/)
: mSaveData(0), mExternalTexture(false)
{
llassert( components <= 4 );
init(usemipmaps);
init(usemipmaps, allow_compression);
setSize(width, height, components);
sImageList.insert(this);
sCount++;
}
LLImageGL::LLImageGL(const LLImageRaw* imageraw, bool usemipmaps)
LLImageGL::LLImageGL(const LLImageRaw* imageraw, bool usemipmaps/* = true*/, bool allow_compression/* = true*/)
: mSaveData(0), mExternalTexture(false)
{
init(usemipmaps);
init(usemipmaps, allow_compression);
setSize(0, 0, 0);
sImageList.insert(this);
sCount++;
@ -450,7 +496,7 @@ LLImageGL::LLImageGL(
LLGLenum formatType,
LLTexUnit::eTextureAddressMode addressMode)
{
init(false);
init(false, true);
mTexName = texName;
mTarget = target;
mComponents = components;
@ -472,7 +518,7 @@ LLImageGL::~LLImageGL()
}
}
void LLImageGL::init(bool usemipmaps)
void LLImageGL::init(bool usemipmaps, bool allow_compression)
{
#if LL_IMAGEGL_THREAD_CHECK
mActiveThread = LLThread::currentID();
@ -502,7 +548,7 @@ void LLImageGL::init(bool usemipmaps)
mHeight = 0;
mCurrentDiscardLevel = -1;
mAllowCompression = true;
mAllowCompression = allow_compression;
mTarget = GL_TEXTURE_2D;
mBindTarget = LLTexUnit::TT_TEXTURE;
@ -1006,7 +1052,7 @@ U32 type_width_from_pixtype(U32 pixtype)
bool should_stagger_image_set(bool compressed)
{
#if LL_DARWIN
return false;
return !compressed && on_main_thread() && gGLManager.mIsAMD;
#else
// glTexSubImage2D doesn't work with compressed textures on select tested Nvidia GPUs on Windows 10 -Cosmic,2023-03-08
// Setting media textures off-thread seems faster when not using sub_image_lines (Nvidia/Windows 10) -Cosmic,2023-03-31
@ -1020,15 +1066,47 @@ void sub_image_lines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 w
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
LL_PROFILE_ZONE_NUM(width);
LL_PROFILE_ZONE_NUM(height);
U32 components = LLImageGL::dataFormatComponents(pixformat);
U32 type_width = type_width_from_pixtype(pixtype);
const U32 line_width = data_width * components * type_width;
const U32 y_offset_end = y_offset + height;
for (U32 y_pos = y_offset; y_pos < y_offset_end; ++y_pos)
if (width == data_width && height % 32 == 0)
{
glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src);
src += line_width;
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("subimage - batched lines");
// full width, batch multiple lines at a time
// set batch size based on width
U32 batch_size = 32;
if (width > 1024)
{
batch_size = 8;
}
else if (width > 512)
{
batch_size = 16;
}
// full width texture, do 32 lines at a time
for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += batch_size)
{
glTexSubImage2D(target, miplevel, x_offset, y_pos, width, batch_size, pixformat, pixtype, src);
src += line_width * batch_size;
}
}
else
{
// partial width or strange height
for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += 1)
{
glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src);
src += line_width;
}
}
}
@ -1192,37 +1270,37 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
}
}
constexpr int DELETE_DELAY = 3; // number of frames to wait before deleting textures
static std::vector<U32> sFreeList[DELETE_DELAY+1];
// static
void LLImageGL::updateClass()
{
sFrameCount++;
// wait a few frames before actually deleting the textures to avoid
// synchronization issues with the GPU
U32 idx = (sFrameCount+DELETE_DELAY) % (DELETE_DELAY+1);
if (!sFreeList[idx].empty())
{
free_tex_images((GLsizei) sFreeList[idx].size(), sFreeList[idx].data());
glDeleteTextures((GLsizei)sFreeList[idx].size(), sFreeList[idx].data());
sFreeList[idx].resize(0);
}
}
// static
void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
{
// wait a few frames before actually deleting the textures to avoid
// synchronization issues with the GPU
static std::vector<U32> sFreeList[4];
if (gGLManager.mInited)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
U32 idx = sFrameCount % 4;
U32 idx = sFrameCount % (DELETE_DELAY+1);
for (S32 i = 0; i < numTextures; ++i)
{
sFreeList[idx].push_back(textures[i]);
}
idx = (sFrameCount + 3) % 4;
if (!sFreeList[idx].empty())
{
free_tex_images((GLsizei) sFreeList[idx].size(), sFreeList[idx].data());
glDeleteTextures((GLsizei)sFreeList[idx].size(), sFreeList[idx].data());
sFreeList[idx].resize(0);
}
}
}
@ -1230,100 +1308,97 @@ void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void* pixels, bool allow_compression)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
bool use_scratch = false;
U32* scratch = NULL;
if (LLRender::sGLCoreProfile)
{
if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
{ //GL_ALPHA is deprecated, convert to RGBA
if (pixels != nullptr)
{
use_scratch = true;
scratch = new(std::nothrow) U32[width * height];
if (!scratch)
{
LLError::LLUserWarningMsg::showOutOfMemory();
// <FS:Beq> FIRE-34374 - OOM Crash 80% of which are in render debug text
// LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
// << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
LL_WARNS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL;
return;
// </FS:Beq>
}
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8* pix = (U8*)&scratch[i];
pix[0] = pix[1] = pix[2] = 0;
pix[3] = ((U8*)pixels)[i];
}
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
if (gGLManager.mGLVersion >= CONVERSION_SCRATCH_BUFFER_GL_VERSION)
{
if (pixformat == GL_ALPHA)
{ //GL_ALPHA is deprecated, convert to RGBA
const GLint mask[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
pixformat = GL_RED;
intformat = GL_R8;
}
pixformat = GL_RGBA;
intformat = GL_RGBA8;
if (pixformat == GL_LUMINANCE)
{ //GL_LUMINANCE is deprecated, convert to GL_RGBA
const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
pixformat = GL_RED;
intformat = GL_R8;
}
if (pixformat == GL_LUMINANCE_ALPHA)
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
pixformat = GL_RG;
intformat = GL_RG8;
}
}
if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
if (pixels != nullptr)
{
use_scratch = true;
scratch = new(std::nothrow) U32[width * height];
if (!scratch)
else
{
if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
{ //GL_ALPHA is deprecated, convert to RGBA
if (pixels != nullptr)
{
LLError::LLUserWarningMsg::showOutOfMemory();
// <FS:Beq> FIRE-34374 - OOM Crash 80% of which are in render debug text
// LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
// << " bytes for a manual image W" << width << " H" << height << LL_ENDL;
LL_WARNS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL;
return;
// </FS:Beq>
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8* pix = (U8*)&sManualScratch[i];
pix[0] = pix[1] = pix[2] = 0;
pix[3] = ((U8*)pixels)[i];
}
pixels = sManualScratch;
}
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8 lum = ((U8*)pixels)[i * 2 + 0];
U8 alpha = ((U8*)pixels)[i * 2 + 1];
U8* pix = (U8*)&scratch[i];
pix[0] = pix[1] = pix[2] = lum;
pix[3] = alpha;
}
pixformat = GL_RGBA;
intformat = GL_RGBA8;
}
pixformat = GL_RGBA;
intformat = GL_RGBA8;
}
if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
if (pixels != nullptr)
{
use_scratch = true;
scratch = new(std::nothrow) U32[width * height];
if (!scratch)
if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
if (pixels != nullptr)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32))
<< " bytes for a manual image W" << width << " H" << height << LL_ENDL;
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8 lum = ((U8*)pixels)[i * 2 + 0];
U8 alpha = ((U8*)pixels)[i * 2 + 1];
U8* pix = (U8*)&sManualScratch[i];
pix[0] = pix[1] = pix[2] = lum;
pix[3] = alpha;
}
pixels = sManualScratch;
}
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8 lum = ((U8*)pixels)[i];
U8* pix = (U8*)&scratch[i];
pix[0] = pix[1] = pix[2] = lum;
pix[3] = 255;
}
pixformat = GL_RGBA;
intformat = GL_RGBA8;
}
if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
if (pixels != nullptr)
{
U32 pixel_count = (U32)(width * height);
for (U32 i = 0; i < pixel_count; i++)
{
U8 lum = ((U8*)pixels)[i];
U8* pix = (U8*)&sManualScratch[i];
pix[0] = pix[1] = pix[2] = lum;
pix[3] = 255;
}
pixels = sManualScratch;
}
pixformat = GL_RGBA;
intformat = GL_RGB8;
}
pixformat = GL_RGBA;
intformat = GL_RGB8;
}
}
@ -1332,6 +1407,14 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
{
switch (intformat)
{
case GL_RED:
case GL_R8:
intformat = GL_COMPRESSED_RED;
break;
case GL_RG:
case GL_RG8:
intformat = GL_COMPRESSED_RG;
break;
case GL_RGB:
case GL_RGB8:
intformat = GL_COMPRESSED_RGB;
@ -1360,12 +1443,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
case GL_ALPHA8:
intformat = GL_COMPRESSED_ALPHA;
break;
case GL_RED:
case GL_R8:
intformat = GL_COMPRESSED_RED;
break;
default:
LL_WARNS() << "Could not compress format: " << std::hex << intformat << LL_ENDL;
LL_WARNS() << "Could not compress format: " << std::hex << intformat << std::dec << LL_ENDL;
break;
}
}
@ -1381,7 +1460,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
if (!use_sub_image)
{
LL_PROFILE_ZONE_NAMED("glTexImage2D alloc + copy");
glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels);
}
else
{
@ -1391,21 +1470,16 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, nullptr);
}
U8* src = (U8*)(use_scratch ? scratch : pixels);
U8* src = (U8*)(pixels);
if (src)
{
LL_PROFILE_ZONE_NAMED("glTexImage2D copy");
sub_image_lines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src, width);
}
}
alloc_tex_image(width, height, pixformat);
alloc_tex_image(width, height, intformat, 1);
}
stop_glerror();
if (use_scratch)
{
delete[] scratch;
}
}
//create an empty GL texture: just create a texture name
@ -2093,6 +2167,8 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
return ;
}
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
U32 length = w * h;
U32 alphatotal = 0;
@ -2106,13 +2182,13 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
// suffer the worst from aliasing when used as alpha masks.
if (w >= 2 && h >= 2)
{
llassert(w%2 == 0);
llassert(h%2 == 0);
llassert(w % 2 == 0);
llassert(h % 2 == 0);
const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset;
for (U32 y = 0; y < h; y+=2)
for (U32 y = 0; y < h; y += 2)
{
const GLubyte* current = rowstart;
for (U32 x = 0; x < w; x+=2)
for (U32 x = 0; x < w; x += 2)
{
const U32 s1 = current[0];
alphatotal += s1;
@ -2135,7 +2211,6 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
sample[asum/(16*4)] += 4;
}
rowstart += 2 * w * mAlphaStride;
}
length *= 2; // we sampled everything twice, essentially
@ -2362,7 +2437,9 @@ bool LLImageGL::scaleDown(S32 desired_discard)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
if (mTarget != GL_TEXTURE_2D)
if (mTarget != GL_TEXTURE_2D
|| mFormatInternal == -1 // not initialized
)
{
return false;
}
@ -2381,41 +2458,32 @@ bool LLImageGL::scaleDown(S32 desired_discard)
if (gGLManager.mDownScaleMethod == 0)
{ // use an FBO to downscale the texture
// allocate new texture
U32 temp_texname = 0;
generateTextures(1, &temp_texname);
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, temp_texname, true);
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glTexImage2D");
glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, NULL);
}
// account for new texture getting created
alloc_tex_image(desired_width, desired_height, mFormatPrimary);
// Use render-to-texture to scale down the texture
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glFramebufferTexture2D");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTarget, temp_texname, 0);
}
glViewport(0, 0, desired_width, desired_height);
// draw a full screen triangle
gGL.getTexUnit(0)->bind(this);
glDrawArrays(GL_TRIANGLES, 0, 3);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
if (gGL.getTexUnit(0)->bind(this, true, true))
{
glDrawArrays(GL_TRIANGLES, 0, 3);
// delete old texture and assign new texture name
deleteTextures(1, &mTexName);
mTexName = temp_texname;
free_tex_image(mTexName);
glTexImage2D(mTarget, 0, mFormatInternal, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
glCopyTexSubImage2D(mTarget, 0, 0, 0, 0, 0, desired_width, desired_height);
alloc_tex_image(desired_width, desired_height, mFormatInternal, 1);
if (mHasMipMaps)
{ // generate mipmaps if needed
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
gGL.getTexUnit(0)->bind(this);
glGenerateMipmap(mTarget);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
mTexOptionsDirty = true;
if (mHasMipMaps)
{ // generate mipmaps if needed
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
gGL.getTexUnit(0)->bind(this);
glGenerateMipmap(mTarget);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
}
else
{
LL_WARNS_ONCE("LLImageGL") << "Failed to bind texture for downscaling." << LL_ENDL;
return false;
}
}
else
@ -2445,10 +2513,10 @@ bool LLImageGL::scaleDown(S32 desired_discard)
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sScratchPBO);
glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
glTexImage2D(mTarget, 0, mFormatInternal, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
alloc_tex_image(desired_width, desired_height, mFormatPrimary);
alloc_tex_image(desired_width, desired_height, mFormatInternal, 1);
if (mHasMipMaps)
{

View File

@ -50,7 +50,7 @@ class LLWindow;
namespace LLImageGLMemory
{
void alloc_tex_image(U32 width, U32 height, U32 pixformat);
void alloc_tex_image(U32 width, U32 height, U32 intformat, U32 count);
void free_tex_image(U32 texName);
void free_tex_images(U32 count, const U32* texNames);
void free_cur_tex_image();
@ -101,9 +101,9 @@ public:
static bool create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, bool usemipmaps = true);
public:
LLImageGL(bool usemipmaps = true);
LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps = true);
LLImageGL(const LLImageRaw* imageraw, bool usemipmaps = true);
LLImageGL(bool usemipmaps = true, bool allow_compression = true);
LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps = true, bool allow_compression = true);
LLImageGL(const LLImageRaw* imageraw, bool usemipmaps = true, bool allow_compression = true);
// For wrapping textures created via GL elsewhere with our API only. Use with caution.
LLImageGL(LLGLuint mTexName, U32 components, LLGLenum target, LLGLint formatInternal, LLGLenum formatPrimary, LLGLenum formatType, LLTexUnit::eTextureAddressMode addressMode);
@ -206,7 +206,7 @@ public:
LLGLenum getTexTarget()const { return mTarget; }
void init(bool usemipmaps);
void init(bool usemipmaps, bool allow_compression);
virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors
void setNeedsAlphaAndPickMask(bool need_mask);
@ -301,6 +301,7 @@ public:
public:
static void initClass(LLWindow* window, S32 num_catagories, bool skip_analyze_alpha = false, bool thread_texture_loads = false, bool thread_media_updates = false);
static void allocateConversionBuffer();
static void cleanupClass() ;
private:
@ -308,6 +309,7 @@ private:
static bool sSkipAnalyzeAlpha;
static U32 sScratchPBO;
static U32 sScratchPBOSize;
static U32* sManualScratch;
//the flag to allow to call readBackRaw(...).
//can be removed if we do not use that function at all.

File diff suppressed because it is too large Load Diff

View File

@ -42,25 +42,17 @@
#include "llpointer.h"
#include "llglheaders.h"
#include "llmatrix4a.h"
#if LL_LINUX && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) >= 70000
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmisleading-indentation"
#endif
#include "glh/glh_linear.h"
#if LL_LINUX && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) >= 70000
#pragma GCC diagnostic push
#endif
#include "glm/mat4x4.hpp"
#include <array>
#include <list>
class LLVertexBuffer;
class LLCubeMap;
class LLImageGL;
class LLRenderTarget;
class LLTexture ;
class LLTexture;
class LLVertexBufferData;
#define LL_MATRIX_STACK_DEPTH 32
@ -229,17 +221,12 @@ public:
void setHasMipMaps(bool hasMips) { mHasMipMaps = hasMips; }
void setTextureColorSpace(eTextureColorSpace space);
eTextureColorSpace getCurrColorSpace() { return mTexColorSpace; }
protected:
friend class LLRender;
S32 mIndex;
U32 mCurrTexture;
eTextureType mCurrTexType;
eTextureColorSpace mTexColorSpace;
S32 mCurrColorScale;
S32 mCurrAlphaScale;
bool mHasMipMaps;
@ -332,8 +319,6 @@ public:
POINTS,
LINES,
LINE_STRIP,
// <FS:Ansariel> Remove QUADS rendering mode
//QUADS,
LINE_LOOP,
NUM_MODES
};
@ -415,8 +400,8 @@ public:
void matrixMode(eMatrixMode mode);
eMatrixMode getMatrixMode();
const glh::matrix4f& getModelviewMatrix();
const glh::matrix4f& getProjectionMatrix();
const glm::mat4& getModelviewMatrix();
const glm::mat4& getProjectionMatrix();
void syncMatrices();
void syncLightState();
@ -431,8 +416,15 @@ public:
void flush();
// if list is set, will store buffers in list for later use, if list isn't set, will use cache
void beginList(std::list<LLVertexBufferData> *list);
void endList();
void begin(const GLuint& mode);
void end();
U8 getMode() const { return mMode; }
void vertex2i(const GLint& x, const GLint& y);
void vertex2f(const GLfloat& x, const GLfloat& y);
void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z);
@ -457,9 +449,9 @@ public:
void diffuseColor4ubv(const U8* c);
void diffuseColor4ub(U8 r, U8 g, U8 b, U8 a);
void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
void vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count);
void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count);
void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
void setColorMask(bool writeColor, bool writeAlpha);
void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha);
@ -499,21 +491,25 @@ public:
static bool sGLCoreProfile;
static bool sNsightDebugSupport;
static LLVector2 sUIGLScaleFactor;
static bool sClassicMode; // classic sky mode active
private:
friend class LLLightState;
LLVertexBuffer* bufferfromCache(U32 attribute_mask, U32 count);
LLVertexBuffer* genBuffer(U32 attribute_mask, S32 count);
void drawBuffer(LLVertexBuffer* vb, U32 mode, S32 count);
void resetStriders(S32 count);
eMatrixMode mMatrixMode;
U32 mMatIdx[NUM_MATRIX_MODES];
U32 mMatHash[NUM_MATRIX_MODES];
glh::matrix4f mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH];
glm::mat4 mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH];
U32 mCurMatHash[NUM_MATRIX_MODES];
U32 mLightHash;
LLColor4 mAmbientLightColor;
bool mDirty;
// <FS:Ansariel> Remove QUADS rendering mode
//U32 mQuadCycle;
U32 mCount;
U32 mMode;
U32 mCurrTextureUnitIndex;
@ -525,7 +521,7 @@ private:
// </FS:Ansariel>
LLPointer<LLVertexBuffer> mBuffer;
LLStrider<LLVector3> mVerticesp;
LLStrider<LLVector4a> mVerticesp;
LLStrider<LLVector2> mTexcoordsp;
LLStrider<LLColor4U> mColorsp;
std::array<LLTexUnit, LL_NUM_TEXTURE_LAYERS> mTexUnits;
@ -539,7 +535,6 @@ private:
std::vector<LLVector3> mUIOffset;
std::vector<LLVector3> mUIScale;
};
extern F32 gGLModelView[16];
@ -547,8 +542,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 glm::mat4 gGLDeltaModelView;
extern glm::mat4 gGLInverseDeltaModelView;
extern thread_local LLRender gGL;
@ -559,19 +554,20 @@ const F32 OGL_TO_CFR_ROTATION[16] = { 0.f, 0.f, -1.f, 0.f, // -Z becomes X
0.f, 1.f, 0.f, 0.f, // Y becomes Z
0.f, 0.f, 0.f, 1.f };
glh::matrix4f copy_matrix(F32* src);
glh::matrix4f get_current_modelview();
glh::matrix4f get_current_projection();
glh::matrix4f get_last_modelview();
glh::matrix4f get_last_projection();
glm::mat4 copy_matrix(F32* src);
glm::mat4 get_current_modelview();
glm::mat4 get_current_projection();
glm::mat4 get_last_modelview();
glm::mat4 get_last_projection();
void copy_matrix(const glh::matrix4f& src, F32* dst);
void set_current_modelview(const glh::matrix4f& mat);
void set_current_projection(glh::matrix4f& mat);
void copy_matrix(const glm::mat4& src, F32* dst);
void set_current_modelview(const glm::mat4& mat);
void set_current_projection(const glm::mat4& mat);
void set_last_modelview(const glm::mat4& mat);
void set_last_projection(const glm::mat4& mat);
glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar);
glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar);
glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up);
// glh compat
glm::vec3 mul_mat4_vec3(const glm::mat4& mat, const glm::vec3& vec);
#define LL_SHADER_LOADING_WARNS(...) LL_WARNS()

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,8 @@
#include "llerror.h"
#include "llglheaders.h"
#include "llvertexbuffer.h"
#include "llglslshader.h"
LLRenderSphere gSphere;
@ -53,12 +55,20 @@ inline LLVector3 polar_to_cart(F32 latitude, F32 longitude)
void LLRenderSphere::renderGGL()
{
LL_PROFILE_ZONE_SCOPED;
S32 const LATITUDE_SLICES = 20;
S32 const LONGITUDE_SLICES = 30;
if (mSpherePoints.empty())
if (mVertexBuffer.isNull())
{
mSpherePoints.resize(LATITUDE_SLICES + 1);
mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX);
mVertexBuffer->allocateBuffer((U32)(LATITUDE_SLICES + 1) * (LONGITUDE_SLICES + 1), LATITUDE_SLICES * LONGITUDE_SLICES * 6);
LLStrider<LLVector3> v;
mVertexBuffer->getVertexStrider(v);
for (S32 lat_i = 0; lat_i < LATITUDE_SLICES + 1; lat_i++)
{
mSpherePoints[lat_i].resize(LONGITUDE_SLICES + 1);
@ -68,24 +78,52 @@ void LLRenderSphere::renderGGL()
F32 lon = (F32)lon_i / LONGITUDE_SLICES;
mSpherePoints[lat_i][lon_i] = polar_to_cart(lat, lon);
v[lat_i * (LONGITUDE_SLICES + 1) + lon_i] = mSpherePoints[lat_i][lon_i];
}
}
}
gGL.begin(LLRender::TRIANGLES);
LLStrider<U16> i;
mVertexBuffer->getIndexStrider(i);
for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++)
{
for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++)
for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++)
{
gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV);
gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV);
gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV);
for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++)
{
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 0] = lat_i * (LONGITUDE_SLICES + 1) + lon_i;
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 1] = lat_i * (LONGITUDE_SLICES + 1) + lon_i + 1;
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 2] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i;
gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV);
gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV);
gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i+1].mV);
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 3] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i;
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 4] = lat_i * (LONGITUDE_SLICES + 1) + lon_i + 1;
i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 5] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i + 1;
}
}
mVertexBuffer->unmapBuffer();
}
if (LLGLSLShader::sCurBoundShaderPtr->mAttributeMask == LLVertexBuffer::MAP_VERTEX)
{ // shader expects only vertex positions in vertex buffer, use fast path
mVertexBuffer->setBuffer();
mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, mVertexBuffer->getNumVerts(), mVertexBuffer->getNumIndices(), 0);
}
else
{ //shader wants colors in the vertex stream, use slow path
gGL.begin(LLRender::TRIANGLES);
for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++)
{
for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++)
{
gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV);
gGL.vertex3fv(mSpherePoints[lat_i][lon_i + 1].mV);
gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i].mV);
gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i].mV);
gGL.vertex3fv(mSpherePoints[lat_i][lon_i + 1].mV);
gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i + 1].mV);
}
}
gGL.end();
}
gGL.end();
}

View File

@ -45,6 +45,7 @@ public:
private:
std::vector< std::vector<LLVector3> > mSpherePoints;
LLPointer<LLVertexBuffer> mVertexBuffer;
};
extern LLRenderSphere gSphere;

View File

@ -475,12 +475,10 @@ void LLRenderTarget::clear(U32 mask_in)
U32 LLRenderTarget::getTexture(U32 attachment) const
{
if (attachment > mTex.size()-1)
{
LL_ERRS() << "Invalid attachment index." << LL_ENDL;
}
if (mTex.empty())
if (attachment >= mTex.size())
{
LL_WARNS() << "Invalid attachment index " << attachment << " for size " << mTex.size() << LL_ENDL;
llassert(false);
return 0;
}
return mTex[attachment];
@ -511,7 +509,6 @@ void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilt
}
gGL.getTexUnit(channel)->setTextureFilteringOption(filter_options);
gGL.getTexUnit(channel)->setTextureColorSpace(isSRGB ? LLTexUnit::TCS_SRGB : LLTexUnit::TCS_LINEAR);
}
void LLRenderTarget::flush()

View File

@ -79,7 +79,7 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
//////////////////////////////////////
// NOTE order of shader object attaching is VERY IMPORTANT!!!
if (features->calculatesAtmospherics)
if (features->calculatesAtmospherics || features->hasGamma || features->isDeferred)
{
if (!shader->attachVertexObject("windlight/atmosphericsVarsV.glsl"))
{
@ -223,6 +223,14 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
}
}
if (features->hasFullGBuffer)
{
if (!shader->attachFragmentObject("deferred/gbufferUtil.glsl"))
{
return false;
}
}
if (features->hasScreenSpaceReflections || features->hasReflectionProbes)
{
if (!shader->attachFragmentObject("deferred/screenSpaceReflUtil.glsl"))
@ -565,17 +573,11 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
}
else if (major_version == 3)
{
if (minor_version < 10)
if (minor_version <= 29)
{
shader_code_text[shader_code_count++] = strdup("#version 300\n");
}
else if (minor_version <= 19)
{
shader_code_text[shader_code_count++] = strdup("#version 310\n");
}
else if (minor_version <= 29)
{
shader_code_text[shader_code_count++] = strdup("#version 320\n");
// OpenGL 3.2 had GLSL version 1.50. anything after that the version numbers match.
// https://www.khronos.org/opengl/wiki/Core_Language_(GLSL)#OpenGL_and_GLSL_versions
shader_code_text[shader_code_count++] = strdup("#version 150\n");
}
else
{
@ -584,7 +586,8 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
}
else
{
if (type == GL_GEOMETRY_SHADER)
// OpenGL 3.2 had GLSL version 1.50. anything after that the version numbers match.
if (type == GL_GEOMETRY_SHADER || minor_version >= 50)
{
//set version to 1.50
shader_code_text[shader_code_count++] = strdup("#version 150\n");
@ -601,8 +604,15 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
extra_code_text[extra_code_count++] = strdup("precision highp float;\n");
}
}
}
extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_130 1\n");
if (type == GL_FRAGMENT_SHADER)
{
extra_code_text[extra_code_count++] = strdup("#define FRAGMENT_SHADER 1\n");
}
else
{
extra_code_text[extra_code_count++] = strdup("#define VERTEX_SHADER 1\n");
}
// Use alpha float to store bit flags
@ -611,7 +621,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_ATMOS 0.34\n"); // bit 0
extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_PBR 0.67\n"); // bit 1
extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_HDRI 1.0\n"); // bit 2
extra_code_text[extra_code_count++] = strdup("#define GET_GBUFFER_FLAG(flag) (abs(norm.w-flag)< 0.1)\n");
extra_code_text[extra_code_count++] = strdup("#define GET_GBUFFER_FLAG(data, flag) (abs(data-flag)< 0.1)\n");
if (defines)
{
@ -722,6 +732,9 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
}
}
// Master definition can be found in deferredUtil.glsl
extra_code_text[extra_code_count++] = strdup("struct GBufferInfo { vec4 albedo; vec4 specular; vec3 normal; vec4 emissive; float gbufferFlag; float envIntensity; };\n");
//copy file into memory
enum {
flag_write_to_out_of_extra_block_area = 0x01
@ -1254,6 +1267,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("sky_hdr_scale");
mReservedUniforms.push_back("sky_sunlight_scale");
mReservedUniforms.push_back("sky_ambient_scale");
mReservedUniforms.push_back("classic_mode");
mReservedUniforms.push_back("blue_horizon");
mReservedUniforms.push_back("blue_density");
mReservedUniforms.push_back("haze_horizon");
@ -1488,6 +1502,11 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("debug_normal_draw_length");
mReservedUniforms.push_back("edgesTex");
mReservedUniforms.push_back("areaTex");
mReservedUniforms.push_back("searchTex");
mReservedUniforms.push_back("blendTex");
llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
std::set<std::string> dupe_check;

View File

@ -121,6 +121,7 @@ public:
SKY_HDR_SCALE, // "sky_hdr_scale"
SKY_SUNLIGHT_SCALE, // "sky_sunlight_scale"
SKY_AMBIENT_SCALE, // "sky_ambient_scale"
CLASSIC_MODE, // "classic_mode"
BLUE_HORIZON, // "blue_horizon"
BLUE_DENSITY, // "blue_density"
HAZE_HORIZON, // "haze_horizon"
@ -345,6 +346,11 @@ public:
DEBUG_NORMAL_DRAW_LENGTH, // "debug_normal_draw_length"
SMAA_EDGE_TEX, // "edgesTex"
SMAA_AREA_TEX, // "areaTex"
SMAA_SEARCH_TEX, // "searchTex"
SMAA_BLEND_TEX, // "blendTex"
END_RESERVED_UNIFORMS
} eGLSLReservedUniforms;
// clang-format on

View File

@ -36,6 +36,7 @@
#include "llshadermgr.h"
#include "llglslshader.h"
#include "llmemory.h"
#include <glm/gtc/type_ptr.hpp>
//Next Highest Power Of Two
//helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
@ -272,11 +273,13 @@ static GLuint gen_buffer()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("gen buffer");
sIndex = pool_size;
#if !LL_DARWIN
if (!gGLManager.mIsAMD)
{
glGenBuffers(pool_size, sNamePool);
}
else
#endif
{ // work around for AMD driver bug
for (U32 i = 0; i < pool_size; ++i)
{
@ -289,22 +292,58 @@ static GLuint gen_buffer()
return ret;
}
static void delete_buffers(S32 count, GLuint* buffers)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
// wait a few frames before actually deleting the buffers to avoid
// synchronization issues with the GPU
static std::vector<GLuint> sFreeList[4];
if (gGLManager.mInited)
{
U32 idx = LLImageGL::sFrameCount % 4;
for (S32 i = 0; i < count; ++i)
{
sFreeList[idx].push_back(buffers[i]);
}
idx = (LLImageGL::sFrameCount + 3) % 4;
if (!sFreeList[idx].empty())
{
glDeleteBuffers((GLsizei)sFreeList[idx].size(), sFreeList[idx].data());
sFreeList[idx].resize(0);
}
}
}
#define ANALYZE_VBO_POOL 0
#if LL_DARWIN
// experimental -- disable VBO pooling on OS X and use glMapBuffer
// VBO Pool interface
class LLVBOPool
{
public:
virtual ~LLVBOPool() = default;
virtual void allocate(GLenum type, U32 size, GLuint& name, U8*& data) = 0;
virtual void free(GLenum type, U32 size, GLuint name, U8* data) = 0;
virtual U64 getVramBytesUsed() = 0;
};
// VBO Pool for Apple GPUs (as in M1/M2 etc, not Intel macs)
// Effectively disables VBO pooling
class LLAppleVBOPool final: public LLVBOPool
{
public:
U64 mAllocated = 0;
U64 getVramBytesUsed()
U64 getVramBytesUsed() override
{
return mAllocated;
}
void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
STOP_GLERROR;
@ -324,7 +363,7 @@ public:
}
}
void free(GLenum type, U32 size, GLuint name, U8* data)
void free(GLenum type, U32 size, GLuint name, U8* data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@ -339,19 +378,17 @@ public:
STOP_GLERROR;
if (name)
{
glDeleteBuffers(1, &name);
delete_buffers(1, &name);
}
STOP_GLERROR;
}
};
#else
class LLVBOPool
// VBO Pool for GPUs that benefit from VBO pooling
class LLDefaultVBOPool final : public LLVBOPool
{
public:
typedef std::chrono::steady_clock::time_point Time;
struct Entry
{
U8* mData;
@ -359,7 +396,7 @@ public:
Time mAge;
};
~LLVBOPool()
~LLDefaultVBOPool() override
{
clear();
}
@ -377,7 +414,7 @@ public:
U32 mMisses = 0;
U32 mHits = 0;
U64 getVramBytesUsed()
U64 getVramBytesUsed() override
{
return mAllocated + mReserved;
}
@ -393,7 +430,7 @@ public:
size += block_size - (size % block_size);
}
void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@ -449,7 +486,7 @@ public:
clean();
}
void free(GLenum type, U32 size, GLuint name, U8* data)
void free(GLenum type, U32 size, GLuint name, U8* data) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
@ -512,7 +549,7 @@ public:
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vbo cache timeout");
auto& entry = entries.back();
ll_aligned_free_16(entry.mData);
glDeleteBuffers(1, &entry.mGLName);
delete_buffers(1, &entry.mGLName);
llassert(mReserved >= iter->first);
mReserved -= iter->first;
entries.pop_back();
@ -548,7 +585,7 @@ public:
for (auto& entry : entries.second)
{
ll_aligned_free_16(entry.mData);
glDeleteBuffers(1, &entry.mGLName);
delete_buffers(1, &entry.mGLName);
}
}
@ -557,7 +594,7 @@ public:
for (auto& entry : entries.second)
{
ll_aligned_free_16(entry.mData);
glDeleteBuffers(1, &entry.mGLName);
delete_buffers(1, &entry.mGLName);
}
}
@ -567,10 +604,71 @@ public:
mVBOPool.clear();
}
};
#endif
static LLVBOPool* sVBOPool = nullptr;
void LLVertexBufferData::drawWithMatrix()
{
if (!mVB)
{
llassert(false);
// Not supposed to happen, check buffer generation
return;
}
if (mTexName)
{
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTexName);
}
else
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.pushMatrix();
gGL.loadMatrix(glm::value_ptr(mModelView));
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
gGL.loadMatrix(glm::value_ptr(mProjection));
gGL.matrixMode(LLRender::MM_TEXTURE0);
gGL.pushMatrix();
gGL.loadMatrix(glm::value_ptr(mTexture0));
mVB->setBuffer();
mVB->drawArrays(mMode, 0, mCount);
gGL.popMatrix();
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.popMatrix();
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.popMatrix();
}
void LLVertexBufferData::draw()
{
if (!mVB)
{
llassert(false);
// Not supposed to happen, check buffer generation
return;
}
if (mTexName)
{
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTexName);
}
else
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
mVB->setBuffer();
mVB->drawArrays(mMode, 0, mCount);
}
//============================================================================
//static
U64 LLVertexBuffer::getBytesAllocated()
{
@ -633,7 +731,6 @@ const U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
//GL_QUADS, // <FS:Ansariel> Remove QUADS rendering mode
GL_LINE_LOOP,
};
@ -864,7 +961,17 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
void LLVertexBuffer::initClass(LLWindow* window)
{
llassert(sVBOPool == nullptr);
sVBOPool = new LLVBOPool();
if (gGLManager.mIsApple)
{
LL_INFOS() << "VBO Pooling Disabled" << LL_ENDL;
sVBOPool = new LLAppleVBOPool();
}
else
{
LL_INFOS() << "VBO Pooling Enabled" << LL_ENDL;
sVBOPool = new LLDefaultVBOPool();
}
#if ENABLE_GL_WORK_QUEUE
sQueue = new GLWorkQueue();
@ -923,6 +1030,24 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask)
}
}
// list of mapped buffers
// NOTE: must not be LLPointer<LLVertexBuffer> to avoid breaking non-ref-counted LLVertexBuffer instances
static std::vector<LLVertexBuffer*> sMappedBuffers;
//static
void LLVertexBuffer::flushBuffers()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
// must only be called from main thread
for (auto& buffer : sMappedBuffers)
{
buffer->_unmapBuffer();
buffer->mMapped = false;
}
sMappedBuffers.resize(0);
}
//static
U32 LLVertexBuffer::calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices)
{
@ -966,6 +1091,12 @@ U32 LLVertexBuffer::calcVertexSize(const U32& typemask)
//virtual
LLVertexBuffer::~LLVertexBuffer()
{
if (mMapped)
{ // is on the mapped buffer list but doesn't need to be flushed
mMapped = false;
unmapBuffer();
}
destroyGLBuffer();
destroyGLIndices();
@ -1167,34 +1298,36 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, U32 start, U32 end)
U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 index, S32 count)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
_mapBuffer();
if (count == -1)
{
count = mNumVerts - index;
}
#if !LL_DARWIN
U32 start = mOffsets[type] + sTypeSize[type] * index;
U32 end = start + sTypeSize[type] * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
if (!gGLManager.mIsApple)
{
MappedRegion& region = mMappedVertexRegions[i];
if (expand_region(region, start, end))
U32 start = mOffsets[type] + sTypeSize[type] * index;
U32 end = start + sTypeSize[type] * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
{
flagged = true;
break;
MappedRegion& region = mMappedVertexRegions[i];
if (expand_region(region, start, end))
{
flagged = true;
break;
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedVertexRegions.push_back({ start, end });
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedVertexRegions.push_back({ start, end });
}
#endif
return mMappedData+mOffsets[type]+sTypeSize[type]*index;
}
@ -1202,35 +1335,37 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde
U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
_mapBuffer();
if (count == -1)
{
count = mNumIndices-index;
}
#if !LL_DARWIN
U32 start = sizeof(U16) * index;
U32 end = start + sizeof(U16) * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
if (!gGLManager.mIsApple)
{
MappedRegion& region = mMappedIndexRegions[i];
if (expand_region(region, start, end))
U32 start = sizeof(U16) * index;
U32 end = start + sizeof(U16) * count-1;
bool flagged = false;
// flag region as mapped
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
{
flagged = true;
break;
MappedRegion& region = mMappedIndexRegions[i];
if (expand_region(region, start, end))
{
flagged = true;
break;
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedIndexRegions.push_back({ start, end });
}
}
if (!flagged)
{
//didn't expand an existing region, make a new one
mMappedIndexRegions.push_back({ start, end });
}
#endif
return mMappedIndexData + sizeof(U16)*index;
}
@ -1242,39 +1377,64 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
// dst -- mMappedData or mMappedIndexData
void LLVertexBuffer::flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst)
{
#if LL_DARWIN
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb memcpy");
STOP_GLERROR;
// copy into mapped buffer
memcpy(dst+start, data, end-start+1);
#else
llassert(target == GL_ARRAY_BUFFER ? sGLRenderBuffer == mGLBuffer : sGLRenderIndices == mGLIndices);
// skip mapped data and stream to GPU via glBufferSubData
if (end != 0)
if (gGLManager.mIsApple)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData");
LL_PROFILE_ZONE_NUM(start);
LL_PROFILE_ZONE_NUM(end);
LL_PROFILE_ZONE_NUM(end-start);
// on OS X, flush_vbo doesn't actually write to the GL buffer, so be sure to call
// _mapBuffer to tag the buffer for flushing to GL
_mapBuffer();
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb memcpy");
STOP_GLERROR;
// copy into mapped buffer
memcpy(dst+start, data, end-start+1);
}
else
{
llassert(target == GL_ARRAY_BUFFER ? sGLRenderBuffer == mGLBuffer : sGLRenderIndices == mGLIndices);
constexpr U32 block_size = 8192;
for (U32 i = start; i <= end; i += block_size)
// skip mapped data and stream to GPU via glBufferSubData
if (end != 0)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
//LL_PROFILE_GPU_ZONE("glBufferSubData");
U32 tend = llmin(i + block_size, end);
U32 size = tend - i + 1;
glBufferSubData(target, i, size, (U8*) data + (i-start));
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData");
LL_PROFILE_ZONE_NUM(start);
LL_PROFILE_ZONE_NUM(end);
LL_PROFILE_ZONE_NUM(end-start);
constexpr U32 block_size = 65536;
for (U32 i = start; i <= end; i += block_size)
{
//LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
//LL_PROFILE_GPU_ZONE("glBufferSubData");
U32 tend = llmin(i + block_size, end);
U32 size = tend - i + 1;
glBufferSubData(target, i, size, (U8*) data + (i-start));
}
}
}
#endif
}
void LLVertexBuffer::unmapBuffer()
{
flushBuffers();
}
void LLVertexBuffer::_mapBuffer()
{
if (!mMapped)
{
mMapped = true;
sMappedBuffers.push_back(this);
}
}
void LLVertexBuffer::_unmapBuffer()
{
STOP_GLERROR;
if (!mMapped)
{
return;
}
struct SortMappedRegion
{
bool operator()(const MappedRegion& lhs, const MappedRegion& rhs)
@ -1283,114 +1443,116 @@ void LLVertexBuffer::unmapBuffer()
}
};
#if LL_DARWIN
STOP_GLERROR;
if (mMappedData)
if (gGLManager.mIsApple)
{
if (mGLBuffer)
STOP_GLERROR;
if (mMappedData)
{
glDeleteBuffers(1, &mGLBuffer);
if (mGLBuffer)
{
delete_buffers(1, &mGLBuffer);
}
mGLBuffer = gen_buffer();
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW);
}
mGLBuffer = gen_buffer();
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW);
}
else if (mGLBuffer != sGLRenderBuffer)
{
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
}
STOP_GLERROR;
if (mMappedIndexData)
{
if (mGLIndices)
{
glDeleteBuffers(1, &mGLIndices);
}
mGLIndices = gen_buffer();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_STATIC_DRAW);
}
else if (mGLIndices != sGLRenderIndices)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
}
STOP_GLERROR;
#else
if (!mMappedVertexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
if (sGLRenderBuffer != mGLBuffer)
else if (mGLBuffer != sGLRenderBuffer)
{
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
}
STOP_GLERROR;
U32 start = 0;
U32 end = 0;
std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
if (mMappedIndexData)
{
const MappedRegion& region = mMappedVertexRegions[i];
if (region.mStart == end + 1)
if (mGLIndices)
{
end = region.mEnd;
}
else
{
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
start = region.mStart;
end = region.mEnd;
delete_buffers(1, &mGLIndices);
}
mGLIndices = gen_buffer();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_STATIC_DRAW);
}
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
mMappedVertexRegions.clear();
}
if (!mMappedIndexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
if (mGLIndices != sGLRenderIndices)
else if (mGLIndices != sGLRenderIndices)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
}
U32 start = 0;
U32 end = 0;
std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
STOP_GLERROR;
}
else
{
if (!mMappedVertexRegions.empty())
{
const MappedRegion& region = mMappedIndexRegions[i];
if (region.mStart == end + 1)
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
if (sGLRenderBuffer != mGLBuffer)
{
end = region.mEnd;
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
sGLRenderBuffer = mGLBuffer;
}
else
U32 start = 0;
U32 end = 0;
std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
{
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
start = region.mStart;
end = region.mEnd;
const MappedRegion& region = mMappedVertexRegions[i];
if (region.mStart == end + 1)
{
end = region.mEnd;
}
else
{
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
start = region.mStart;
end = region.mEnd;
}
}
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
mMappedVertexRegions.clear();
}
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
mMappedIndexRegions.clear();
if (!mMappedIndexRegions.empty())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
if (mGLIndices != sGLRenderIndices)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
sGLRenderIndices = mGLIndices;
}
U32 start = 0;
U32 end = 0;
std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion());
for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
{
const MappedRegion& region = mMappedIndexRegions[i];
if (region.mStart == end + 1)
{
end = region.mEnd;
}
else
{
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
start = region.mStart;
end = region.mEnd;
}
}
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
mMappedIndexRegions.clear();
}
}
#endif
}
//----------------------------------------------------------------------------
@ -1523,12 +1685,13 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4a>& strider, U32 i
void LLVertexBuffer::setBuffer()
{
STOP_GLERROR;
#if LL_DARWIN
if (!mGLBuffer)
{ // OS X doesn't allocate a buffer until we call unmapBuffer
return;
if (mMapped)
{
LL_WARNS_ONCE() << "Missing call to unmapBuffer or flushBuffers" << LL_ENDL;
_unmapBuffer();
}
#endif
// no data may be pending
llassert(mMappedVertexRegions.empty());
llassert(mMappedIndexRegions.empty());

View File

@ -38,6 +38,7 @@
#include <set>
#include <vector>
#include <list>
#include <glm/gtc/matrix_transform.hpp>
#define LL_MAX_VERTEX_ATTRIB_LOCATION 64
@ -53,6 +54,41 @@
//============================================================================
// base class
class LLPrivateMemoryPool;
class LLVertexBuffer;
class LLVertexBufferData
{
public:
LLVertexBufferData()
: mVB(nullptr)
, mMode(0)
, mCount(0)
, mTexName(0)
, mProjection(glm::identity<glm::mat4>())
, mModelView(glm::identity<glm::mat4>())
, mTexture0(glm::identity<glm::mat4>())
{}
LLVertexBufferData(LLVertexBuffer* buffer, U8 mode, U32 count, U32 tex_name, const glm::mat4& model_view, const glm::mat4& projection, const glm::mat4& texture0)
: mVB(buffer)
, mMode(mode)
, mCount(count)
, mTexName(tex_name)
, mProjection(model_view)
, mModelView(projection)
, mTexture0(texture0)
{}
void drawWithMatrix();
void draw();
LLPointer<LLVertexBuffer> mVB;
U8 mMode;
U32 mCount;
U32 mTexName;
glm::mat4 mProjection;
glm::mat4 mModelView;
glm::mat4 mTexture0;
};
typedef std::list<LLVertexBufferData> buffer_data_list_t;
class LLVertexBuffer final : public LLRefCount
{
public:
@ -89,6 +125,9 @@ public:
// indexed by the following enum
static U32 calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices);
// flush any pending mapped buffers
static void flushBuffers();
//WARNING -- when updating these enums you MUST
// 1 - update LLVertexBuffer::sTypeSize
// 2 - update LLVertexBuffer::vb_type_name
@ -159,6 +198,8 @@ public:
// map for data access (see also getFooStrider below)
U8* mapVertexBuffer(AttributeType type, U32 index, S32 count = -1);
U8* mapIndexBuffer(U32 index, S32 count = -1);
// synonym for flushBuffers
void unmapBuffer();
// set for rendering
@ -285,6 +326,13 @@ private:
bool allocateBuffer(S32 nverts, S32 nindices, bool create) { return allocateBuffer(nverts, nindices); }
// actually unmap buffer
void _unmapBuffer();
// add to set of mapped buffers
void _mapBuffer();
bool mMapped = false;
public:
static U64 getBytesAllocated();

View File

@ -27,6 +27,8 @@
#define LLBADGE_CPP
#include "llbadge.h"
#include "llfontgl.h"
#include "llfontvertexbuffer.h"
#include "llscrollcontainer.h"
#include "lluictrlfactory.h"
@ -202,29 +204,17 @@ void renderBadgeBackground(F32 centerX, F32 centerY, F32 width, F32 height, cons
(F32)ll_round(x) + width,
(F32)ll_round(y) + height);
LLVector3 vertices[4];
// <FS:Ansariel> Remove QUADS rendering mode
//vertices[0] = LLVector3(screen_rect.mRight, screen_rect.mTop, 1.0f);
//vertices[1] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 1.0f);
//vertices[2] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 1.0f);
//vertices[3] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 1.0f);
//
//gGL.begin(LLRender::QUADS);
//{
// gGL.vertexBatchPreTransformed(vertices, 4);
//}
//gGL.end();
vertices[0] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 1.0f);
vertices[1] = LLVector3(screen_rect.mRight, screen_rect.mTop, 1.0f);
vertices[2] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 1.0f);
vertices[3] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 1.0f);
LLVector4a vertices[4];
vertices[0].set(screen_rect.mLeft, screen_rect.mTop, 1.0f);
vertices[1].set(screen_rect.mRight, screen_rect.mTop, 1.0f);
vertices[2].set(screen_rect.mLeft, screen_rect.mBottom, 1.0f);
vertices[3].set(screen_rect.mRight, screen_rect.mBottom, 1.0f);
gGL.begin(LLRender::TRIANGLE_STRIP);
{
gGL.vertexBatchPreTransformed(vertices, 4);
}
gGL.end();
// </FS:Ansariel>
gGL.popUIMatrix();
}
@ -363,17 +353,17 @@ void LLBadge::draw()
//
// Draw the label
//
mGLFont->render(mLabel.getWString(),
badge_label_begin_offset,
badge_center_x + mLabelOffsetHoriz,
badge_center_y + mLabelOffsetVert,
mLabelColor % alpha,
LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position
LLFontGL::NORMAL, // normal text (not bold, italics, etc.)
LLFontGL::DROP_SHADOW_SOFT,
badge_char_length, badge_pixel_length,
right_position_out, do_not_use_ellipses);
mFontBuffer.render(mGLFont,
mLabel.getWString(),
badge_label_begin_offset,
badge_center_x + mLabelOffsetHoriz,
badge_center_y + mLabelOffsetVert,
mLabelColor % alpha,
LLFontGL::HCENTER, LLFontGL::VCENTER, // centered around the position
LLFontGL::NORMAL, // normal text (not bold, italics, etc.)
LLFontGL::DROP_SHADOW_SOFT,
badge_char_length, badge_pixel_length,
right_position_out, do_not_use_ellipses);
}
}
}

View File

@ -34,12 +34,14 @@
#include "llstring.h"
#include "lluiimage.h"
#include "llview.h"
#include "llfontvertexbuffer.h"
//
// Declarations
//
class LLFontGL;
class LLFontVertexBuffer;
class LLScrollContainer;
class LLUICtrlFactory;
@ -144,6 +146,7 @@ private:
LLUIColor mBorderColor;
const LLFontGL* mGLFont;
LLFontVertexBuffer mFontBuffer;
LLPointer< LLUIImage > mImage;
LLUIColor mImageColor;

View File

@ -43,6 +43,8 @@
#include "llfloater.h"
#include "llfloaterreg.h"
#include "llfocusmgr.h"
#include "llfontgl.h"
#include "llfontvertexbuffer.h"
#include "llwindow.h"
#include "llnotificationsutil.h"
#include "llrender.h"
@ -127,11 +129,10 @@ LLButton::Params::Params()
LLButton::LLButton(const LLButton::Params& p)
: LLUICtrl(p),
: LLUICtrl(p),
LLBadgeOwner(getHandle()),
mMouseDownFrame(0),
mMouseHeldDownCount(0),
mBorderEnabled( false ),
mFlashing( false ),
mCurGlowStrength(0.f),
mNeedsHighlight(false),
@ -349,6 +350,30 @@ void LLButton::onCommit()
LLUICtrl::onCommit();
}
void LLButton::setUnselectedLabelColor(const LLUIColor& c)
{
mUnselectedLabelColor = c;
mFontBuffer.reset();
}
void LLButton::setSelectedLabelColor(const LLUIColor& c)
{
mSelectedLabelColor = c;
mFontBuffer.reset();
}
void LLButton::setUseEllipses(bool use_ellipses)
{
mUseEllipses = use_ellipses;
mFontBuffer.reset();
}
void LLButton::setUseFontColor(bool use_font_color)
{
mUseFontColor = use_font_color;
mFontBuffer.reset();
}
boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb)
{
return setClickedCallback(initCommitCallback(cb));
@ -453,6 +478,18 @@ bool LLButton::postBuild()
return LLUICtrl::postBuild();
}
void LLButton::onVisibilityChange(bool new_visibility)
{
mFontBuffer.reset();
return LLUICtrl::onVisibilityChange(new_visibility);
}
void LLButton::dirtyRect()
{
LLUICtrl::dirtyRect();
mFontBuffer.reset();
}
bool LLButton::handleUnicodeCharHere(llwchar uni_char)
{
bool handled = false;
@ -639,19 +676,25 @@ void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
{
LLUICtrl::onMouseLeave(x, y, mask);
mNeedsHighlight = false;
setHighlight(false);
}
void LLButton::setHighlight(bool b)
{
mNeedsHighlight = b;
if (mNeedsHighlight != b)
{
mNeedsHighlight = b;
mFontBuffer.reset();
}
}
bool LLButton::handleHover(S32 x, S32 y, MASK mask)
{
if (isInEnabledChain()
&& (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this))
mNeedsHighlight = true;
{
setHighlight(true);
}
if (!childrenHandleHover(x, y, mask))
{
@ -1020,7 +1063,7 @@ void LLButton::draw()
// LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value.
// Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode.
// Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars.
mLastDrawCharsCount = mGLFont->render(label, 0,
mLastDrawCharsCount = mFontBuffer.render(mGLFont, label, 0,
(F32)x,
(F32)(getRect().getHeight() / 2 + mBottomVPad),
label_color % alpha,
@ -1071,6 +1114,7 @@ void LLButton::setToggleState(bool b)
setFlashing(false); // stop flash state whenever the selected/unselected state if reset
// Unselected label assignments
autoResize();
mFontBuffer.reset();
}
}
@ -1100,11 +1144,13 @@ bool LLButton::toggleState()
void LLButton::setLabel( const std::string& label )
{
mUnselectedLabel = mSelectedLabel = label;
mFontBuffer.reset();
}
void LLButton::setLabel( const LLUIString& label )
{
mUnselectedLabel = mSelectedLabel = label;
mFontBuffer.reset();
}
void LLButton::setLabel( const LLStringExplicit& label )
@ -1118,17 +1164,32 @@ bool LLButton::setLabelArg( const std::string& key, const LLStringExplicit& text
{
mUnselectedLabel.setArg(key, text);
mSelectedLabel.setArg(key, text);
mFontBuffer.reset();
return true;
}
void LLButton::setLabelUnselected( const LLStringExplicit& label )
{
mUnselectedLabel = label;
mFontBuffer.reset();
}
void LLButton::setLabelSelected( const LLStringExplicit& label )
{
mSelectedLabel = label;
mFontBuffer.reset();
}
void LLButton::setDisabledLabelColor(const LLUIColor& c)
{
mDisabledLabelColor = c;
mFontBuffer.reset();
}
void LLButton::setFont(const LLFontGL* font)
{
mGLFont = (font ? font : LLFontGL::getFontSansSerif());
mFontBuffer.reset();
}
bool LLButton::labelIsTruncated() const
@ -1141,6 +1202,12 @@ const LLUIString& LLButton::getCurrentLabel() const
return getToggleState() ? mSelectedLabel : mUnselectedLabel;
}
void LLButton::setDropShadowedText(bool b)
{
mDropShadowedText = b;
mFontBuffer.reset();
}
void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
{
mImageUnselected = image;
@ -1224,6 +1291,7 @@ void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image)
mImageDisabledSelected = image;
mDisabledImageColor = mImageColor;
mFadeWhenDisabled = true;
mFontBuffer.reset();
}
void LLButton::setImagePressed(LLPointer<LLUIImage> image)

Some files were not shown because too many files have changed in this diff Show More