Merge branch 'DRTVWR-559' into marchcat/587-v-pbr-merge
# Conflicts: # indra/llcommon/CMakeLists.txt # indra/newview/llspatialpartition.cpp # indra/newview/llviewergenericmessage.cpp # indra/newview/llvoavatar.cppmaster
commit
d1c0a5b840
|
|
@ -7,9 +7,18 @@
|
|||
*.pyc
|
||||
*.rej
|
||||
*.swp
|
||||
*.vcxproj
|
||||
*.filters
|
||||
*.sln
|
||||
*.depend
|
||||
*.stamp
|
||||
*.rc
|
||||
|
||||
*~
|
||||
|
||||
# Specific paths and/or names
|
||||
CMakeCache.txt
|
||||
cmake_install.cmake
|
||||
LICENSES
|
||||
build-darwin-*
|
||||
build-linux-*
|
||||
|
|
@ -17,6 +26,10 @@ debian/files
|
|||
debian/secondlife-appearance-utility*
|
||||
debian/secondlife-viewer*
|
||||
indra/.distcc
|
||||
indra/cmake/*
|
||||
indra/out/*
|
||||
|
||||
indra/packages/*
|
||||
build-vc80/
|
||||
build-vc100/
|
||||
build-vc120/
|
||||
|
|
|
|||
170
autobuild.xml
170
autobuild.xml
|
|
@ -702,11 +702,11 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>34af0a90a3015b7e7ec2486090bc4ce6ee5be758</string>
|
||||
<string>7cc58b3acb230a7e65ea5f0ff800be393eb4aa1b</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-glext/releases/download/v68-af397ee/glext-68-common-af397ee.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-glext/releases/download/v69/glext-68-common-685b36e.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>common</string>
|
||||
|
|
@ -1732,6 +1732,62 @@
|
|||
<key>description</key>
|
||||
<string>Meshoptimizer. Mesh optimization library.</string>
|
||||
</map>
|
||||
<key>mikktspace</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-mikktspace</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (C) 2011 by Morten S. Mikkelsen</string>
|
||||
<key>description</key>
|
||||
<string>Mikktspace Tangent Generator</string>
|
||||
<key>license</key>
|
||||
<string>Copyright (C) 2011 by Morten S. Mikkelsen</string>
|
||||
<key>license_file</key>
|
||||
<string>mikktspace.txt</string>
|
||||
<key>name</key>
|
||||
<string>mikktspace</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b48b7ac0792d3ea8f087d99d9e4a29d8</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104415/914944/mikktspace-1-darwin64-574859.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>0a016b9c0c1e2c0b557e0124094da6c5</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104407/914918/mikktspace-1-windows-574859.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>02e9e5b6fe6788f4d2babb83ec544843</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104406/914909/mikktspace-1-windows64-574859.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1</string>
|
||||
</map>
|
||||
<key>minizip-ng</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
|
|
@ -2318,6 +2374,42 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>name</key>
|
||||
<string>threejs</string>
|
||||
</map>
|
||||
<key>tinygltf</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-tinygltf</string>
|
||||
<key>copyright</key>
|
||||
<string>// Copyright (c) 2015 - Present Syoyo Fujita, Aurélien Chatelain and many contributors.</string>
|
||||
<key>description</key>
|
||||
<string>tinygltf import library</string>
|
||||
<key>license</key>
|
||||
<string>MIT</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/tinygltf_license.txt</string>
|
||||
<key>name</key>
|
||||
<string>tinygltf</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>common</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>4dad1c0948141e1667c01a3ee755e4dc</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/105849/926137/tinygltf-v2.5.0-common-575729.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>common</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>source</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-tinygltf</string>
|
||||
<key>source_type</key>
|
||||
<string>git</string>
|
||||
<key>version</key>
|
||||
<string>v2.5.0</string>
|
||||
</map>
|
||||
<key>tracy</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
|
|
@ -2327,11 +2419,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b84ccb1606b3fc5b216d0123a23a4922e02b6bd8</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<string>9b6e1a1f4b0969d38a1ca8ee00aeb548</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-tracy/releases/download/v0.8.1-235e98f/tracy-v0.8.1.235e98f-darwin64-235e98f.tar.zst</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/110584/960613/tracy-v0.8.1.578241-darwin64-578241.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -2341,11 +2431,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>54f126b85f179362cf0b6024e3cd621b53d68703</string>
|
||||
<string>05b72ae5d733aed7d3bf142287601cc6</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-tracy/releases/download/v0.8.1-235e98f/tracy-v0.8.1.235e98f-windows64-235e98f.tar.zst</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/110586/960637/tracy-v0.8.1.578241-windows64-578241.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
|
|
@ -2369,6 +2459,8 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>https://bitbucket.org/lindenlab/3p-tracy</string>
|
||||
<key>source_type</key>
|
||||
<string>git</string>
|
||||
<key>version</key>
|
||||
<string>v0.8.1.578241</string>
|
||||
</map>
|
||||
<key>tut</key>
|
||||
<map>
|
||||
|
|
@ -2630,6 +2722,62 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>description</key>
|
||||
<string>XMLRPC Library</string>
|
||||
</map>
|
||||
<key>vulkan_gltf</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-vulkan-gltf-pbr</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 2018 Sascha Willems</string>
|
||||
<key>description</key>
|
||||
<string>Vulkan GLTF Sample Implementation</string>
|
||||
<key>license</key>
|
||||
<string>Copyright (c) 2018 Sascha Willems</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/vulkan_gltf.txt</string>
|
||||
<key>name</key>
|
||||
<string>vulkan_gltf</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>8cff2060843db3db788511ee34a8e8cc</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/101316/891509/vulkan_gltf-1-darwin64-572743.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>58eea384be49ba756ce9c5e66669540b</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/101318/891520/vulkan_gltf-1-windows-572743.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>79b6a11622c2f83cfc2b7cd1fafb867b</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/101319/891521/vulkan_gltf-1-windows64-572743.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1</string>
|
||||
</map>
|
||||
<key>xxhash</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
|
|
@ -2887,6 +3035,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>RelWithDebInfo</string>
|
||||
<string>-project</string>
|
||||
<string>SecondLife.xcodeproj</string>
|
||||
<string>-parallelizeTargets</string>
|
||||
</array>
|
||||
</map>
|
||||
<key>default</key>
|
||||
|
|
@ -2914,6 +3063,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>RelWithDebInfo</string>
|
||||
<string>-project</string>
|
||||
<string>SecondLife.xcodeproj</string>
|
||||
<string>-parallelizeTargets</string>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
|
|
@ -2943,6 +3093,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>Release</string>
|
||||
<string>-project</string>
|
||||
<string>SecondLife.xcodeproj</string>
|
||||
<string>-parallelizeTargets</string>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
|
|
@ -2968,6 +3119,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>Release</string>
|
||||
<string>-project</string>
|
||||
<string>SecondLife.xcodeproj</string>
|
||||
<string>-parallelizeTargets</string>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ Agathos Frascati
|
|||
CT-317
|
||||
CT-352
|
||||
Ai Austin
|
||||
SL-19399
|
||||
Aiko Ying
|
||||
Aimee Trescothick
|
||||
SNOW-227
|
||||
|
|
@ -1421,6 +1422,7 @@ Sovereign Engineer
|
|||
SL-18497
|
||||
SL-18525
|
||||
SL-18534
|
||||
SL-19690
|
||||
SL-19336
|
||||
SpacedOut Frye
|
||||
VWR-34
|
||||
|
|
|
|||
|
|
@ -187,3 +187,4 @@ if (LINUX OR DARWIN)
|
|||
endif (LINUX OR DARWIN)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ set(cmake_SOURCE_FILES
|
|||
VisualLeakDetector.cmake
|
||||
LibVLCPlugin.cmake
|
||||
XmlRpcEpi.cmake
|
||||
xxHash.cmake
|
||||
ZLIBNG.cmake
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
include_guard()
|
||||
|
||||
# FMODSTUDIO can be set when launching the make using the argument -DFMODSTUDIO:BOOL=ON
|
||||
# FMODSTUDIO can be set when launching the make using the argument -DUSE_FMODSTUDIO:BOOL=ON
|
||||
# When building using proprietary binaries though (i.e. having access to LL private servers),
|
||||
# we always build with FMODSTUDIO.
|
||||
if (INSTALL_PROPRIETARY)
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ include(Prebuilt)
|
|||
include(GLH)
|
||||
|
||||
add_library( ll::glext INTERFACE IMPORTED )
|
||||
if (WINDOWS OR LINUX)
|
||||
use_system_binary(glext)
|
||||
use_prebuilt_binary(glext)
|
||||
endif (WINDOWS OR LINUX)
|
||||
use_system_binary(glext)
|
||||
use_prebuilt_binary(glext)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,13 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
|
|||
message("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_CFLAGS ${${name}_test_additional_CFLAGS}")
|
||||
endif()
|
||||
|
||||
if (DARWIN)
|
||||
# test binaries always need to be signed for local development
|
||||
set_target_properties(PROJECT_${project}_TEST_${name}
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-")
|
||||
endif ()
|
||||
|
||||
#
|
||||
# Setup test targets
|
||||
#
|
||||
|
|
@ -221,6 +228,13 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
|
|||
)
|
||||
endif ()
|
||||
|
||||
if (DARWIN)
|
||||
# test binaries always need to be signed for local development
|
||||
set_target_properties(INTEGRATION_TEST_${testname}
|
||||
PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-")
|
||||
endif ()
|
||||
|
||||
# Add link deps to the executable
|
||||
if(TEST_DEBUG)
|
||||
message(STATUS "TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})")
|
||||
|
|
|
|||
|
|
@ -1,2 +1,5 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
include(Variables)
|
||||
include(Mikktspace)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
if (NOT USESYSTEMLIBS)
|
||||
use_prebuilt_binary(mikktspace)
|
||||
endif (NOT USESYSTEMLIBS)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
use_prebuilt_binary(tinygltf)
|
||||
|
||||
set(TINYGLTF_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tinygltf)
|
||||
|
||||
|
|
@ -11,8 +11,9 @@ if (USE_TRACY)
|
|||
use_prebuilt_binary(tracy)
|
||||
|
||||
target_include_directories( ll::tracy SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/tracy)
|
||||
target_link_libraries( ll::tracy INTERFACE TracyClient )
|
||||
|
||||
# See: indra/llcommon/llprofiler.h
|
||||
target_compile_definitions(ll::tracy INTERFACE LL_PROFILER_CONFIGURATION=3 )
|
||||
# See: indra/llcommon/llprofiler.h
|
||||
add_compile_definitions(LL_PROFILER_CONFIGURATION=3)
|
||||
endif (USE_TRACY)
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ set(LIBS_OPEN_PREFIX)
|
|||
set(SCRIPTS_PREFIX ../scripts)
|
||||
set(VIEWER_PREFIX)
|
||||
set(INTEGRATION_TESTS_PREFIX)
|
||||
set(LL_TESTS ON CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation")
|
||||
set(LL_TESTS OFF CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation")
|
||||
set(INCREMENTAL_LINK OFF CACHE BOOL "Use incremental linking on win32 builds (enable for faster links on some machines)")
|
||||
set(ENABLE_MEDIA_PLUGINS ON CACHE BOOL "Turn off building media plugins if they are imported by third-party library mechanism")
|
||||
set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
use_prebuilt_binary(vulkan_gltf)
|
||||
|
||||
|
|
@ -377,7 +377,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
|
|||
// clear buffer area to ensure we don't pick up UI elements
|
||||
{
|
||||
gGL.flush();
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.0f);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.color4f( 0.f, 0.f, 0.f, 1.f );
|
||||
|
|
@ -410,7 +409,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
|
|||
gGL.flush();
|
||||
|
||||
gGL.setSceneBlendType(LLRender::BT_REPLACE);
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
|
@ -500,7 +498,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
|
|||
{
|
||||
// Set the alpha channel to one (clean up after previous blending)
|
||||
gGL.flush();
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.color4f( 0.f, 0.f, 0.f, 1.f );
|
||||
|
|
@ -1025,7 +1022,6 @@ void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LL
|
|||
|
||||
BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target)
|
||||
{
|
||||
LLGLEnable color_mat(GL_COLOR_MATERIAL);
|
||||
// *TODO: Is this correct?
|
||||
//gPipeline.disableLights();
|
||||
stop_glerror();
|
||||
|
|
@ -1112,7 +1108,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
|
|||
if( tex )
|
||||
{
|
||||
bool no_alpha_test = getInfo()->mWriteAllChannels;
|
||||
LLGLDisable alpha_test(no_alpha_test ? GL_ALPHA_TEST : 0);
|
||||
if (no_alpha_test)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
|
|
@ -1162,7 +1157,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
|
|||
getInfo()->mStaticImageFileName.empty() &&
|
||||
color_specified )
|
||||
{
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.000f);
|
||||
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
|
@ -1260,7 +1254,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
|
|||
LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask );
|
||||
if( tex )
|
||||
{
|
||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
gGL.getTexUnit(0)->bind(tex, TRUE);
|
||||
gl_rect_2d_simple_tex( width, height );
|
||||
|
|
@ -1279,7 +1272,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
|
|||
LLGLTexture* tex = mLocalTextureObject->getImage();
|
||||
if (tex)
|
||||
{
|
||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
gGL.getTexUnit(0)->bind(tex);
|
||||
gl_rect_2d_simple_tex( width, height );
|
||||
|
|
@ -1316,7 +1308,6 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
|||
// Note: if the first param is a mulitply, multiply against the current buffer's alpha
|
||||
if( !first_param || !first_param->getMultiplyBlend() )
|
||||
{
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
||||
// Clear the alpha
|
||||
|
|
@ -1328,7 +1319,6 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
|||
}
|
||||
|
||||
// Accumulate alphas
|
||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
||||
gGL.color4f( 1.f, 1.f, 1.f, 1.f );
|
||||
for (LLTexLayerParamAlpha* param : mParamAlphaList)
|
||||
{
|
||||
|
|
@ -1350,7 +1340,6 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
|||
LLGLTexture* tex = mLocalTextureObject->getImage();
|
||||
if( tex && (tex->getComponents() == 4) )
|
||||
{
|
||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
||||
LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
|
||||
|
||||
gGL.getTexUnit(0)->bind(tex, TRUE);
|
||||
|
|
@ -1370,7 +1359,6 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
|||
{
|
||||
if( (tex->getComponents() == 4) || (tex->getComponents() == 1) )
|
||||
{
|
||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
||||
gGL.getTexUnit(0)->bind(tex, TRUE);
|
||||
gl_rect_2d_simple_tex( width, height );
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
|
@ -1387,7 +1375,6 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
|||
// Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO );
|
||||
if ( !is_approx_equal(layer_color.mV[VW], 1.f) )
|
||||
{
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.color4fv(layer_color.mV);
|
||||
gl_rect_2d_simple( width, height );
|
||||
|
|
@ -1472,7 +1459,14 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
|||
}
|
||||
else
|
||||
{ // platforms with working drivers...
|
||||
glReadPixels(x, y, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, alpha_data);
|
||||
// We just want GL_ALPHA, but that isn't supported in OGL core profile 4.
|
||||
static const size_t TEMP_BYTES_PER_PIXEL = 4;
|
||||
U8* temp_data = (U8*)ll_aligned_malloc_32(mem_size * TEMP_BYTES_PER_PIXEL);
|
||||
glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, temp_data);
|
||||
for (size_t pixel = 0; pixel < pixels; pixel++) {
|
||||
alpha_data[pixel] = temp_data[(pixel * TEMP_BYTES_PER_PIXEL) + 3];
|
||||
}
|
||||
ll_aligned_free_32(temp_data);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther)
|
|||
mCachedProcessedTexture(pOther.mCachedProcessedTexture),
|
||||
mStaticImageTGA(pOther.mStaticImageTGA),
|
||||
mStaticImageRaw(pOther.mStaticImageRaw),
|
||||
mNeedsCreateTexture(pOther.mNeedsCreateTexture),
|
||||
mNeedsCreateTexture(pOther.mNeedsCreateTexture.load()),
|
||||
mStaticImageInvalid(pOther.mStaticImageInvalid),
|
||||
mAvgDistortionVec(pOther.mAvgDistortionVec),
|
||||
mCachedEffectiveWeight(pOther.mCachedEffectiveWeight)
|
||||
|
|
@ -344,7 +344,6 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
|
|||
mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
|
||||
}
|
||||
|
||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
||||
gGL.getTexUnit(0)->bind(mCachedProcessedTexture);
|
||||
gl_rect_2d_simple_tex(width, height);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
|
@ -361,7 +360,6 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
|
|||
}
|
||||
else
|
||||
{
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.color4f(0.f, 0.f, 0.f, effective_weight);
|
||||
gl_rect_2d_simple(width, height);
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ private:
|
|||
LLPointer<LLGLTexture> mCachedProcessedTexture;
|
||||
LLPointer<LLImageTGA> mStaticImageTGA;
|
||||
LLPointer<LLImageRaw> mStaticImageRaw;
|
||||
BOOL mNeedsCreateTexture;
|
||||
std::atomic<BOOL> mNeedsCreateTexture;
|
||||
BOOL mStaticImageInvalid;
|
||||
LL_ALIGN_16(LLVector4a mAvgDistortionVec);
|
||||
F32 mCachedEffectiveWeight;
|
||||
|
|
|
|||
|
|
@ -607,9 +607,7 @@ void LLAudioDecodeMgr::Impl::startMoreDecodes()
|
|||
|
||||
// Kick off a decode
|
||||
mDecodes[decode_id] = LLPointer<LLVorbisDecodeState>(NULL);
|
||||
try
|
||||
{
|
||||
main_queue->postTo(
|
||||
bool posted = main_queue->postTo(
|
||||
general_queue,
|
||||
[decode_id]() // Work done on general queue
|
||||
{
|
||||
|
|
@ -639,8 +637,7 @@ void LLAudioDecodeMgr::Impl::startMoreDecodes()
|
|||
|
||||
enqueueFinishAudio(decode_id, decode_state);
|
||||
});
|
||||
}
|
||||
catch (const LLThreadSafeQueueInterrupt&)
|
||||
if (! posted)
|
||||
{
|
||||
// Shutdown
|
||||
// Consider making processQueue() do a cleanup instead
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ include(Tracy)
|
|||
|
||||
set(llcommon_SOURCE_FILES
|
||||
apply.cpp
|
||||
commoncontrol.cpp
|
||||
indra_constants.cpp
|
||||
lazyeventapi.cpp
|
||||
llallocator.cpp
|
||||
|
|
@ -120,6 +121,7 @@ set(llcommon_HEADER_FILES
|
|||
apply.h
|
||||
chrono.h
|
||||
classic_callback.h
|
||||
commoncontrol.h
|
||||
ctype_workaround.h
|
||||
fix_macros.h
|
||||
function_types.h
|
||||
|
|
@ -178,6 +180,7 @@ set(llcommon_HEADER_FILES
|
|||
llinitdestroyclass.h
|
||||
llinitparam.h
|
||||
llinstancetracker.h
|
||||
llinstancetrackersubclass.h
|
||||
llkeybind.h
|
||||
llkeythrottle.h
|
||||
llleap.h
|
||||
|
|
@ -251,6 +254,7 @@ set(llcommon_HEADER_FILES
|
|||
stdtypes.h
|
||||
stringize.h
|
||||
threadpool.h
|
||||
threadpool_fwd.h
|
||||
threadsafeschedule.h
|
||||
timer.h
|
||||
tuple.h
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* @file commoncontrol.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2022-06-08
|
||||
* @brief Implementation for commoncontrol.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Copyright (c) 2022, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "commoncontrol.h"
|
||||
// STL headers
|
||||
// std headers
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
#include "llevents.h"
|
||||
#include "llsdutil.h"
|
||||
|
||||
LLSD LL::CommonControl::access(const LLSD& params)
|
||||
{
|
||||
// We can't actually introduce a link-time dependency on llxml, or on any
|
||||
// global LLControlGroup (*koff* gSavedSettings *koff*) but we can issue a
|
||||
// runtime query. If we're running as part of a viewer with
|
||||
// LLViewerControlListener, we can use that to interact with any
|
||||
// instantiated LLControGroup.
|
||||
LLSD response;
|
||||
{
|
||||
LLEventStream reply("reply");
|
||||
LLTempBoundListener connection = reply.listen("listener",
|
||||
[&response] (const LLSD& event)
|
||||
{
|
||||
response = event;
|
||||
return false;
|
||||
});
|
||||
LLSD rparams{ params };
|
||||
rparams["reply"] = reply.getName();
|
||||
LLEventPumps::instance().obtain("LLViewerControl").post(rparams);
|
||||
}
|
||||
// LLViewerControlListener responds immediately. If it's listening at all,
|
||||
// it will already have set response.
|
||||
if (! response.isDefined())
|
||||
{
|
||||
LLTHROW(NoListener("No LLViewerControl listener instantiated"));
|
||||
}
|
||||
LLSD error{ response["error"] };
|
||||
if (error.isDefined())
|
||||
{
|
||||
LLTHROW(ParamError(error));
|
||||
}
|
||||
response.erase("error");
|
||||
response.erase("reqid");
|
||||
return response;
|
||||
}
|
||||
|
||||
/// set control group.key to defined default value
|
||||
LLSD LL::CommonControl::set_default(const std::string& group, const std::string& key)
|
||||
{
|
||||
return access(llsd::map("op", "set",
|
||||
"group", group, "key", key))["value"];
|
||||
}
|
||||
|
||||
/// set control group.key to specified value
|
||||
LLSD LL::CommonControl::set(const std::string& group, const std::string& key, const LLSD& value)
|
||||
{
|
||||
return access(llsd::map("op", "set",
|
||||
"group", group, "key", key, "value", value))["value"];
|
||||
}
|
||||
|
||||
/// toggle boolean control group.key
|
||||
LLSD LL::CommonControl::toggle(const std::string& group, const std::string& key)
|
||||
{
|
||||
return access(llsd::map("op", "toggle",
|
||||
"group", group, "key", key))["value"];
|
||||
}
|
||||
|
||||
/// get the definition for control group.key, (! isDefined()) if bad
|
||||
/// ["name"], ["type"], ["value"], ["comment"]
|
||||
LLSD LL::CommonControl::get_def(const std::string& group, const std::string& key)
|
||||
{
|
||||
return access(llsd::map("op", "get",
|
||||
"group", group, "key", key));
|
||||
}
|
||||
|
||||
/// get the value of control group.key
|
||||
LLSD LL::CommonControl::get(const std::string& group, const std::string& key)
|
||||
{
|
||||
return access(llsd::map("op", "get",
|
||||
"group", group, "key", key))["value"];
|
||||
}
|
||||
|
||||
/// get defined groups
|
||||
std::vector<std::string> LL::CommonControl::get_groups()
|
||||
{
|
||||
auto groups{ access(llsd::map("op", "groups"))["groups"] };
|
||||
return { groups.beginArray(), groups.endArray() };
|
||||
}
|
||||
|
||||
/// get definitions for all variables in group
|
||||
LLSD LL::CommonControl::get_vars(const std::string& group)
|
||||
{
|
||||
return access(llsd::map("op", "vars", "group", group))["vars"];
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* @file commoncontrol.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2022-06-08
|
||||
* @brief Access LLViewerControl LLEventAPI, if process has one.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Copyright (c) 2022, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_COMMONCONTROL_H)
|
||||
#define LL_COMMONCONTROL_H
|
||||
|
||||
#include <vector>
|
||||
#include "llexception.h"
|
||||
#include "llsd.h"
|
||||
|
||||
namespace LL
|
||||
{
|
||||
class CommonControl
|
||||
{
|
||||
public:
|
||||
struct Error: public LLException
|
||||
{
|
||||
Error(const std::string& what): LLException(what) {}
|
||||
};
|
||||
|
||||
/// Exception thrown if there's no LLViewerControl LLEventAPI
|
||||
struct NoListener: public Error
|
||||
{
|
||||
NoListener(const std::string& what): Error(what) {}
|
||||
};
|
||||
|
||||
struct ParamError: public Error
|
||||
{
|
||||
ParamError(const std::string& what): Error(what) {}
|
||||
};
|
||||
|
||||
/// set control group.key to defined default value
|
||||
static
|
||||
LLSD set_default(const std::string& group, const std::string& key);
|
||||
|
||||
/// set control group.key to specified value
|
||||
static
|
||||
LLSD set(const std::string& group, const std::string& key, const LLSD& value);
|
||||
|
||||
/// toggle boolean control group.key
|
||||
static
|
||||
LLSD toggle(const std::string& group, const std::string& key);
|
||||
|
||||
/// get the definition for control group.key, (! isDefined()) if bad
|
||||
/// ["name"], ["type"], ["value"], ["comment"]
|
||||
static
|
||||
LLSD get_def(const std::string& group, const std::string& key);
|
||||
|
||||
/// get the value of control group.key
|
||||
static
|
||||
LLSD get(const std::string& group, const std::string& key);
|
||||
|
||||
/// get defined groups
|
||||
static
|
||||
std::vector<std::string> get_groups();
|
||||
|
||||
/// get definitions for all variables in group
|
||||
static
|
||||
LLSD get_vars(const std::string& group);
|
||||
|
||||
private:
|
||||
static
|
||||
LLSD access(const LLSD& params);
|
||||
};
|
||||
} // namespace LL
|
||||
|
||||
#endif /* ! defined(LL_COMMONCONTROL_H) */
|
||||
|
|
@ -528,6 +528,7 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
|
|||
//static
|
||||
S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
//*****************************************
|
||||
LLAPRFilePoolScope scope(pool);
|
||||
apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), APR_READ|APR_BINARY);
|
||||
|
|
@ -572,6 +573,7 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb
|
|||
//static
|
||||
S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
|
||||
if (offset < 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ LLAssetDictionary::LLAssetDictionary()
|
|||
addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false));
|
||||
addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false));
|
||||
addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true));
|
||||
addEntry(LLAssetType::AT_MATERIAL, new AssetEntry("MATERIAL", "material", "render material", true, true, true));
|
||||
addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false));
|
||||
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE));
|
||||
|
||||
|
|
|
|||
|
|
@ -127,8 +127,9 @@ public:
|
|||
AT_RESERVED_6 = 55,
|
||||
|
||||
AT_SETTINGS = 56, // Collection of settings
|
||||
AT_MATERIAL = 57, // Render Material
|
||||
|
||||
AT_COUNT = 57,
|
||||
AT_COUNT = 58,
|
||||
|
||||
// +*********************************************************+
|
||||
// | TO ADD AN ELEMENT TO THIS ENUM: |
|
||||
|
|
|
|||
|
|
@ -80,8 +80,8 @@ struct LLContextStatus
|
|||
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status);
|
||||
|
||||
#define dumpStack(tag) \
|
||||
if (debugLoggingEnabled(tag)) \
|
||||
{ \
|
||||
LLCallStack cs; \
|
||||
LL_DEBUGS(tag) << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL; \
|
||||
}
|
||||
LL_DEBUGS(tag) << "STACK:\n" \
|
||||
<< "====================\n" \
|
||||
<< LLCallStack() \
|
||||
<< "====================" \
|
||||
<< LL_ENDL;
|
||||
|
|
|
|||
|
|
@ -37,12 +37,13 @@ thread_local bool gProfilerEnabled = false;
|
|||
|
||||
#if (TRACY_ENABLE)
|
||||
// Override new/delete for tracy memory profiling
|
||||
void *operator new(size_t size)
|
||||
|
||||
void* ll_tracy_new(size_t size)
|
||||
{
|
||||
void* ptr;
|
||||
if (gProfilerEnabled)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
//LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
ptr = (malloc)(size);
|
||||
}
|
||||
else
|
||||
|
|
@ -57,12 +58,22 @@ void *operator new(size_t size)
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void operator delete(void *ptr) noexcept
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return ll_tracy_new(size);
|
||||
}
|
||||
|
||||
void* operator new[](std::size_t count)
|
||||
{
|
||||
return ll_tracy_new(count);
|
||||
}
|
||||
|
||||
void ll_tracy_delete(void* ptr)
|
||||
{
|
||||
TracyFree(ptr);
|
||||
if (gProfilerEnabled)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
//LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
(free)(ptr);
|
||||
}
|
||||
else
|
||||
|
|
@ -71,6 +82,16 @@ void operator delete(void *ptr) noexcept
|
|||
}
|
||||
}
|
||||
|
||||
void operator delete(void *ptr) noexcept
|
||||
{
|
||||
ll_tracy_delete(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr) noexcept
|
||||
{
|
||||
ll_tracy_delete(ptr);
|
||||
}
|
||||
|
||||
// C-style malloc/free can't be so easily overridden, so we define tracy versions and use
|
||||
// a pre-processor #define in linden_common.h to redirect to them. The parens around the native
|
||||
// functions below prevents recursive substitution by the preprocessor.
|
||||
|
|
|
|||
|
|
@ -1603,20 +1603,6 @@ namespace LLError
|
|||
}
|
||||
}
|
||||
|
||||
bool debugLoggingEnabled(const std::string& tag)
|
||||
{
|
||||
LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5);
|
||||
if (!lock.isLocked())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
|
||||
LLError::ELevel level = LLError::LEVEL_DEBUG;
|
||||
bool res = checkLevelMap(s->mTagLevelMap, tag, level);
|
||||
return res;
|
||||
}
|
||||
|
||||
void crashdriver(void (*callback)(int*))
|
||||
{
|
||||
// The LLERROR_CRASH macro used to have inline code of the form:
|
||||
|
|
|
|||
|
|
@ -82,9 +82,11 @@ const int LL_ERR_NOERR = 0;
|
|||
|
||||
#ifdef SHOW_ASSERT
|
||||
#define llassert(func) llassert_always_msg(func, #func)
|
||||
#define llassert_msg(func, msg) llassert_always_msg(func, msg)
|
||||
#define llverify(func) llassert_always_msg(func, #func)
|
||||
#else
|
||||
#define llassert(func)
|
||||
#define llassert_msg(func, msg)
|
||||
#define llverify(func) do {if (func) {}} while(0)
|
||||
#endif
|
||||
|
||||
|
|
@ -462,8 +464,31 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
|
|||
LLError::CallSite& _site(_sites[which]); \
|
||||
lllog_test_()
|
||||
|
||||
// Check at run-time whether logging is enabled, without generating output
|
||||
/*
|
||||
// Check at run-time whether logging is enabled, without generating output.
|
||||
Resist the temptation to add a function like this because it incurs the
|
||||
expense of locking and map-searching every time control reaches it.
|
||||
bool debugLoggingEnabled(const std::string& tag);
|
||||
|
||||
Instead of:
|
||||
|
||||
if debugLoggingEnabled("SomeTag")
|
||||
{
|
||||
// ... presumably expensive operation ...
|
||||
LL_DEBUGS("SomeTag") << ... << LL_ENDL;
|
||||
}
|
||||
|
||||
Use this:
|
||||
|
||||
LL_DEBUGS("SomeTag");
|
||||
// ... presumably expensive operation ...
|
||||
LL_CONT << ...;
|
||||
LL_ENDL;
|
||||
|
||||
LL_DEBUGS("SomeTag") performs the locking and map-searching ONCE, then caches
|
||||
the result in a static variable.
|
||||
*/
|
||||
|
||||
// used by LLERROR_CRASH
|
||||
void crashdriver(void (*)(int*));
|
||||
|
||||
|
|
|
|||
|
|
@ -29,11 +29,6 @@
|
|||
|
||||
#include "llframetimer.h"
|
||||
|
||||
// We don't bother building a stand alone lib; we just need to include the one source file for Tracy support
|
||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
|
||||
#include "TracyClient.cpp"
|
||||
#endif // LL_PROFILER_CONFIGURATION
|
||||
|
||||
// Static members
|
||||
//LLTimer LLFrameTimer::sInternalTimer;
|
||||
U64 LLFrameTimer::sStartTotalTime = totalTime();
|
||||
|
|
|
|||
|
|
@ -104,22 +104,26 @@ public:
|
|||
return LockStatic()->mMap.size();
|
||||
}
|
||||
|
||||
// snapshot of std::pair<const KEY, std::shared_ptr<T>> pairs
|
||||
class snapshot
|
||||
// snapshot of std::pair<const KEY, std::shared_ptr<SUBCLASS>> pairs, for
|
||||
// some SUBCLASS derived from T
|
||||
template <typename SUBCLASS>
|
||||
class snapshot_of
|
||||
{
|
||||
// It's very important that what we store in this snapshot are
|
||||
// weak_ptrs, NOT shared_ptrs. That's how we discover whether any
|
||||
// instance has been deleted during the lifespan of a snapshot.
|
||||
typedef std::vector<std::pair<const KEY, weak_t>> VectorType;
|
||||
// Dereferencing our iterator produces a std::shared_ptr for each
|
||||
// instance that still exists. Since we store weak_ptrs, that involves
|
||||
// two chained transformations:
|
||||
// Dereferencing the iterator we publish produces a
|
||||
// std::shared_ptr<SUBCLASS> for each instance that still exists.
|
||||
// Since we store weak_ptr<T>, that involves two chained
|
||||
// transformations:
|
||||
// - a transform_iterator to lock the weak_ptr and return a shared_ptr
|
||||
// - a filter_iterator to skip any shared_ptr that has become invalid.
|
||||
// - a filter_iterator to skip any shared_ptr<T> that has become
|
||||
// invalid or references any T instance that isn't SUBCLASS.
|
||||
// It is very important that we filter lazily, that is, during
|
||||
// traversal. Any one of our stored weak_ptrs might expire during
|
||||
// traversal.
|
||||
typedef std::pair<const KEY, ptr_t> strong_pair;
|
||||
typedef std::pair<const KEY, std::shared_ptr<SUBCLASS>> strong_pair;
|
||||
// Note for future reference: nat has not yet had any luck (up to
|
||||
// Boost 1.67) trying to use boost::transform_iterator with a hand-
|
||||
// coded functor, only with actual functions. In my experience, an
|
||||
|
|
@ -127,7 +131,7 @@ public:
|
|||
// result_type typedef. But this works.
|
||||
static strong_pair strengthen(typename VectorType::value_type& pair)
|
||||
{
|
||||
return { pair.first, pair.second.lock() };
|
||||
return { pair.first, std::dynamic_pointer_cast<SUBCLASS>(pair.second.lock()) };
|
||||
}
|
||||
static bool dead_skipper(const strong_pair& pair)
|
||||
{
|
||||
|
|
@ -135,7 +139,7 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
snapshot():
|
||||
snapshot_of():
|
||||
// populate our vector with a snapshot of (locked!) InstanceMap
|
||||
// note, this assigns pair<KEY, shared_ptr> to pair<KEY, weak_ptr>
|
||||
mData(mLock->mMap.begin(), mLock->mMap.end())
|
||||
|
|
@ -184,44 +188,51 @@ public:
|
|||
#endif // LL_WINDOWS
|
||||
VectorType mData;
|
||||
};
|
||||
using snapshot = snapshot_of<T>;
|
||||
|
||||
// iterate over this for references to each instance
|
||||
class instance_snapshot: public snapshot
|
||||
// iterate over this for references to each SUBCLASS instance
|
||||
template <typename SUBCLASS>
|
||||
class instance_snapshot_of: public snapshot_of<SUBCLASS>
|
||||
{
|
||||
private:
|
||||
static T& instance_getter(typename snapshot::iterator::reference pair)
|
||||
using super = snapshot_of<SUBCLASS>;
|
||||
static T& instance_getter(typename super::iterator::reference pair)
|
||||
{
|
||||
return *pair.second;
|
||||
}
|
||||
public:
|
||||
typedef boost::transform_iterator<decltype(instance_getter)*,
|
||||
typename snapshot::iterator> iterator;
|
||||
iterator begin() { return iterator(snapshot::begin(), instance_getter); }
|
||||
iterator end() { return iterator(snapshot::end(), instance_getter); }
|
||||
typename super::iterator> iterator;
|
||||
iterator begin() { return iterator(super::begin(), instance_getter); }
|
||||
iterator end() { return iterator(super::end(), instance_getter); }
|
||||
|
||||
void deleteAll()
|
||||
{
|
||||
for (auto it(snapshot::begin()), end(snapshot::end()); it != end; ++it)
|
||||
for (auto it(super::begin()), end(super::end()); it != end; ++it)
|
||||
{
|
||||
delete it->second.get();
|
||||
}
|
||||
}
|
||||
};
|
||||
using instance_snapshot = instance_snapshot_of<T>;
|
||||
|
||||
// iterate over this for each key
|
||||
class key_snapshot: public snapshot
|
||||
template <typename SUBCLASS>
|
||||
class key_snapshot_of: public snapshot_of<SUBCLASS>
|
||||
{
|
||||
private:
|
||||
static KEY key_getter(typename snapshot::iterator::reference pair)
|
||||
using super = snapshot_of<SUBCLASS>;
|
||||
static KEY key_getter(typename super::iterator::reference pair)
|
||||
{
|
||||
return pair.first;
|
||||
}
|
||||
public:
|
||||
typedef boost::transform_iterator<decltype(key_getter)*,
|
||||
typename snapshot::iterator> iterator;
|
||||
iterator begin() { return iterator(snapshot::begin(), key_getter); }
|
||||
iterator end() { return iterator(snapshot::end(), key_getter); }
|
||||
typename super::iterator> iterator;
|
||||
iterator begin() { return iterator(super::begin(), key_getter); }
|
||||
iterator end() { return iterator(super::end(), key_getter); }
|
||||
};
|
||||
using key_snapshot = key_snapshot_of<T>;
|
||||
|
||||
static ptr_t getInstance(const KEY& k)
|
||||
{
|
||||
|
|
@ -368,22 +379,25 @@ public:
|
|||
return LockStatic()->mSet.size();
|
||||
}
|
||||
|
||||
// snapshot of std::shared_ptr<T> pointers
|
||||
class snapshot
|
||||
// snapshot of std::shared_ptr<SUBCLASS> pointers
|
||||
template <typename SUBCLASS>
|
||||
class snapshot_of
|
||||
{
|
||||
// It's very important that what we store in this snapshot are
|
||||
// weak_ptrs, NOT shared_ptrs. That's how we discover whether any
|
||||
// instance has been deleted during the lifespan of a snapshot.
|
||||
typedef std::vector<weak_t> VectorType;
|
||||
// Dereferencing our iterator produces a std::shared_ptr for each
|
||||
// instance that still exists. Since we store weak_ptrs, that involves
|
||||
// two chained transformations:
|
||||
// Dereferencing the iterator we publish produces a
|
||||
// std::shared_ptr<SUBCLASS> for each instance that still exists.
|
||||
// Since we store weak_ptrs, that involves two chained
|
||||
// transformations:
|
||||
// - a transform_iterator to lock the weak_ptr and return a shared_ptr
|
||||
// - a filter_iterator to skip any shared_ptr that has become invalid.
|
||||
typedef std::shared_ptr<T> strong_ptr;
|
||||
// - a filter_iterator to skip any shared_ptr that has become invalid
|
||||
// or references any T instance that isn't SUBCLASS.
|
||||
typedef std::shared_ptr<SUBCLASS> strong_ptr;
|
||||
static strong_ptr strengthen(typename VectorType::value_type& ptr)
|
||||
{
|
||||
return ptr.lock();
|
||||
return std::dynamic_pointer_cast<SUBCLASS>(ptr.lock());
|
||||
}
|
||||
static bool dead_skipper(const strong_ptr& ptr)
|
||||
{
|
||||
|
|
@ -391,7 +405,7 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
snapshot():
|
||||
snapshot_of():
|
||||
// populate our vector with a snapshot of (locked!) InstanceSet
|
||||
// note, this assigns stored shared_ptrs to weak_ptrs for snapshot
|
||||
mData(mLock->mSet.begin(), mLock->mSet.end())
|
||||
|
|
@ -437,22 +451,33 @@ public:
|
|||
#endif // LL_WINDOWS
|
||||
VectorType mData;
|
||||
};
|
||||
using snapshot = snapshot_of<T>;
|
||||
|
||||
// iterate over this for references to each instance
|
||||
struct instance_snapshot: public snapshot
|
||||
template <typename SUBCLASS>
|
||||
class instance_snapshot_of: public snapshot_of<SUBCLASS>
|
||||
{
|
||||
typedef boost::indirect_iterator<typename snapshot::iterator> iterator;
|
||||
iterator begin() { return iterator(snapshot::begin()); }
|
||||
iterator end() { return iterator(snapshot::end()); }
|
||||
private:
|
||||
using super = snapshot_of<SUBCLASS>;
|
||||
|
||||
public:
|
||||
typedef boost::indirect_iterator<typename super::iterator> iterator;
|
||||
iterator begin() { return iterator(super::begin()); }
|
||||
iterator end() { return iterator(super::end()); }
|
||||
|
||||
void deleteAll()
|
||||
{
|
||||
for (auto it(snapshot::begin()), end(snapshot::end()); it != end; ++it)
|
||||
for (auto it(super::begin()), end(super::end()); it != end; ++it)
|
||||
{
|
||||
delete it->get();
|
||||
}
|
||||
}
|
||||
};
|
||||
using instance_snapshot = instance_snapshot_of<T>;
|
||||
// key_snapshot_of isn't really meaningful, but define it anyway to avoid
|
||||
// requiring two different LLInstanceTrackerSubclass implementations.
|
||||
template <typename SUBCLASS>
|
||||
using key_snapshot_of = instance_snapshot_of<SUBCLASS>;
|
||||
|
||||
protected:
|
||||
LLInstanceTracker()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
/**
|
||||
* @file llinstancetrackersubclass.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2022-12-09
|
||||
* @brief Intermediate class to get subclass-specific types from
|
||||
* LLInstanceTracker instance-retrieval methods.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Copyright (c) 2022, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_LLINSTANCETRACKERSUBCLASS_H)
|
||||
#define LL_LLINSTANCETRACKERSUBCLASS_H
|
||||
|
||||
#include <memory> // std::shared_ptr, std::weak_ptr
|
||||
|
||||
/**
|
||||
* Derive your subclass S of a subclass T of LLInstanceTracker<T> from
|
||||
* LLInstanceTrackerSubclass<S, T> to perform appropriate downcasting and
|
||||
* filtering for LLInstanceTracker access methods.
|
||||
*
|
||||
* LLInstanceTracker<T> uses CRTP, so that getWeak(), getInstance(), snapshot
|
||||
* and instance_snapshot return pointers and references to T. The trouble is
|
||||
* that subclasses T0 and T1 derived from T also get pointers and references
|
||||
* to their base class T, requiring explicit downcasting. Moreover,
|
||||
* T0::getInstance() shouldn't find an instance of any T subclass other than
|
||||
* T0. Nor should T0::snapshot.
|
||||
*
|
||||
* @code
|
||||
* class Tracked: public LLInstanceTracker<Tracked, std::string>
|
||||
* {
|
||||
* private:
|
||||
* using super = LLInstanceTracker<Tracked, std::string>;
|
||||
* public:
|
||||
* Tracked(const std::string& name): super(name) {}
|
||||
* // All references to Tracked::ptr_t, Tracked::getInstance() etc.
|
||||
* // appropriately use Tracked.
|
||||
* // ...
|
||||
* };
|
||||
*
|
||||
* // But now we derive SubTracked from Tracked. We need SubTracked::ptr_t,
|
||||
* // SubTracked::getInstance() etc. to use SubTracked, not Tracked.
|
||||
* // This LLInstanceTrackerSubclass specialization is itself derived from
|
||||
* // Tracked.
|
||||
* class SubTracked: public LLInstanceTrackerSubclass<SubTracked, Tracked>
|
||||
* {
|
||||
* private:
|
||||
* using super = LLInstanceTrackerSubclass<SubTracked, Tracked>;
|
||||
* public:
|
||||
* // LLInstanceTrackerSubclass's constructor forwards to Tracked's.
|
||||
* SubTracked(const std::string& name): super(name) {}
|
||||
* // SubTracked::getInstance() returns std::shared_ptr<SubTracked>, etc.
|
||||
* // ...
|
||||
* @endcode
|
||||
*/
|
||||
template <typename SUBCLASS, typename T>
|
||||
class LLInstanceTrackerSubclass: public T
|
||||
{
|
||||
public:
|
||||
using ptr_t = std::shared_ptr<SUBCLASS>;
|
||||
using weak_t = std::weak_ptr<SUBCLASS>;
|
||||
|
||||
// forward any constructor call to the corresponding T ctor
|
||||
template <typename... ARGS>
|
||||
LLInstanceTrackerSubclass(ARGS&&... args):
|
||||
T(std::forward<ARGS>(args)...)
|
||||
{}
|
||||
|
||||
weak_t getWeak()
|
||||
{
|
||||
// call base-class getWeak(), try to lock, downcast to SUBCLASS
|
||||
return std::dynamic_pointer_cast<SUBCLASS>(T::getWeak().lock());
|
||||
}
|
||||
|
||||
template <typename KEY>
|
||||
static ptr_t getInstance(const KEY& k)
|
||||
{
|
||||
return std::dynamic_pointer_cast<SUBCLASS>(T::getInstance(k));
|
||||
}
|
||||
|
||||
using snapshot = typename T::template snapshot_of<SUBCLASS>;
|
||||
using instance_snapshot = typename T::template instance_snapshot_of<SUBCLASS>;
|
||||
using key_snapshot = typename T::template key_snapshot_of<SUBCLASS>;
|
||||
|
||||
static size_t instanceCount()
|
||||
{
|
||||
// T::instanceCount() lies because our snapshot, et al., won't
|
||||
// necessarily return all the T instances -- only those that are also
|
||||
// SUBCLASS instances. Count those.
|
||||
size_t count = 0;
|
||||
for (const auto& pair : snapshot())
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ! defined(LL_LLINSTANCETRACKERSUBCLASS_H) */
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
# include <sys/types.h>
|
||||
# include <mach/task.h>
|
||||
# include <mach/mach_init.h>
|
||||
#include <mach/mach_host.h>
|
||||
#elif LL_LINUX
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
|
@ -109,6 +110,50 @@ void LLMemory::updateMemoryInfo()
|
|||
{
|
||||
sAvailPhysicalMemInKB = U32Kilobytes(0);
|
||||
}
|
||||
|
||||
#elif defined(LL_DARWIN)
|
||||
task_vm_info info;
|
||||
mach_msg_type_number_t infoCount = TASK_VM_INFO_COUNT;
|
||||
// MACH_TASK_BASIC_INFO reports the same resident_size, but does not tell us the reusable bytes or phys_footprint.
|
||||
if (task_info(mach_task_self(), TASK_VM_INFO, reinterpret_cast<task_info_t>(&info), &infoCount) == KERN_SUCCESS)
|
||||
{
|
||||
// Our Windows definition of PagefileUsage is documented by Microsoft as "the total amount of
|
||||
// memory that the memory manager has committed for a running process", which is rss.
|
||||
sAllocatedPageSizeInKB = U32Bytes(info.resident_size);
|
||||
|
||||
// Activity Monitor => Inspect Process => Real Memory Size appears to report resident_size
|
||||
// Activity monitor => main window memory column appears to report phys_footprint, which spot checks as at least 30% less.
|
||||
// I think that is because of compression, which isn't going to give us a consistent measurement. We want uncompressed totals.
|
||||
//
|
||||
// In between is resident_size - reusable. This is what Chrome source code uses, with source comments saying it is 'the "Real Memory" value
|
||||
// reported for the app by the Memory Monitor in Instruments.' It is still about 8% bigger than phys_footprint.
|
||||
//
|
||||
// (On Windows, we use WorkingSetSize.)
|
||||
sAllocatedMemInKB = U32Bytes(info.resident_size - info.reusable);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "task_info failed" << LL_ENDL;
|
||||
}
|
||||
|
||||
// Total installed and available physical memory are properties of the host, not just our process.
|
||||
vm_statistics64_data_t vmstat;
|
||||
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
|
||||
mach_port_t host = mach_host_self();
|
||||
vm_size_t page_size;
|
||||
host_page_size(host, &page_size);
|
||||
kern_return_t result = host_statistics64(host, HOST_VM_INFO64, reinterpret_cast<host_info_t>(&vmstat), &count);
|
||||
if (result == KERN_SUCCESS) {
|
||||
// This is what Chrome reports as 'the "Physical Memory Free" value reported by the Memory Monitor in Instruments.'
|
||||
// Note though that inactive pages are not included here and not yet free, but could become so under memory pressure.
|
||||
sAvailPhysicalMemInKB = U32Bytes(vmstat.free_count * page_size);
|
||||
sMaxPhysicalMemInKB = LLMemoryInfo::getHardwareMemSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "task_info failed" << LL_ENDL;
|
||||
}
|
||||
|
||||
#else
|
||||
//not valid for other systems for now.
|
||||
sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS());
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@
|
|||
|
||||
//============================================================================
|
||||
|
||||
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
|
||||
//#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
|
||||
#define MUTEX_DEBUG 0 //disable mutex debugging as it's interfering with profiles
|
||||
|
||||
#if MUTEX_DEBUG
|
||||
#include <map>
|
||||
|
|
@ -61,7 +62,7 @@ protected:
|
|||
mutable LLThread::id_t mLockingThread;
|
||||
|
||||
#if MUTEX_DEBUG
|
||||
std::map<LLThread::id_t, BOOL> mIsLocked;
|
||||
std::unordered_map<LLThread::id_t, BOOL> mIsLocked;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -340,4 +340,28 @@ private:
|
|||
bool mStayUnique;
|
||||
};
|
||||
|
||||
|
||||
// boost hash adapter
|
||||
template <class Type>
|
||||
struct boost::hash<LLPointer<Type>>
|
||||
{
|
||||
typedef LLPointer<Type> argument_type;
|
||||
typedef std::size_t result_type;
|
||||
result_type operator()(argument_type const& s) const
|
||||
{
|
||||
return (std::size_t) s.get();
|
||||
}
|
||||
};
|
||||
|
||||
// Adapt boost hash to std hash
|
||||
namespace std
|
||||
{
|
||||
template<class Type> struct hash<LLPointer<Type>>
|
||||
{
|
||||
std::size_t operator()(LLPointer<Type> const& s) const noexcept
|
||||
{
|
||||
return boost::hash<LLPointer<Type>>()(s);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -86,8 +86,12 @@ extern thread_local bool gProfilerEnabled;
|
|||
#define TRACY_ONLY_IPV4 1
|
||||
#include "Tracy.hpp"
|
||||
|
||||
// Mutually exclusive with detailed memory tracing
|
||||
// Enable OpenGL profiling
|
||||
#define LL_PROFILER_ENABLE_TRACY_OPENGL 0
|
||||
|
||||
// Enable RenderDoc labeling
|
||||
#define LL_PROFILER_ENABLE_RENDER_DOC 0
|
||||
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY
|
||||
|
|
@ -104,14 +108,13 @@ extern thread_local bool gProfilerEnabled;
|
|||
#define LL_PROFILE_ZONE_ERR(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000 ) // RGB yellow
|
||||
#define LL_PROFILE_ZONE_INFO(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF ) // RGB cyan
|
||||
#define LL_PROFILE_ZONE_WARN(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 ) // RGB red
|
||||
#define LL_PROFILE_ALLOC(ptr, size) TracyAlloc(ptr, size)
|
||||
#define LL_PROFILE_FREE(ptr) TracyFree(ptr)
|
||||
#endif
|
||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER
|
||||
#define LL_PROFILER_FRAME_END
|
||||
#define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
|
||||
#define LL_RECORD_BLOCK_TIME(name) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
|
||||
#define LL_PROFILE_ZONE_NAMED(name) // LL_PROFILE_ZONE_NAMED is a no-op when Tracy is disabled
|
||||
#define LL_PROFILE_ZONE_NAMED_COLOR(name,color) // LL_PROFILE_ZONE_NAMED_COLOR is a no-op when Tracy is disabled
|
||||
#define LL_PROFILE_ZONE_SCOPED // LL_PROFILE_ZONE_SCOPED is a no-op when Tracy is disabled
|
||||
#define LL_PROFILE_ZONE_COLOR(name,color) // LL_RECORD_BLOCK_TIME(name)
|
||||
|
||||
|
|
@ -121,8 +124,6 @@ extern thread_local bool gProfilerEnabled;
|
|||
#define LL_PROFILE_ZONE_ERR(name) (void)(name); // Not supported
|
||||
#define LL_PROFILE_ZONE_INFO(name) (void)(name); // Not supported
|
||||
#define LL_PROFILE_ZONE_WARN(name) (void)(name); // Not supported
|
||||
#define LL_PROFILE_ALLOC(ptr, size) (void)(ptr); (void)(size);
|
||||
#define LL_PROFILE_FREE(ptr) (void)(ptr);
|
||||
#endif
|
||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
|
||||
#define LL_PROFILER_FRAME_END FrameMark
|
||||
|
|
@ -138,14 +139,45 @@ extern thread_local bool gProfilerEnabled;
|
|||
#define LL_PROFILE_ZONE_ERR(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000 ) // RGB yellow
|
||||
#define LL_PROFILE_ZONE_INFO(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF ) // RGB cyan
|
||||
#define LL_PROFILE_ZONE_WARN(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 ) // RGB red
|
||||
#define LL_PROFILE_ALLOC(ptr, size) TracyAlloc(ptr, size)
|
||||
#define LL_PROFILE_FREE(ptr) TracyFree(ptr)
|
||||
#endif
|
||||
#else
|
||||
#define LL_PROFILER_FRAME_END
|
||||
#define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
|
||||
#endif // LL_PROFILER
|
||||
|
||||
#if LL_PROFILER_ENABLE_TRACY_OPENGL
|
||||
#define LL_PROFILE_GPU_ZONE(name) TracyGpuZone(name)
|
||||
#define LL_PROFILE_GPU_ZONEC(name,color) TracyGpuZoneC(name,color)
|
||||
#define LL_PROFILER_GPU_COLLECT TracyGpuCollect
|
||||
#define LL_PROFILER_GPU_CONTEXT TracyGpuContext
|
||||
|
||||
// disable memory tracking (incompatible with GPU tracing
|
||||
#define LL_PROFILE_ALLOC(ptr, size) (void)(ptr); (void)(size);
|
||||
#define LL_PROFILE_FREE(ptr) (void)(ptr);
|
||||
#else
|
||||
#define LL_PROFILE_GPU_ZONE(name) (void)name;
|
||||
#define LL_PROFILE_GPU_ZONEC(name,color) (void)name;(void)color;
|
||||
#define LL_PROFILER_GPU_COLLECT
|
||||
#define LL_PROFILER_GPU_CONTEXT
|
||||
|
||||
#define LL_LABEL_OBJECT_GL(type, name, length, label)
|
||||
|
||||
#if LL_PROFILER_CONFIGURATION > 1
|
||||
#define LL_PROFILE_ALLOC(ptr, size) TracyAlloc(ptr, size)
|
||||
#define LL_PROFILE_FREE(ptr) TracyFree(ptr)
|
||||
#else
|
||||
#define LL_PROFILE_ALLOC(ptr, size) (void)(ptr); (void)(size);
|
||||
#define LL_PROFILE_FREE(ptr) (void)(ptr);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_ENABLE_RENDER_DOC
|
||||
#define LL_LABEL_OBJECT_GL(type, name, length, label) glObjectLabel(type, name, length, label)
|
||||
#else
|
||||
#define LL_LABEL_OBJECT_GL(type, name, length, label)
|
||||
#endif
|
||||
|
||||
#include "llprofilercategories.h"
|
||||
|
||||
#endif // LL_PROFILER_H
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
#define LL_PROFILER_CATEGORY_ENABLE_LOGGING 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_MATERIAL 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_MEDIA 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_MEMORY 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_MEMORY 0
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_NETWORK 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_OCTREE 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_PIPELINE 1
|
||||
|
|
|
|||
|
|
@ -26,20 +26,26 @@
|
|||
#include "linden_common.h"
|
||||
#include "llqueuedthread.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "llstl.h"
|
||||
#include "lltimer.h" // ms_sleep()
|
||||
#include "lltracethreadrecorder.h"
|
||||
#include "llmutex.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
// MAIN THREAD
|
||||
LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) :
|
||||
LLThread(name),
|
||||
mThreaded(threaded),
|
||||
mIdleThread(TRUE),
|
||||
mNextHandle(0),
|
||||
mStarted(FALSE)
|
||||
mStarted(FALSE),
|
||||
mThreaded(threaded),
|
||||
mRequestQueue(name, 1024 * 1024)
|
||||
{
|
||||
llassert(threaded); // not threaded implementation is deprecated
|
||||
mMainQueue = LL::WorkQueue::getInstance("mainloop");
|
||||
|
||||
if (mThreaded)
|
||||
{
|
||||
if(should_pause)
|
||||
|
|
@ -69,6 +75,11 @@ void LLQueuedThread::shutdown()
|
|||
unpause(); // MAIN THREAD
|
||||
if (mThreaded)
|
||||
{
|
||||
if (mRequestQueue.size() == 0)
|
||||
{
|
||||
mRequestQueue.close();
|
||||
}
|
||||
|
||||
S32 timeout = 100;
|
||||
for ( ; timeout>0; timeout--)
|
||||
{
|
||||
|
|
@ -104,6 +115,8 @@ void LLQueuedThread::shutdown()
|
|||
{
|
||||
LL_WARNS() << "~LLQueuedThread() called with active requests: " << active_count << LL_ENDL;
|
||||
}
|
||||
|
||||
mRequestQueue.close();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
@ -112,6 +125,7 @@ void LLQueuedThread::shutdown()
|
|||
// virtual
|
||||
size_t LLQueuedThread::update(F32 max_time_ms)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
if (!mStarted)
|
||||
{
|
||||
if (!mThreaded)
|
||||
|
|
@ -125,29 +139,34 @@ size_t LLQueuedThread::update(F32 max_time_ms)
|
|||
|
||||
size_t LLQueuedThread::updateQueue(F32 max_time_ms)
|
||||
{
|
||||
F64 max_time = (F64)max_time_ms * .001;
|
||||
LLTimer timer;
|
||||
size_t pending = 1;
|
||||
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
// Frame Update
|
||||
if (mThreaded)
|
||||
{
|
||||
pending = getPending();
|
||||
if(pending > 0)
|
||||
// schedule a call to threadedUpdate for every call to updateQueue
|
||||
if (!isQuitting())
|
||||
{
|
||||
mRequestQueue.post([=]()
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qt - update");
|
||||
mIdleThread = FALSE;
|
||||
threadedUpdate();
|
||||
mIdleThread = TRUE;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if(getPending() > 0)
|
||||
{
|
||||
unpause();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (pending > 0)
|
||||
{
|
||||
pending = processNextRequest();
|
||||
if (max_time && timer.getElapsedTimeF64() > max_time)
|
||||
break;
|
||||
mRequestQueue.runFor(std::chrono::microseconds((int) (max_time_ms*1000.f)));
|
||||
threadedUpdate();
|
||||
}
|
||||
}
|
||||
return pending;
|
||||
return getPending();
|
||||
}
|
||||
|
||||
void LLQueuedThread::incQueue()
|
||||
|
|
@ -166,11 +185,7 @@ void LLQueuedThread::incQueue()
|
|||
// May be called from any thread
|
||||
size_t LLQueuedThread::getPending()
|
||||
{
|
||||
size_t res;
|
||||
lockData();
|
||||
res = mRequestQueue.size();
|
||||
unlockData();
|
||||
return res;
|
||||
return mRequestQueue.size();
|
||||
}
|
||||
|
||||
// MAIN thread
|
||||
|
|
@ -195,35 +210,28 @@ void LLQueuedThread::waitOnPending()
|
|||
// MAIN thread
|
||||
void LLQueuedThread::printQueueStats()
|
||||
{
|
||||
lockData();
|
||||
if (!mRequestQueue.empty())
|
||||
U32 size = mRequestQueue.size();
|
||||
if (size > 0)
|
||||
{
|
||||
QueuedRequest *req = *mRequestQueue.begin();
|
||||
LL_INFOS() << llformat("Pending Requests:%d Current status:%d", mRequestQueue.size(), req->getStatus()) << LL_ENDL;
|
||||
LL_INFOS() << llformat("Pending Requests:%d ", mRequestQueue.size()) << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() << "Queued Thread Idle" << LL_ENDL;
|
||||
}
|
||||
unlockData();
|
||||
}
|
||||
|
||||
// MAIN thread
|
||||
LLQueuedThread::handle_t LLQueuedThread::generateHandle()
|
||||
{
|
||||
lockData();
|
||||
while ((mNextHandle == nullHandle()) || (mRequestHash.find(mNextHandle)))
|
||||
{
|
||||
mNextHandle++;
|
||||
}
|
||||
const LLQueuedThread::handle_t res = mNextHandle++;
|
||||
unlockData();
|
||||
U32 res = ++mNextHandle;
|
||||
return res;
|
||||
}
|
||||
|
||||
// MAIN thread
|
||||
bool LLQueuedThread::addRequest(QueuedRequest* req)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
if (mStatus == QUITTING)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -231,14 +239,14 @@ bool LLQueuedThread::addRequest(QueuedRequest* req)
|
|||
|
||||
lockData();
|
||||
req->setStatus(STATUS_QUEUED);
|
||||
mRequestQueue.insert(req);
|
||||
mRequestHash.insert(req);
|
||||
#if _DEBUG
|
||||
// LL_INFOS() << llformat("LLQueuedThread::Added req [%08d]",handle) << LL_ENDL;
|
||||
#endif
|
||||
unlockData();
|
||||
|
||||
incQueue();
|
||||
llassert(!mDataLock->isSelfLocked());
|
||||
mRequestQueue.post([this, req]() { processRequest(req); });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -246,6 +254,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req)
|
|||
// MAIN thread
|
||||
bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_complete)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
llassert (handle != nullHandle());
|
||||
bool res = false;
|
||||
bool waspaused = isPaused();
|
||||
|
|
@ -312,6 +321,7 @@ LLQueuedThread::status_t LLQueuedThread::getRequestStatus(handle_t handle)
|
|||
|
||||
void LLQueuedThread::abortRequest(handle_t handle, bool autocomplete)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
lockData();
|
||||
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
||||
if (req)
|
||||
|
|
@ -333,30 +343,9 @@ void LLQueuedThread::setFlags(handle_t handle, U32 flags)
|
|||
unlockData();
|
||||
}
|
||||
|
||||
void LLQueuedThread::setPriority(handle_t handle, U32 priority)
|
||||
{
|
||||
lockData();
|
||||
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
||||
if (req)
|
||||
{
|
||||
if(req->getStatus() == STATUS_INPROGRESS)
|
||||
{
|
||||
// not in list
|
||||
req->setPriority(priority);
|
||||
}
|
||||
else if(req->getStatus() == STATUS_QUEUED)
|
||||
{
|
||||
// remove from list then re-insert
|
||||
llverify(mRequestQueue.erase(req) == 1);
|
||||
req->setPriority(priority);
|
||||
mRequestQueue.insert(req);
|
||||
}
|
||||
}
|
||||
unlockData();
|
||||
}
|
||||
|
||||
bool LLQueuedThread::completeRequest(handle_t handle)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
bool res = false;
|
||||
lockData();
|
||||
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
||||
|
|
@ -399,23 +388,19 @@ bool LLQueuedThread::check()
|
|||
//============================================================================
|
||||
// Runs on its OWN thread
|
||||
|
||||
size_t LLQueuedThread::processNextRequest()
|
||||
void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req)
|
||||
{
|
||||
QueuedRequest *req;
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
|
||||
mIdleThread = FALSE;
|
||||
//threadedUpdate();
|
||||
|
||||
// Get next request from pool
|
||||
lockData();
|
||||
|
||||
while(1)
|
||||
{
|
||||
req = NULL;
|
||||
if (mRequestQueue.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
req = *mRequestQueue.begin();
|
||||
mRequestQueue.erase(mRequestQueue.begin());
|
||||
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qtpr - abort");
|
||||
req->setStatus(STATUS_ABORTED);
|
||||
req->finishRequest(false);
|
||||
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||
|
|
@ -424,16 +409,15 @@ size_t LLQueuedThread::processNextRequest()
|
|||
req->deleteRequest();
|
||||
// check();
|
||||
}
|
||||
continue;
|
||||
unlockData();
|
||||
}
|
||||
else
|
||||
{
|
||||
llassert_always(req->getStatus() == STATUS_QUEUED);
|
||||
break;
|
||||
}
|
||||
U32 start_priority = 0 ;
|
||||
|
||||
if (req)
|
||||
{
|
||||
req->setStatus(STATUS_INPROGRESS);
|
||||
start_priority = req->getPriority();
|
||||
}
|
||||
unlockData();
|
||||
|
||||
|
|
@ -447,6 +431,7 @@ size_t LLQueuedThread::processNextRequest()
|
|||
|
||||
if (complete)
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qtpr - complete");
|
||||
lockData();
|
||||
req->setStatus(STATUS_COMPLETE);
|
||||
req->finishRequest(true);
|
||||
|
|
@ -454,33 +439,69 @@ size_t LLQueuedThread::processNextRequest()
|
|||
{
|
||||
mRequestHash.erase(req);
|
||||
req->deleteRequest();
|
||||
// check();
|
||||
// check();
|
||||
}
|
||||
unlockData();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qtpr - retry");
|
||||
//put back on queue and try again in 0.1ms
|
||||
lockData();
|
||||
req->setStatus(STATUS_QUEUED);
|
||||
mRequestQueue.insert(req);
|
||||
|
||||
unlockData();
|
||||
if (mThreaded && start_priority < PRIORITY_NORMAL)
|
||||
|
||||
llassert(!mDataLock->isSelfLocked());
|
||||
|
||||
#if 0
|
||||
// try again on next frame
|
||||
// NOTE: tried using "post" with a time in the future, but this
|
||||
// would invariably cause this thread to wait for a long time (10+ ms)
|
||||
// while work is pending
|
||||
bool ret = LL::WorkQueue::postMaybe(
|
||||
mMainQueue,
|
||||
[=]()
|
||||
{
|
||||
ms_sleep(1); // sleep the thread a little
|
||||
LL_PROFILE_ZONE_NAMED("processRequest - retry");
|
||||
mRequestQueue.post([=]()
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED("processRequest - retry"); // <-- not redundant, track retry on both queues
|
||||
processRequest(req);
|
||||
});
|
||||
});
|
||||
llassert(ret);
|
||||
#else
|
||||
using namespace std::chrono_literals;
|
||||
auto retry_time = LL::WorkQueue::TimePoint::clock::now() + 16ms;
|
||||
mRequestQueue.post([=]
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED("processRequest - retry");
|
||||
if (LL::WorkQueue::TimePoint::clock::now() < retry_time)
|
||||
{
|
||||
auto sleep_time = std::chrono::duration_cast<std::chrono::milliseconds>(retry_time - LL::WorkQueue::TimePoint::clock::now());
|
||||
|
||||
if (sleep_time.count() > 0)
|
||||
{
|
||||
ms_sleep(sleep_time.count());
|
||||
}
|
||||
}
|
||||
processRequest(req);
|
||||
});
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLTrace::get_thread_recorder()->pushToParent();
|
||||
}
|
||||
|
||||
return getPending();
|
||||
mIdleThread = TRUE;
|
||||
}
|
||||
|
||||
// virtual
|
||||
bool LLQueuedThread::runCondition()
|
||||
{
|
||||
// mRunCondition must be locked here
|
||||
if (mRequestQueue.empty() && mIdleThread)
|
||||
if (mRequestQueue.size() == 0 && mIdleThread)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
|
|
@ -494,18 +515,13 @@ void LLQueuedThread::run()
|
|||
startThread();
|
||||
mStarted = TRUE;
|
||||
|
||||
while (1)
|
||||
|
||||
/*while (1)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
// this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state.
|
||||
checkPause();
|
||||
|
||||
if (isQuitting())
|
||||
{
|
||||
LLTrace::get_thread_recorder()->pushToParent();
|
||||
endThread();
|
||||
break;
|
||||
}
|
||||
|
||||
mIdleThread = FALSE;
|
||||
|
||||
threadedUpdate();
|
||||
|
|
@ -514,12 +530,18 @@ void LLQueuedThread::run()
|
|||
|
||||
if (pending_work == 0)
|
||||
{
|
||||
//LL_PROFILE_ZONE_NAMED("LLQueuedThread - sleep");
|
||||
mIdleThread = TRUE;
|
||||
ms_sleep(1);
|
||||
//ms_sleep(1);
|
||||
}
|
||||
//LLThread::yield(); // thread should yield after each request
|
||||
}
|
||||
}*/
|
||||
mRequestQueue.runUntilClose();
|
||||
|
||||
endThread();
|
||||
LL_INFOS() << "LLQueuedThread " << mName << " EXITING." << LL_ENDL;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
|
@ -539,10 +561,9 @@ void LLQueuedThread::threadedUpdate()
|
|||
|
||||
//============================================================================
|
||||
|
||||
LLQueuedThread::QueuedRequest::QueuedRequest(LLQueuedThread::handle_t handle, U32 priority, U32 flags) :
|
||||
LLQueuedThread::QueuedRequest::QueuedRequest(LLQueuedThread::handle_t handle, U32 flags) :
|
||||
LLSimpleHashEntry<LLQueuedThread::handle_t>(handle),
|
||||
mStatus(STATUS_UNKNOWN),
|
||||
mPriority(priority),
|
||||
mFlags(flags)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "llthread.h"
|
||||
#include "llsimplehash.h"
|
||||
#include "workqueue.h"
|
||||
|
||||
//============================================================================
|
||||
// Note: ~LLQueuedThread is O(N) N=# of queued threads, assumed to be small
|
||||
|
|
@ -45,15 +46,6 @@ class LL_COMMON_API LLQueuedThread : public LLThread
|
|||
{
|
||||
//------------------------------------------------------------------------
|
||||
public:
|
||||
enum priority_t {
|
||||
PRIORITY_IMMEDIATE = 0x7FFFFFFF,
|
||||
PRIORITY_URGENT = 0x40000000,
|
||||
PRIORITY_HIGH = 0x30000000,
|
||||
PRIORITY_NORMAL = 0x20000000,
|
||||
PRIORITY_LOW = 0x10000000,
|
||||
PRIORITY_LOWBITS = 0x0FFFFFFF,
|
||||
PRIORITY_HIGHBITS = 0x70000000
|
||||
};
|
||||
enum status_t {
|
||||
STATUS_EXPIRED = -1,
|
||||
STATUS_UNKNOWN = 0,
|
||||
|
|
@ -82,27 +74,16 @@ public:
|
|||
virtual ~QueuedRequest(); // use deleteRequest()
|
||||
|
||||
public:
|
||||
QueuedRequest(handle_t handle, U32 priority, U32 flags = 0);
|
||||
QueuedRequest(handle_t handle, U32 flags = 0);
|
||||
|
||||
status_t getStatus()
|
||||
{
|
||||
return mStatus;
|
||||
}
|
||||
U32 getPriority() const
|
||||
{
|
||||
return mPriority;
|
||||
}
|
||||
U32 getFlags() const
|
||||
{
|
||||
return mFlags;
|
||||
}
|
||||
bool higherPriority(const QueuedRequest& second) const
|
||||
{
|
||||
if ( mPriority == second.mPriority)
|
||||
return mHashKey < second.mHashKey;
|
||||
else
|
||||
return mPriority > second.mPriority;
|
||||
}
|
||||
|
||||
protected:
|
||||
status_t setStatus(status_t newstatus)
|
||||
|
|
@ -121,28 +102,11 @@ public:
|
|||
virtual void finishRequest(bool completed); // Always called from thread after request has completed or aborted
|
||||
virtual void deleteRequest(); // Only method to delete a request
|
||||
|
||||
void setPriority(U32 pri)
|
||||
{
|
||||
// Only do this on a request that is not in a queued list!
|
||||
mPriority = pri;
|
||||
};
|
||||
|
||||
protected:
|
||||
LLAtomicBase<status_t> mStatus;
|
||||
U32 mPriority;
|
||||
U32 mFlags;
|
||||
};
|
||||
|
||||
protected:
|
||||
struct queued_request_less
|
||||
{
|
||||
bool operator()(const QueuedRequest* lhs, const QueuedRequest* rhs) const
|
||||
{
|
||||
return lhs->higherPriority(*rhs); // higher priority in front of queue (set)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
|
@ -167,7 +131,7 @@ private:
|
|||
protected:
|
||||
handle_t generateHandle();
|
||||
bool addRequest(QueuedRequest* req);
|
||||
size_t processNextRequest(void);
|
||||
void processRequest(QueuedRequest* req);
|
||||
void incQueue();
|
||||
|
||||
public:
|
||||
|
|
@ -186,7 +150,6 @@ public:
|
|||
status_t getRequestStatus(handle_t handle);
|
||||
void abortRequest(handle_t handle, bool autocomplete);
|
||||
void setFlags(handle_t handle, U32 flags);
|
||||
void setPriority(handle_t handle, U32 priority);
|
||||
bool completeRequest(handle_t handle);
|
||||
// This is public for support classes like LLWorkerThread,
|
||||
// but generally the methods above should be used.
|
||||
|
|
@ -200,8 +163,10 @@ protected:
|
|||
BOOL mStarted; // required when mThreaded is false to call startThread() from update()
|
||||
LLAtomicBool mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
|
||||
|
||||
typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
|
||||
request_queue_t mRequestQueue;
|
||||
//typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
|
||||
//request_queue_t mRequestQueue;
|
||||
LL::WorkQueue mRequestQueue;
|
||||
LL::WorkQueue::weak_t mMainQueue;
|
||||
|
||||
enum { REQUEST_HASH_SIZE = 512 }; // must be power of 2
|
||||
typedef LLSimpleHash<handle_t, REQUEST_HASH_SIZE> request_hash_t;
|
||||
|
|
|
|||
|
|
@ -475,6 +475,7 @@ LLSDNotationParser::~LLSDNotationParser()
|
|||
// virtual
|
||||
S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||
// map: { string:object, string:object }
|
||||
// array: [ object, object, object ]
|
||||
// undef: !
|
||||
|
|
@ -734,6 +735,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) c
|
|||
|
||||
S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||
// map: { string:object, string:object }
|
||||
map = LLSD::emptyMap();
|
||||
S32 parse_count = 0;
|
||||
|
|
@ -794,6 +796,7 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) c
|
|||
|
||||
S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||
// array: [ object, object, object ]
|
||||
array = LLSD::emptyArray();
|
||||
S32 parse_count = 0;
|
||||
|
|
@ -833,6 +836,7 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_dept
|
|||
|
||||
bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||
std::string value;
|
||||
auto count = deserialize_string(istr, value, mMaxBytesLeft);
|
||||
if(PARSE_FAILURE == count) return false;
|
||||
|
|
@ -843,6 +847,7 @@ bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
|
|||
|
||||
bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||
// binary: b##"ff3120ab1"
|
||||
// or: b(len)"..."
|
||||
|
||||
|
|
@ -945,6 +950,7 @@ LLSDBinaryParser::~LLSDBinaryParser()
|
|||
// virtual
|
||||
S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||
/**
|
||||
* Undefined: '!'<br>
|
||||
* Boolean: '1' for true '0' for false<br>
|
||||
|
|
|
|||
|
|
@ -923,6 +923,8 @@ void LLSDXMLParser::parsePart(const char *buf, llssize len)
|
|||
// virtual
|
||||
S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data, S32 max_depth) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||
|
||||
#ifdef XML_PARSER_PERFORMANCE_TESTS
|
||||
XML_Timer timer( &parseTime );
|
||||
#endif // XML_PARSER_PERFORMANCE_TESTS
|
||||
|
|
|
|||
|
|
@ -771,12 +771,10 @@ static U32Kilobytes LLMemoryAdjustKBResult(U32Kilobytes inKB)
|
|||
}
|
||||
#endif
|
||||
|
||||
U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const
|
||||
#if LL_DARWIN
|
||||
// static
|
||||
U32Kilobytes LLMemoryInfo::getHardwareMemSize()
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
return LLMemoryAdjustKBResult(U32Kilobytes(mStatsMap["Total Physical KB"].asInteger()));
|
||||
|
||||
#elif LL_DARWIN
|
||||
// This might work on Linux as well. Someone check...
|
||||
uint64_t phys = 0;
|
||||
int mib[2] = { CTL_HW, HW_MEMSIZE };
|
||||
|
|
@ -785,6 +783,16 @@ U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const
|
|||
sysctl(mib, 2, &phys, &len, NULL, 0);
|
||||
|
||||
return U64Bytes(phys);
|
||||
}
|
||||
#endif
|
||||
|
||||
U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
return LLMemoryAdjustKBResult(U32Kilobytes(mStatsMap["Total Physical KB"].asInteger()));
|
||||
|
||||
#elif LL_DARWIN
|
||||
return getHardwareMemSize();
|
||||
|
||||
#elif LL_LINUX
|
||||
U64 phys = 0;
|
||||
|
|
|
|||
|
|
@ -130,6 +130,9 @@ public:
|
|||
void stream(std::ostream& s) const; ///< output text info to s
|
||||
|
||||
U32Kilobytes getPhysicalMemoryKB() const;
|
||||
#if LL_DARWIN
|
||||
static U32Kilobytes getHardwareMemSize(); // Because some Mac linkers won't let us reference extern gSysMemory from a different lib.
|
||||
#endif
|
||||
|
||||
//get the available memory infomation in KiloBytes.
|
||||
static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
|
||||
const DWORD MS_VC_EXCEPTION=0x406D1388;
|
||||
|
||||
#pragma pack(push,8)
|
||||
|
|
@ -133,6 +134,15 @@ void LLThread::threadRun()
|
|||
{
|
||||
#ifdef LL_WINDOWS
|
||||
set_thread_name(-1, mName.c_str());
|
||||
|
||||
#if 0 // probably a bad idea, see usage of SetThreadIdealProcessor in LLWindowWin32)
|
||||
HANDLE hThread = GetCurrentThread();
|
||||
if (hThread)
|
||||
{
|
||||
SetThreadAffinityMask(hThread, (DWORD_PTR) 0xFFFFFFFFFFFFFFFE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
LL_PROFILER_SET_THREAD_NAME( mName.c_str() );
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
|
||||
#include "u64.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#if LL_WINDOWS
|
||||
# include "llwin32headerslean.h"
|
||||
#elif LL_LINUX || LL_DARWIN
|
||||
|
|
@ -62,9 +65,18 @@ LLTimer* LLTimer::sTimer = NULL;
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
#if LL_WINDOWS
|
||||
|
||||
|
||||
#if 0
|
||||
void ms_sleep(U32 ms)
|
||||
{
|
||||
Sleep(ms);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
using TimePoint = std::chrono::steady_clock::time_point;
|
||||
auto resume_time = TimePoint::clock::now() + std::chrono::milliseconds(ms);
|
||||
while (TimePoint::clock::now() < resume_time)
|
||||
{
|
||||
std::this_thread::yield(); //note: don't use LLThread::yield here to avoid yielding for too long
|
||||
}
|
||||
}
|
||||
|
||||
U32 micro_sleep(U64 us, U32 max_yields)
|
||||
|
|
@ -74,6 +86,35 @@ U32 micro_sleep(U64 us, U32 max_yields)
|
|||
ms_sleep((U32)(us / 1000));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
U32 micro_sleep(U64 us, U32 max_yields)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
#if 0
|
||||
LARGE_INTEGER ft;
|
||||
ft.QuadPart = -static_cast<S64>(us * 10); // '-' using relative time
|
||||
|
||||
HANDLE timer = CreateWaitableTimer(NULL, TRUE, NULL);
|
||||
SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
|
||||
WaitForSingleObject(timer, INFINITE);
|
||||
CloseHandle(timer);
|
||||
#else
|
||||
Sleep(us / 1000);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ms_sleep(U32 ms)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
micro_sleep(ms * 1000, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#elif LL_LINUX || LL_DARWIN
|
||||
static void _sleep_loop(struct timespec& thiswait)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include "linden_common.h"
|
||||
|
||||
// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
|
||||
// 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
|
||||
|
|
@ -51,7 +51,7 @@ const LLUUID LLUUID::null;
|
|||
const LLTransactionID LLTransactionID::tnull;
|
||||
|
||||
// static
|
||||
LLMutex * LLUUID::mMutex = NULL;
|
||||
LLMutex* LLUUID::mMutex = NULL;
|
||||
|
||||
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ U32 janky_fast_random_byes_range(U32 val)
|
|||
*/
|
||||
U32 janky_fast_random_seeded_bytes(U32 seed, U32 val)
|
||||
{
|
||||
seed = U64L(1664525) * (U64)(seed) + U64L(1013904223);
|
||||
seed = U64L(1664525) * (U64)(seed)+U64L(1013904223);
|
||||
return (U32)(seed) % val;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -177,23 +177,23 @@ void LLUUID::toString(std::string& out) const
|
|||
}
|
||||
|
||||
// *TODO: deprecate
|
||||
void LLUUID::toString(char *out) const
|
||||
void LLUUID::toString(char* out) const
|
||||
{
|
||||
std::string buffer;
|
||||
toString(buffer);
|
||||
strcpy(out,buffer.c_str()); /* Flawfinder: ignore */
|
||||
strcpy(out, buffer.c_str()); /* Flawfinder: ignore */
|
||||
}
|
||||
|
||||
void LLUUID::toCompressedString(std::string& out) const
|
||||
{
|
||||
char bytes[UUID_BYTES+1];
|
||||
char bytes[UUID_BYTES + 1];
|
||||
memcpy(bytes, mData, UUID_BYTES); /* Flawfinder: ignore */
|
||||
bytes[UUID_BYTES] = '\0';
|
||||
out.assign(bytes, UUID_BYTES);
|
||||
}
|
||||
|
||||
// *TODO: deprecate
|
||||
void LLUUID::toCompressedString(char *out) const
|
||||
void LLUUID::toCompressedString(char* out) const
|
||||
{
|
||||
memcpy(out, mData, UUID_BYTES); /* Flawfinder: ignore */
|
||||
out[UUID_BYTES] = '\0';
|
||||
|
|
@ -213,7 +213,7 @@ std::string LLUUID::asString() const
|
|||
|
||||
BOOL LLUUID::set(const char* in_string, BOOL emit)
|
||||
{
|
||||
return set(ll_safe_string(in_string),emit);
|
||||
return set(ll_safe_string(in_string), emit);
|
||||
}
|
||||
|
||||
BOOL LLUUID::set(const std::string& in_string, BOOL emit)
|
||||
|
|
@ -233,7 +233,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit)
|
|||
// Shouldn't see any of these any more
|
||||
if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */
|
||||
{
|
||||
if(emit)
|
||||
if (emit)
|
||||
{
|
||||
LL_WARNS() << "Warning! Using broken UUID string format" << LL_ENDL;
|
||||
}
|
||||
|
|
@ -242,7 +242,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit)
|
|||
else
|
||||
{
|
||||
// Bad UUID string. Spam as INFO, as most cases we don't care.
|
||||
if(emit)
|
||||
if (emit)
|
||||
{
|
||||
//don't spam the logs because a resident can't spell.
|
||||
LL_WARNS() << "Bad UUID string: " << in_string << LL_ENDL;
|
||||
|
|
@ -259,7 +259,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit)
|
|||
if ((i == 4) || (i == 6) || (i == 8) || (i == 10))
|
||||
{
|
||||
cur_pos++;
|
||||
if (broken_format && (i==10))
|
||||
if (broken_format && (i == 10))
|
||||
{
|
||||
// Missing - in the broken format
|
||||
cur_pos--;
|
||||
|
|
@ -272,17 +272,17 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit)
|
|||
{
|
||||
mData[i] += (U8)(in_string[cur_pos] - '0');
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <= 'f'))
|
||||
{
|
||||
mData[i] += (U8)(10 + in_string[cur_pos] - 'a');
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <= 'F'))
|
||||
{
|
||||
mData[i] += (U8)(10 + in_string[cur_pos] - 'A');
|
||||
}
|
||||
else
|
||||
{
|
||||
if(emit)
|
||||
if (emit)
|
||||
{
|
||||
LL_WARNS() << "Invalid UUID string character" << LL_ENDL;
|
||||
}
|
||||
|
|
@ -297,17 +297,17 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit)
|
|||
{
|
||||
mData[i] += (U8)(in_string[cur_pos] - '0');
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <= 'f'))
|
||||
{
|
||||
mData[i] += (U8)(10 + in_string[cur_pos] - 'a');
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <= 'F'))
|
||||
{
|
||||
mData[i] += (U8)(10 + in_string[cur_pos] - 'A');
|
||||
}
|
||||
else
|
||||
{
|
||||
if(emit)
|
||||
if (emit)
|
||||
{
|
||||
LL_WARNS() << "Invalid UUID string character" << LL_ENDL;
|
||||
}
|
||||
|
|
@ -342,7 +342,7 @@ BOOL LLUUID::validate(const std::string& in_string)
|
|||
if ((i == 4) || (i == 6) || (i == 8) || (i == 10))
|
||||
{
|
||||
cur_pos++;
|
||||
if (broken_format && (i==10))
|
||||
if (broken_format && (i == 10))
|
||||
{
|
||||
// Missing - in the broken format
|
||||
cur_pos--;
|
||||
|
|
@ -352,10 +352,10 @@ BOOL LLUUID::validate(const std::string& in_string)
|
|||
if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
|
||||
{
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <= 'f'))
|
||||
{
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <= 'F'))
|
||||
{
|
||||
}
|
||||
else
|
||||
|
|
@ -368,10 +368,10 @@ BOOL LLUUID::validate(const std::string& in_string)
|
|||
if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
|
||||
{
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <= 'f'))
|
||||
{
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <= 'F'))
|
||||
{
|
||||
}
|
||||
else
|
||||
|
|
@ -387,7 +387,7 @@ const LLUUID& LLUUID::operator^=(const LLUUID& rhs)
|
|||
{
|
||||
U32* me = (U32*)&(mData[0]);
|
||||
const U32* other = (U32*)&(rhs.mData[0]);
|
||||
for(S32 i = 0; i < 4; ++i)
|
||||
for (S32 i = 0; i < 4; ++i)
|
||||
{
|
||||
me[i] = me[i] ^ other[i];
|
||||
}
|
||||
|
|
@ -413,14 +413,14 @@ void LLUUID::combine(const LLUUID& other, LLUUID& result) const
|
|||
md5_uuid.raw_digest(result.mData);
|
||||
}
|
||||
|
||||
LLUUID LLUUID::combine(const LLUUID &other) const
|
||||
LLUUID LLUUID::combine(const LLUUID& other) const
|
||||
{
|
||||
LLUUID combination;
|
||||
combine(other, combination);
|
||||
return combination;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const LLUUID &uuid)
|
||||
std::ostream& operator<<(std::ostream& s, const LLUUID& uuid)
|
||||
{
|
||||
std::string uuid_str;
|
||||
uuid.toString(uuid_str);
|
||||
|
|
@ -428,11 +428,11 @@ std::ostream& operator<<(std::ostream& s, const LLUUID &uuid)
|
|||
return s;
|
||||
}
|
||||
|
||||
std::istream& operator>>(std::istream &s, LLUUID &uuid)
|
||||
std::istream& operator>>(std::istream& s, LLUUID& uuid)
|
||||
{
|
||||
U32 i;
|
||||
char uuid_str[UUID_STR_LENGTH]; /* Flawfinder: ignore */
|
||||
for (i = 0; i < UUID_STR_LENGTH-1; i++)
|
||||
for (i = 0; i < UUID_STR_LENGTH - 1; i++)
|
||||
{
|
||||
s >> uuid_str[i];
|
||||
}
|
||||
|
|
@ -441,20 +441,20 @@ std::istream& operator>>(std::istream &s, LLUUID &uuid)
|
|||
return s;
|
||||
}
|
||||
|
||||
static void get_random_bytes(void *buf, int nbytes)
|
||||
static void get_random_bytes(void* buf, int nbytes)
|
||||
{
|
||||
int i;
|
||||
char *cp = (char *) buf;
|
||||
char* cp = (char*)buf;
|
||||
|
||||
// *NOTE: If we are not using the janky generator ll_rand()
|
||||
// generates at least 3 good bytes of data since it is 0 to
|
||||
// RAND_MAX. This could be made more efficient by copying all the
|
||||
// bytes.
|
||||
for (i=0; i < nbytes; i++)
|
||||
for (i = 0; i < nbytes; i++)
|
||||
#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
|
||||
*cp++ = janky_fast_random_bytes() & 0xFF;
|
||||
* cp++ = janky_fast_random_bytes() & 0xFF;
|
||||
#else
|
||||
*cp++ = ll_rand() & 0xFF;
|
||||
* cp++ = ll_rand() & 0xFF;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
@ -464,11 +464,11 @@ static void get_random_bytes(void *buf, int nbytes)
|
|||
typedef struct _ASTAT_
|
||||
{
|
||||
ADAPTER_STATUS adapt;
|
||||
NAME_BUFFER NameBuff [30];
|
||||
NAME_BUFFER NameBuff[30];
|
||||
}ASTAT, * PASTAT;
|
||||
|
||||
// static
|
||||
S32 LLUUID::getNodeID(unsigned char *node_id)
|
||||
S32 LLUUID::getNodeID(unsigned char* node_id)
|
||||
{
|
||||
ASTAT Adapter;
|
||||
NCB Ncb;
|
||||
|
|
@ -477,32 +477,32 @@ S32 LLUUID::getNodeID(unsigned char *node_id)
|
|||
int i;
|
||||
int retval = 0;
|
||||
|
||||
memset( &Ncb, 0, sizeof(Ncb) );
|
||||
memset(&Ncb, 0, sizeof(Ncb));
|
||||
Ncb.ncb_command = NCBENUM;
|
||||
Ncb.ncb_buffer = (UCHAR *)&lenum;
|
||||
Ncb.ncb_buffer = (UCHAR*)&lenum;
|
||||
Ncb.ncb_length = sizeof(lenum);
|
||||
uRetCode = Netbios( &Ncb );
|
||||
uRetCode = Netbios(&Ncb);
|
||||
|
||||
for(i=0; i < lenum.length ;i++)
|
||||
for (i = 0; i < lenum.length; i++)
|
||||
{
|
||||
memset( &Ncb, 0, sizeof(Ncb) );
|
||||
memset(&Ncb, 0, sizeof(Ncb));
|
||||
Ncb.ncb_command = NCBRESET;
|
||||
Ncb.ncb_lana_num = lenum.lana[i];
|
||||
|
||||
uRetCode = Netbios( &Ncb );
|
||||
uRetCode = Netbios(&Ncb);
|
||||
|
||||
memset( &Ncb, 0, sizeof (Ncb) );
|
||||
memset(&Ncb, 0, sizeof(Ncb));
|
||||
Ncb.ncb_command = NCBASTAT;
|
||||
Ncb.ncb_lana_num = lenum.lana[i];
|
||||
|
||||
strcpy( (char *)Ncb.ncb_callname, "* " ); /* Flawfinder: ignore */
|
||||
Ncb.ncb_buffer = (unsigned char *)&Adapter;
|
||||
strcpy((char*)Ncb.ncb_callname, "* "); /* Flawfinder: ignore */
|
||||
Ncb.ncb_buffer = (unsigned char*)&Adapter;
|
||||
Ncb.ncb_length = sizeof(Adapter);
|
||||
|
||||
uRetCode = Netbios( &Ncb );
|
||||
if ( uRetCode == 0 )
|
||||
uRetCode = Netbios(&Ncb);
|
||||
if (uRetCode == 0)
|
||||
{
|
||||
memcpy(node_id,Adapter.adapt.adapter_address,6); /* Flawfinder: ignore */
|
||||
memcpy(node_id, Adapter.adapt.adapter_address, 6); /* Flawfinder: ignore */
|
||||
retval = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -525,16 +525,16 @@ S32 LLUUID::getNodeID(unsigned char *node_id)
|
|||
#include <net/route.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
// static
|
||||
S32 LLUUID::getNodeID(unsigned char *node_id)
|
||||
// static
|
||||
S32 LLUUID::getNodeID(unsigned char* node_id)
|
||||
{
|
||||
int i;
|
||||
unsigned char *a = NULL;
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
unsigned char* a = NULL;
|
||||
struct ifaddrs* ifap, * ifa;
|
||||
int rv;
|
||||
S32 result = 0;
|
||||
|
||||
if ((rv=getifaddrs(&ifap))==-1)
|
||||
if ((rv = getifaddrs(&ifap)) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -545,25 +545,25 @@ S32 LLUUID::getNodeID(unsigned char *node_id)
|
|||
|
||||
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
|
||||
{
|
||||
// printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family);
|
||||
for(i=0; i< ifa->ifa_addr->sa_len; i++)
|
||||
// printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family);
|
||||
for (i = 0; i < ifa->ifa_addr->sa_len; i++)
|
||||
{
|
||||
// printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]);
|
||||
// printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]);
|
||||
}
|
||||
// printf("\n");
|
||||
// printf("\n");
|
||||
|
||||
if(ifa->ifa_addr->sa_family == AF_LINK)
|
||||
if (ifa->ifa_addr->sa_family == AF_LINK)
|
||||
{
|
||||
// This is a link-level address
|
||||
struct sockaddr_dl *lla = (struct sockaddr_dl *)ifa->ifa_addr;
|
||||
struct sockaddr_dl* lla = (struct sockaddr_dl*)ifa->ifa_addr;
|
||||
|
||||
// printf("\tLink level address, type %02X\n", lla->sdl_type);
|
||||
// printf("\tLink level address, type %02X\n", lla->sdl_type);
|
||||
|
||||
if(lla->sdl_type == IFT_ETHER)
|
||||
if (lla->sdl_type == IFT_ETHER)
|
||||
{
|
||||
// Use the first ethernet MAC in the list.
|
||||
// For some reason, the macro LLADDR() defined in net/if_dl.h doesn't expand correctly. This is what it would do.
|
||||
a = (unsigned char *)&((lla)->sdl_data);
|
||||
a = (unsigned char*)&((lla)->sdl_data);
|
||||
a += (lla)->sdl_nlen;
|
||||
|
||||
if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
|
||||
|
|
@ -611,17 +611,17 @@ S32 LLUUID::getNodeID(unsigned char *node_id)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
// static
|
||||
S32 LLUUID::getNodeID(unsigned char *node_id)
|
||||
// static
|
||||
S32 LLUUID::getNodeID(unsigned char* node_id)
|
||||
{
|
||||
int sd;
|
||||
struct ifreq ifr, *ifrp;
|
||||
struct ifreq ifr, * ifrp;
|
||||
struct ifconf ifc;
|
||||
char buf[1024];
|
||||
int n, i;
|
||||
unsigned char *a;
|
||||
unsigned char* a;
|
||||
|
||||
/*
|
||||
/*
|
||||
* BSD 4.4 defines the size of an ifreq to be
|
||||
* max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
|
||||
* However, under earlier systems, sa_len isn't present, so the size is
|
||||
|
|
@ -644,23 +644,23 @@ S32 LLUUID::getNodeID(unsigned char *node_id)
|
|||
memset(buf, 0, sizeof(buf));
|
||||
ifc.ifc_len = sizeof(buf);
|
||||
ifc.ifc_buf = buf;
|
||||
if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
|
||||
if (ioctl(sd, SIOCGIFCONF, (char*)&ifc) < 0) {
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
n = ifc.ifc_len;
|
||||
for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
|
||||
ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
|
||||
for (i = 0; i < n; i += ifreq_size(*ifr)) {
|
||||
ifrp = (struct ifreq*)((char*)ifc.ifc_buf + i);
|
||||
strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); /* Flawfinder: ignore */
|
||||
#ifdef SIOCGIFHWADDR
|
||||
if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
|
||||
continue;
|
||||
a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
|
||||
a = (unsigned char*)&ifr.ifr_hwaddr.sa_data;
|
||||
#else
|
||||
#ifdef SIOCGENADDR
|
||||
if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
|
||||
continue;
|
||||
a = (unsigned char *) ifr.ifr_enaddr;
|
||||
a = (unsigned char*)ifr.ifr_enaddr;
|
||||
#else
|
||||
/*
|
||||
* XXX we don't have a way of getting the hardware
|
||||
|
|
@ -684,7 +684,7 @@ S32 LLUUID::getNodeID(unsigned char *node_id)
|
|||
|
||||
#endif
|
||||
|
||||
S32 LLUUID::cmpTime(uuid_time_t *t1, uuid_time_t *t2)
|
||||
S32 LLUUID::cmpTime(uuid_time_t* t1, uuid_time_t* t2)
|
||||
{
|
||||
// Compare two time values.
|
||||
|
||||
|
|
@ -695,20 +695,20 @@ S32 LLUUID::cmpTime(uuid_time_t *t1, uuid_time_t *t2)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void LLUUID::getSystemTime(uuid_time_t *timestamp)
|
||||
void LLUUID::getSystemTime(uuid_time_t* timestamp)
|
||||
{
|
||||
// Get system time with 100ns precision. Time is since Oct 15, 1582.
|
||||
#if LL_WINDOWS
|
||||
ULARGE_INTEGER time;
|
||||
GetSystemTimeAsFileTime((FILETIME *)&time);
|
||||
GetSystemTimeAsFileTime((FILETIME*)&time);
|
||||
// NT keeps time in FILETIME format which is 100ns ticks since
|
||||
// Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
|
||||
// The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
|
||||
// + 18 years and 5 leap days.
|
||||
time.QuadPart +=
|
||||
(unsigned __int64) (1000*1000*10) // seconds
|
||||
* (unsigned __int64) (60 * 60 * 24) // days
|
||||
* (unsigned __int64) (17+30+31+365*18+5); // # of days
|
||||
(unsigned __int64)(1000 * 1000 * 10) // seconds
|
||||
* (unsigned __int64)(60 * 60 * 24) // days
|
||||
* (unsigned __int64)(17 + 30 + 31 + 365 * 18 + 5); // # of days
|
||||
|
||||
timestamp->high = time.HighPart;
|
||||
timestamp->low = time.LowPart;
|
||||
|
|
@ -721,12 +721,12 @@ void LLUUID::getSystemTime(uuid_time_t *timestamp)
|
|||
// Unix base time is January 1, 1970.
|
||||
U64 uuid_time = ((U64)tp.tv_sec * 10000000) + (tp.tv_usec * 10) +
|
||||
U64L(0x01B21DD213814000);
|
||||
timestamp->high = (U32) (uuid_time >> 32);
|
||||
timestamp->low = (U32) (uuid_time & 0xFFFFFFFF);
|
||||
timestamp->high = (U32)(uuid_time >> 32);
|
||||
timestamp->low = (U32)(uuid_time & 0xFFFFFFFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLUUID::getCurrentTime(uuid_time_t *timestamp)
|
||||
void LLUUID::getCurrentTime(uuid_time_t* timestamp)
|
||||
{
|
||||
// Get current time as 60 bit 100ns ticks since whenever.
|
||||
// Compensate for the fact that real clock resolution is less
|
||||
|
|
@ -745,7 +745,7 @@ void LLUUID::getCurrentTime(uuid_time_t *timestamp)
|
|||
mMutex = new LLMutex();
|
||||
}
|
||||
|
||||
uuid_time_t time_now = {0,0};
|
||||
uuid_time_t time_now = { 0,0 };
|
||||
|
||||
while (1) {
|
||||
getSystemTime(&time_now);
|
||||
|
|
@ -770,7 +770,8 @@ void LLUUID::getCurrentTime(uuid_time_t *timestamp)
|
|||
time_now.low += uuids_this_tick;
|
||||
if (!(time_now.low & 0x80000000))
|
||||
time_now.high++;
|
||||
} else
|
||||
}
|
||||
else
|
||||
time_now.low += uuids_this_tick;
|
||||
}
|
||||
|
||||
|
|
@ -787,7 +788,7 @@ void LLUUID::generate()
|
|||
static int has_init = 0;
|
||||
|
||||
// Create a UUID.
|
||||
static uuid_time_t time_last = {0,0};
|
||||
static uuid_time_t time_last = { 0,0 };
|
||||
static U16 clock_seq = 0;
|
||||
#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
|
||||
static U32 seed = 0L; // dummy seed. reset it below
|
||||
|
|
@ -834,32 +835,32 @@ void LLUUID::generate()
|
|||
|
||||
time_last = timestamp;
|
||||
|
||||
memcpy(mData+10, node_id, 6); /* Flawfinder: ignore */
|
||||
memcpy(mData + 10, node_id, 6); /* Flawfinder: ignore */
|
||||
U32 tmp;
|
||||
tmp = timestamp.low;
|
||||
mData[3] = (unsigned char) tmp;
|
||||
mData[3] = (unsigned char)tmp;
|
||||
tmp >>= 8;
|
||||
mData[2] = (unsigned char) tmp;
|
||||
mData[2] = (unsigned char)tmp;
|
||||
tmp >>= 8;
|
||||
mData[1] = (unsigned char) tmp;
|
||||
mData[1] = (unsigned char)tmp;
|
||||
tmp >>= 8;
|
||||
mData[0] = (unsigned char) tmp;
|
||||
mData[0] = (unsigned char)tmp;
|
||||
|
||||
tmp = (U16) timestamp.high;
|
||||
mData[5] = (unsigned char) tmp;
|
||||
tmp = (U16)timestamp.high;
|
||||
mData[5] = (unsigned char)tmp;
|
||||
tmp >>= 8;
|
||||
mData[4] = (unsigned char) tmp;
|
||||
mData[4] = (unsigned char)tmp;
|
||||
|
||||
tmp = (timestamp.high >> 16) | 0x1000;
|
||||
mData[7] = (unsigned char) tmp;
|
||||
mData[7] = (unsigned char)tmp;
|
||||
tmp >>= 8;
|
||||
mData[6] = (unsigned char) tmp;
|
||||
mData[6] = (unsigned char)tmp;
|
||||
|
||||
tmp = our_clock_seq;
|
||||
|
||||
mData[9] = (unsigned char) tmp;
|
||||
mData[9] = (unsigned char)tmp;
|
||||
tmp >>= 8;
|
||||
mData[8] = (unsigned char) tmp;
|
||||
mData[8] = (unsigned char)tmp;
|
||||
|
||||
HBXXH128::digest(*this, (const void*)mData, 16);
|
||||
}
|
||||
|
|
@ -880,9 +881,9 @@ U32 LLUUID::getRandomSeed()
|
|||
// time from generating the same seed.
|
||||
pid_t pid = LLApp::getPid();
|
||||
|
||||
seed[6]=(unsigned char)(pid >> 8);
|
||||
seed[7]=(unsigned char)(pid);
|
||||
getSystemTime((uuid_time_t *)(&seed[8]));
|
||||
seed[6] = (unsigned char)(pid >> 8);
|
||||
seed[7] = (unsigned char)(pid);
|
||||
getSystemTime((uuid_time_t*)(&seed[8]));
|
||||
|
||||
U64 seed64 = HBXXH64::digest((const void*)seed, 16);
|
||||
return U32(seed64) ^ U32(seed64 >> 32);
|
||||
|
|
@ -890,16 +891,16 @@ U32 LLUUID::getRandomSeed()
|
|||
|
||||
BOOL LLUUID::parseUUID(const std::string& buf, LLUUID* value)
|
||||
{
|
||||
if( buf.empty() || value == NULL)
|
||||
if (buf.empty() || value == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
std::string temp( buf );
|
||||
std::string temp(buf);
|
||||
LLStringUtil::trim(temp);
|
||||
if( LLUUID::validate( temp ) )
|
||||
if (LLUUID::validate(temp))
|
||||
{
|
||||
value->set( temp );
|
||||
value->set(temp);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
|
@ -942,9 +943,9 @@ LLUUID::LLUUID()
|
|||
|
||||
|
||||
// Faster than copying from memory
|
||||
void LLUUID::setNull()
|
||||
void LLUUID::setNull()
|
||||
{
|
||||
U32 *word = (U32 *)mData;
|
||||
U32* word = (U32*)mData;
|
||||
word[0] = 0;
|
||||
word[1] = 0;
|
||||
word[2] = 0;
|
||||
|
|
@ -953,10 +954,10 @@ LLUUID::LLUUID()
|
|||
|
||||
|
||||
// Compare
|
||||
bool LLUUID::operator==(const LLUUID& rhs) const
|
||||
bool LLUUID::operator==(const LLUUID& rhs) const
|
||||
{
|
||||
U32 *tmp = (U32 *)mData;
|
||||
U32 *rhstmp = (U32 *)rhs.mData;
|
||||
U32* tmp = (U32*)mData;
|
||||
U32* rhstmp = (U32*)rhs.mData;
|
||||
// Note: binary & to avoid branching
|
||||
return
|
||||
(tmp[0] == rhstmp[0]) &
|
||||
|
|
@ -966,10 +967,10 @@ LLUUID::LLUUID()
|
|||
}
|
||||
|
||||
|
||||
bool LLUUID::operator!=(const LLUUID& rhs) const
|
||||
bool LLUUID::operator!=(const LLUUID& rhs) const
|
||||
{
|
||||
U32 *tmp = (U32 *)mData;
|
||||
U32 *rhstmp = (U32 *)rhs.mData;
|
||||
U32* tmp = (U32*)mData;
|
||||
U32* rhstmp = (U32*)rhs.mData;
|
||||
// Note: binary | to avoid branching
|
||||
return
|
||||
(tmp[0] != rhstmp[0]) |
|
||||
|
|
@ -988,22 +989,22 @@ LLUUID::LLUUID()
|
|||
}
|
||||
*/
|
||||
|
||||
BOOL LLUUID::notNull() const
|
||||
BOOL LLUUID::notNull() const
|
||||
{
|
||||
U32 *word = (U32 *)mData;
|
||||
U32* word = (U32*)mData;
|
||||
return (word[0] | word[1] | word[2] | word[3]) > 0;
|
||||
}
|
||||
|
||||
// Faster than == LLUUID::null because doesn't require
|
||||
// as much memory access.
|
||||
BOOL LLUUID::isNull() const
|
||||
BOOL LLUUID::isNull() const
|
||||
{
|
||||
U32 *word = (U32 *)mData;
|
||||
U32* word = (U32*)mData;
|
||||
// If all bits are zero, return !0 == TRUE
|
||||
return !(word[0] | word[1] | word[2] | word[3]);
|
||||
}
|
||||
|
||||
LLUUID::LLUUID(const char *in_string)
|
||||
LLUUID::LLUUID(const char* in_string)
|
||||
{
|
||||
if (!in_string || in_string[0] == 0)
|
||||
{
|
||||
|
|
@ -1014,7 +1015,7 @@ LLUUID::LLUUID()
|
|||
set(in_string);
|
||||
}
|
||||
|
||||
LLUUID::LLUUID(const std::string& in_string)
|
||||
LLUUID::LLUUID(const std::string& in_string)
|
||||
{
|
||||
if (in_string.empty())
|
||||
{
|
||||
|
|
@ -1027,12 +1028,12 @@ LLUUID::LLUUID()
|
|||
|
||||
// IW: DON'T "optimize" these w/ U32s or you'll scoogie the sort order
|
||||
// IW: this will make me very sad
|
||||
bool LLUUID::operator<(const LLUUID &rhs) const
|
||||
bool LLUUID::operator<(const LLUUID& rhs) const
|
||||
{
|
||||
U32 i;
|
||||
for( i = 0; i < (UUID_BYTES - 1); i++ )
|
||||
for (i = 0; i < (UUID_BYTES - 1); i++)
|
||||
{
|
||||
if( mData[i] != rhs.mData[i] )
|
||||
if (mData[i] != rhs.mData[i])
|
||||
{
|
||||
return (mData[i] < rhs.mData[i]);
|
||||
}
|
||||
|
|
@ -1040,12 +1041,12 @@ LLUUID::LLUUID()
|
|||
return (mData[UUID_BYTES - 1] < rhs.mData[UUID_BYTES - 1]);
|
||||
}
|
||||
|
||||
bool LLUUID::operator>(const LLUUID &rhs) const
|
||||
bool LLUUID::operator>(const LLUUID& rhs) const
|
||||
{
|
||||
U32 i;
|
||||
for( i = 0; i < (UUID_BYTES - 1); i++ )
|
||||
for (i = 0; i < (UUID_BYTES - 1); i++)
|
||||
{
|
||||
if( mData[i] != rhs.mData[i] )
|
||||
if (mData[i] != rhs.mData[i])
|
||||
{
|
||||
return (mData[i] > rhs.mData[i]);
|
||||
}
|
||||
|
|
@ -1053,10 +1054,10 @@ LLUUID::LLUUID()
|
|||
return (mData[UUID_BYTES - 1] > rhs.mData[UUID_BYTES - 1]);
|
||||
}
|
||||
|
||||
U16 LLUUID::getCRC16() const
|
||||
U16 LLUUID::getCRC16() const
|
||||
{
|
||||
// A UUID is 16 bytes, or 8 shorts.
|
||||
U16 *short_data = (U16*)mData;
|
||||
U16* short_data = (U16*)mData;
|
||||
U16 out = 0;
|
||||
out += short_data[0];
|
||||
out += short_data[1];
|
||||
|
|
@ -1069,8 +1070,8 @@ LLUUID::LLUUID()
|
|||
return out;
|
||||
}
|
||||
|
||||
U32 LLUUID::getCRC32() const
|
||||
U32 LLUUID::getCRC32() const
|
||||
{
|
||||
U32 *tmp = (U32*)mData;
|
||||
U32* tmp = (U32*)mData;
|
||||
return tmp[0] + tmp[1] + tmp[2] + tmp[3];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ void LLWorkerThread::clearDeleteList()
|
|||
{
|
||||
worker->mRequestHandle = LLWorkerThread::nullHandle();
|
||||
worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK);
|
||||
worker->clearFlags(LLWorkerClass::WCF_WORKING);
|
||||
delete worker;
|
||||
}
|
||||
mDeleteList.clear() ;
|
||||
|
|
@ -97,6 +98,7 @@ size_t LLWorkerThread::update(F32 max_time_ms)
|
|||
{
|
||||
if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED))
|
||||
{
|
||||
worker->setFlags(LLWorkerClass::WCF_DELETE_REQUESTED);
|
||||
delete_list.push_back(worker);
|
||||
mDeleteList.erase(curiter);
|
||||
}
|
||||
|
|
@ -130,11 +132,11 @@ size_t LLWorkerThread::update(F32 max_time_ms)
|
|||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority)
|
||||
LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass, S32 param)
|
||||
{
|
||||
handle_t handle = generateHandle();
|
||||
|
||||
WorkRequest* req = new WorkRequest(handle, priority, workerclass, param);
|
||||
WorkRequest* req = new WorkRequest(handle, workerclass, param);
|
||||
|
||||
bool res = addRequest(req);
|
||||
if (!res)
|
||||
|
|
@ -157,8 +159,8 @@ void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass)
|
|||
//============================================================================
|
||||
// Runs on its OWN thread
|
||||
|
||||
LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param) :
|
||||
LLQueuedThread::QueuedRequest(handle, priority),
|
||||
LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param) :
|
||||
LLQueuedThread::QueuedRequest(handle),
|
||||
mWorkerClass(workerclass),
|
||||
mParam(param)
|
||||
{
|
||||
|
|
@ -177,6 +179,7 @@ void LLWorkerThread::WorkRequest::deleteRequest()
|
|||
// virtual
|
||||
bool LLWorkerThread::WorkRequest::processRequest()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
LLWorkerClass* workerclass = getWorkerClass();
|
||||
workerclass->setWorking(true);
|
||||
bool complete = workerclass->doWork(getParam());
|
||||
|
|
@ -187,6 +190,7 @@ bool LLWorkerThread::WorkRequest::processRequest()
|
|||
// virtual
|
||||
void LLWorkerThread::WorkRequest::finishRequest(bool completed)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
LLWorkerClass* workerclass = getWorkerClass();
|
||||
workerclass->finishWork(getParam(), completed);
|
||||
U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED);
|
||||
|
|
@ -200,7 +204,6 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na
|
|||
: mWorkerThread(workerthread),
|
||||
mWorkerClassName(name),
|
||||
mRequestHandle(LLWorkerThread::nullHandle()),
|
||||
mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
|
||||
mMutex(),
|
||||
mWorkFlags(0)
|
||||
{
|
||||
|
|
@ -289,7 +292,7 @@ bool LLWorkerClass::yield()
|
|||
//----------------------------------------------------------------------------
|
||||
|
||||
// calls startWork, adds doWork() to queue
|
||||
void LLWorkerClass::addWork(S32 param, U32 priority)
|
||||
void LLWorkerClass::addWork(S32 param)
|
||||
{
|
||||
mMutex.lock();
|
||||
llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK)));
|
||||
|
|
@ -303,7 +306,7 @@ void LLWorkerClass::addWork(S32 param, U32 priority)
|
|||
startWork(param);
|
||||
clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED);
|
||||
setFlags(WCF_HAVE_WORK);
|
||||
mRequestHandle = mWorkerThread->addWorkRequest(this, param, priority);
|
||||
mRequestHandle = mWorkerThread->addWorkRequest(this, param);
|
||||
mMutex.unlock();
|
||||
}
|
||||
|
||||
|
|
@ -318,7 +321,6 @@ void LLWorkerClass::abortWork(bool autocomplete)
|
|||
if (mRequestHandle != LLWorkerThread::nullHandle())
|
||||
{
|
||||
mWorkerThread->abortRequest(mRequestHandle, autocomplete);
|
||||
mWorkerThread->setPriority(mRequestHandle, LLQueuedThread::PRIORITY_IMMEDIATE);
|
||||
setFlags(WCF_ABORT_REQUESTED);
|
||||
}
|
||||
mMutex.unlock();
|
||||
|
|
@ -392,16 +394,5 @@ void LLWorkerClass::scheduleDelete()
|
|||
}
|
||||
}
|
||||
|
||||
void LLWorkerClass::setPriority(U32 priority)
|
||||
{
|
||||
mMutex.lock();
|
||||
if (mRequestHandle != LLWorkerThread::nullHandle() && mRequestPriority != priority)
|
||||
{
|
||||
mRequestPriority = priority;
|
||||
mWorkerThread->setPriority(mRequestHandle, priority);
|
||||
}
|
||||
mMutex.unlock();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public:
|
|||
virtual ~WorkRequest(); // use deleteRequest()
|
||||
|
||||
public:
|
||||
WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param);
|
||||
WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param);
|
||||
|
||||
S32 getParam()
|
||||
{
|
||||
|
|
@ -90,7 +90,7 @@ public:
|
|||
|
||||
/*virtual*/ size_t update(F32 max_time_ms);
|
||||
|
||||
handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL);
|
||||
handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param);
|
||||
|
||||
S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug
|
||||
|
||||
|
|
@ -151,10 +151,6 @@ public:
|
|||
bool isWorking() { return getFlags(WCF_WORKING); }
|
||||
bool wasAborted() { return getFlags(WCF_ABORT_REQUESTED); }
|
||||
|
||||
// setPriority(): changes the priority of a request
|
||||
void setPriority(U32 priority);
|
||||
U32 getPriority() { return mRequestPriority; }
|
||||
|
||||
const std::string& getName() const { return mWorkerClassName; }
|
||||
|
||||
protected:
|
||||
|
|
@ -169,7 +165,7 @@ protected:
|
|||
void setWorkerThread(LLWorkerThread* workerthread);
|
||||
|
||||
// addWork(): calls startWork, adds doWork() to queue
|
||||
void addWork(S32 param, U32 priority = LLWorkerThread::PRIORITY_NORMAL);
|
||||
void addWork(S32 param);
|
||||
|
||||
// abortWork(): requests that work be aborted
|
||||
void abortWork(bool autocomplete);
|
||||
|
|
@ -193,7 +189,6 @@ protected:
|
|||
LLWorkerThread* mWorkerThread;
|
||||
std::string mWorkerClassName;
|
||||
handle_t mRequestHandle;
|
||||
U32 mRequestPriority; // last priority set
|
||||
|
||||
private:
|
||||
LLMutex mMutex;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace tut
|
|||
{
|
||||
struct workqueue_data
|
||||
{
|
||||
WorkQueue queue{"queue"};
|
||||
WorkSchedule queue{"queue"};
|
||||
};
|
||||
typedef test_group<workqueue_data> workqueue_group;
|
||||
typedef workqueue_group::object object;
|
||||
|
|
@ -49,8 +49,8 @@ namespace tut
|
|||
{
|
||||
set_test_name("name");
|
||||
ensure_equals("didn't capture name", queue.getKey(), "queue");
|
||||
ensure("not findable", WorkQueue::getInstance("queue") == queue.getWeak().lock());
|
||||
WorkQueue q2;
|
||||
ensure("not findable", WorkSchedule::getInstance("queue") == queue.getWeak().lock());
|
||||
WorkSchedule q2;
|
||||
ensure("has no name", LLStringUtil::startsWith(q2.getKey(), "WorkQueue"));
|
||||
}
|
||||
|
||||
|
|
@ -73,16 +73,16 @@ namespace tut
|
|||
{
|
||||
set_test_name("postEvery");
|
||||
// record of runs
|
||||
using Shared = std::deque<WorkQueue::TimePoint>;
|
||||
using Shared = std::deque<WorkSchedule::TimePoint>;
|
||||
// This is an example of how to share data between the originator of
|
||||
// postEvery(work) and the work item itself, since usually a WorkQueue
|
||||
// postEvery(work) and the work item itself, since usually a WorkSchedule
|
||||
// is used to dispatch work to a different thread. Neither of them
|
||||
// should call any of LLCond's wait methods: you don't want to stall
|
||||
// either the worker thread or the originating thread (conventionally
|
||||
// main). Use LLCond or a subclass even if all you want to do is
|
||||
// signal the work item that it can quit; consider LLOneShotCond.
|
||||
LLCond<Shared> data;
|
||||
auto start = WorkQueue::TimePoint::clock::now();
|
||||
auto start = WorkSchedule::TimePoint::clock::now();
|
||||
// 2s seems like a long time to wait, since it directly impacts the
|
||||
// duration of this test program. Unfortunately GitHub's Mac runners
|
||||
// are pretty wimpy, and we're getting spurious "too late" errors just
|
||||
|
|
@ -97,7 +97,7 @@ namespace tut
|
|||
data.update_one(
|
||||
[](Shared& data)
|
||||
{
|
||||
data.push_back(WorkQueue::TimePoint::clock::now());
|
||||
data.push_back(WorkSchedule::TimePoint::clock::now());
|
||||
});
|
||||
// by the 3rd call, return false to stop
|
||||
return (++count < 3);
|
||||
|
|
@ -106,7 +106,7 @@ namespace tut
|
|||
// postEvery() running, so run until we have exhausted the iterations
|
||||
// or we time out waiting
|
||||
for (auto finish = start + 10*interval;
|
||||
WorkQueue::TimePoint::clock::now() < finish &&
|
||||
WorkSchedule::TimePoint::clock::now() < finish &&
|
||||
data.get([](const Shared& data){ return data.size(); }) < 3; )
|
||||
{
|
||||
queue.runPending();
|
||||
|
|
@ -143,8 +143,8 @@ namespace tut
|
|||
void object::test<4>()
|
||||
{
|
||||
set_test_name("postTo");
|
||||
WorkQueue main("main");
|
||||
auto qptr = WorkQueue::getInstance("queue");
|
||||
WorkSchedule main("main");
|
||||
auto qptr = WorkSchedule::getInstance("queue");
|
||||
int result = 0;
|
||||
main.postTo(
|
||||
qptr,
|
||||
|
|
@ -175,8 +175,8 @@ namespace tut
|
|||
void object::test<5>()
|
||||
{
|
||||
set_test_name("postTo with void return");
|
||||
WorkQueue main("main");
|
||||
auto qptr = WorkQueue::getInstance("queue");
|
||||
WorkSchedule main("main");
|
||||
auto qptr = WorkSchedule::getInstance("queue");
|
||||
std::string observe;
|
||||
main.postTo(
|
||||
qptr,
|
||||
|
|
@ -198,7 +198,7 @@ namespace tut
|
|||
std::string stored;
|
||||
// Try to call waitForResult() on this thread's main coroutine. It
|
||||
// should throw because the main coroutine must service the queue.
|
||||
auto what{ catch_what<WorkQueue::Error>(
|
||||
auto what{ catch_what<WorkSchedule::Error>(
|
||||
[this, &stored](){ stored = queue.waitForResult(
|
||||
[](){ return "should throw"; }); }) };
|
||||
ensure("lambda should not have run", stored.empty());
|
||||
|
|
|
|||
|
|
@ -17,18 +17,58 @@
|
|||
// std headers
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
#include "commoncontrol.h"
|
||||
#include "llerror.h"
|
||||
#include "llevents.h"
|
||||
#include "llsd.h"
|
||||
#include "stringize.h"
|
||||
|
||||
LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity):
|
||||
#include <boost/fiber/algo/round_robin.hpp>
|
||||
|
||||
/*****************************************************************************
|
||||
* Custom fiber scheduler for worker threads
|
||||
*****************************************************************************/
|
||||
// As of 2022-12-06, each of our worker threads only runs a single (default)
|
||||
// fiber: we don't launch explicit fibers within worker threads, nor do we
|
||||
// anticipate doing so. So a worker thread that's simply waiting for incoming
|
||||
// tasks should really sleep a little. Override the default fiber scheduler to
|
||||
// implement that.
|
||||
struct sleepy_robin: public boost::fibers::algo::round_robin
|
||||
{
|
||||
virtual void suspend_until( std::chrono::steady_clock::time_point const&) noexcept
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
// round_robin holds a std::condition_variable, and
|
||||
// round_robin::suspend_until() calls
|
||||
// std::condition_variable::wait_until(). On Windows, that call seems
|
||||
// busier than it ought to be. Try just sleeping.
|
||||
Sleep(1);
|
||||
#else
|
||||
// currently unused other than windows, but might as well have something here
|
||||
// different units than Sleep(), but we actually just want to sleep for any de-minimis duration
|
||||
usleep(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void notify() noexcept
|
||||
{
|
||||
// Since our Sleep() call above will wake up on its own, we need not
|
||||
// take any special action to wake it.
|
||||
}
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* ThreadPoolBase
|
||||
*****************************************************************************/
|
||||
LL::ThreadPoolBase::ThreadPoolBase(const std::string& name, size_t threads,
|
||||
WorkQueueBase* queue):
|
||||
super(name),
|
||||
mQueue(name, capacity),
|
||||
mName("ThreadPool:" + name),
|
||||
mThreadCount(threads)
|
||||
mThreadCount(getConfiguredWidth(name, threads)),
|
||||
mQueue(queue)
|
||||
{}
|
||||
|
||||
void LL::ThreadPool::start()
|
||||
void LL::ThreadPoolBase::start()
|
||||
{
|
||||
for (size_t i = 0; i < mThreadCount; ++i)
|
||||
{
|
||||
|
|
@ -56,17 +96,17 @@ void LL::ThreadPool::start()
|
|||
});
|
||||
}
|
||||
|
||||
LL::ThreadPool::~ThreadPool()
|
||||
LL::ThreadPoolBase::~ThreadPoolBase()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void LL::ThreadPool::close()
|
||||
void LL::ThreadPoolBase::close()
|
||||
{
|
||||
if (! mQueue.isClosed())
|
||||
if (! mQueue->isClosed())
|
||||
{
|
||||
LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL;
|
||||
mQueue.close();
|
||||
mQueue->close();
|
||||
for (auto& pair: mThreads)
|
||||
{
|
||||
LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
|
||||
|
|
@ -76,14 +116,74 @@ void LL::ThreadPool::close()
|
|||
}
|
||||
}
|
||||
|
||||
void LL::ThreadPool::run(const std::string& name)
|
||||
void LL::ThreadPoolBase::run(const std::string& name)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
// Try using sleepy_robin fiber scheduler.
|
||||
boost::fibers::use_scheduling_algorithm<sleepy_robin>();
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL;
|
||||
run();
|
||||
LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL;
|
||||
}
|
||||
|
||||
void LL::ThreadPool::run()
|
||||
void LL::ThreadPoolBase::run()
|
||||
{
|
||||
mQueue.runUntilClose();
|
||||
mQueue->runUntilClose();
|
||||
}
|
||||
|
||||
//static
|
||||
size_t LL::ThreadPoolBase::getConfiguredWidth(const std::string& name, size_t dft)
|
||||
{
|
||||
LLSD poolSizes;
|
||||
try
|
||||
{
|
||||
poolSizes = LL::CommonControl::get("Global", "ThreadPoolSizes");
|
||||
// "ThreadPoolSizes" is actually a map containing the sizes of
|
||||
// interest -- or should be, if this process has an
|
||||
// LLViewerControlListener instance and its settings include
|
||||
// "ThreadPoolSizes". If we failed to retrieve it, perhaps we're in a
|
||||
// program that doesn't define that, or perhaps there's no such
|
||||
// setting, or perhaps we're asking too early, before the LLEventAPI
|
||||
// itself has been instantiated. In any of those cases, it seems worth
|
||||
// warning.
|
||||
if (! poolSizes.isDefined())
|
||||
{
|
||||
// Note: we don't warn about absence of an override key for a
|
||||
// particular ThreadPool name, that's fine. This warning is about
|
||||
// complete absence of a ThreadPoolSizes setting, which we expect
|
||||
// in a normal viewer session.
|
||||
LL_WARNS("ThreadPool") << "No 'ThreadPoolSizes' setting for ThreadPool '"
|
||||
<< name << "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
catch (const LL::CommonControl::Error& exc)
|
||||
{
|
||||
// We don't want ThreadPool to *require* LLViewerControlListener.
|
||||
// Just log it and carry on.
|
||||
LL_WARNS("ThreadPool") << "Can't check 'ThreadPoolSizes': " << exc.what() << LL_ENDL;
|
||||
}
|
||||
|
||||
LL_DEBUGS("ThreadPool") << "ThreadPoolSizes = " << poolSizes << LL_ENDL;
|
||||
// LLSD treats an undefined value as an empty map when asked to retrieve a
|
||||
// key, so we don't need this to be conditional.
|
||||
LLSD sizeSpec{ poolSizes[name] };
|
||||
// We retrieve sizeSpec as LLSD, rather than immediately as LLSD::Integer,
|
||||
// so we can distinguish the case when it's undefined.
|
||||
return sizeSpec.isInteger() ? sizeSpec.asInteger() : dft;
|
||||
}
|
||||
|
||||
//static
|
||||
size_t LL::ThreadPoolBase::getWidth(const std::string& name, size_t dft)
|
||||
{
|
||||
auto instance{ getInstance(name) };
|
||||
if (instance)
|
||||
{
|
||||
return instance->getWidth();
|
||||
}
|
||||
else
|
||||
{
|
||||
return getConfiguredWidth(name, dft);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
#if ! defined(LL_THREADPOOL_H)
|
||||
#define LL_THREADPOOL_H
|
||||
|
||||
#include "threadpool_fwd.h"
|
||||
#include "workqueue.h"
|
||||
#include <memory> // std::unique_ptr
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility> // std::pair
|
||||
|
|
@ -22,17 +24,24 @@
|
|||
namespace LL
|
||||
{
|
||||
|
||||
class ThreadPool: public LLInstanceTracker<ThreadPool, std::string>
|
||||
class ThreadPoolBase: public LLInstanceTracker<ThreadPoolBase, std::string>
|
||||
{
|
||||
private:
|
||||
using super = LLInstanceTracker<ThreadPool, std::string>;
|
||||
using super = LLInstanceTracker<ThreadPoolBase, std::string>;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Pass ThreadPool a string name. This can be used to look up the
|
||||
* Pass ThreadPoolBase a string name. This can be used to look up the
|
||||
* relevant WorkQueue.
|
||||
*
|
||||
* The number of threads you pass sets the compile-time default. But
|
||||
* if the user has overridden the LLSD map in the "ThreadPoolSizes"
|
||||
* setting with a key matching this ThreadPool name, that setting
|
||||
* overrides this parameter.
|
||||
*/
|
||||
ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024);
|
||||
virtual ~ThreadPool();
|
||||
ThreadPoolBase(const std::string& name, size_t threads,
|
||||
WorkQueueBase* queue);
|
||||
virtual ~ThreadPoolBase();
|
||||
|
||||
/**
|
||||
* Launch the ThreadPool. Until this call, a constructed ThreadPool
|
||||
|
|
@ -50,8 +59,6 @@ namespace LL
|
|||
|
||||
std::string getName() const { return mName; }
|
||||
size_t getWidth() const { return mThreads.size(); }
|
||||
/// obtain a non-const reference to the WorkQueue to post work to it
|
||||
WorkQueue& getQueue() { return mQueue; }
|
||||
|
||||
/**
|
||||
* Override run() if you need special processing. The default run()
|
||||
|
|
@ -59,15 +66,72 @@ namespace LL
|
|||
*/
|
||||
virtual void run();
|
||||
|
||||
/**
|
||||
* getConfiguredWidth() returns the setting, if any, for the specified
|
||||
* ThreadPool name. Returns dft if the "ThreadPoolSizes" map does not
|
||||
* contain the specified name.
|
||||
*/
|
||||
static
|
||||
size_t getConfiguredWidth(const std::string& name, size_t dft=0);
|
||||
|
||||
/**
|
||||
* This getWidth() returns the width of the instantiated ThreadPool
|
||||
* with the specified name, if any. If no instance exists, returns its
|
||||
* getConfiguredWidth() if any. If there's no instance and no relevant
|
||||
* override, return dft. Presumably dft should match the threads
|
||||
* parameter passed to the ThreadPool constructor call that will
|
||||
* eventually instantiate the ThreadPool with that name.
|
||||
*/
|
||||
static
|
||||
size_t getWidth(const std::string& name, size_t dft);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<WorkQueueBase> mQueue;
|
||||
|
||||
private:
|
||||
void run(const std::string& name);
|
||||
|
||||
WorkQueue mQueue;
|
||||
std::string mName;
|
||||
size_t mThreadCount;
|
||||
std::vector<std::pair<std::string, std::thread>> mThreads;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialize with WorkQueue or, for timestamped tasks, WorkSchedule
|
||||
*/
|
||||
template <class QUEUE>
|
||||
struct ThreadPoolUsing: public ThreadPoolBase
|
||||
{
|
||||
using queue_t = QUEUE;
|
||||
|
||||
/**
|
||||
* Pass ThreadPoolUsing a string name. This can be used to look up the
|
||||
* relevant WorkQueue.
|
||||
*
|
||||
* The number of threads you pass sets the compile-time default. But
|
||||
* if the user has overridden the LLSD map in the "ThreadPoolSizes"
|
||||
* setting with a key matching this ThreadPool name, that setting
|
||||
* overrides this parameter.
|
||||
*
|
||||
* Pass an explicit capacity to limit the size of the queue.
|
||||
* Constraining the queue can cause a submitter to block. Do not
|
||||
* constrain any ThreadPool accepting work from the main thread.
|
||||
*/
|
||||
ThreadPoolUsing(const std::string& name, size_t threads=1, size_t capacity=1024*1024):
|
||||
ThreadPoolBase(name, threads, new queue_t(name, capacity))
|
||||
{}
|
||||
~ThreadPoolUsing() override {}
|
||||
|
||||
/**
|
||||
* obtain a non-const reference to the specific WorkQueue subclass to
|
||||
* post work to it
|
||||
*/
|
||||
queue_t& getQueue() { return static_cast<queue_t&>(*mQueue); }
|
||||
};
|
||||
|
||||
/// ThreadPool is shorthand for using the simpler WorkQueue
|
||||
using ThreadPool = ThreadPoolUsing<WorkQueue>;
|
||||
|
||||
} // namespace LL
|
||||
|
||||
#endif /* ! defined(LL_THREADPOOL_H) */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @file threadpool_fwd.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2022-12-09
|
||||
* @brief Forward declarations for ThreadPool et al.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Copyright (c) 2022, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_THREADPOOL_FWD_H)
|
||||
#define LL_THREADPOOL_FWD_H
|
||||
|
||||
#include "workqueue.h"
|
||||
|
||||
namespace LL
|
||||
{
|
||||
template <class QUEUE>
|
||||
struct ThreadPoolUsing;
|
||||
|
||||
using ThreadPool = ThreadPoolUsing<WorkQueue>;
|
||||
} // namespace LL
|
||||
|
||||
#endif /* ! defined(LL_THREADPOOL_FWD_H) */
|
||||
|
|
@ -26,14 +26,121 @@
|
|||
using Mutex = LLCoros::Mutex;
|
||||
using Lock = LLCoros::LockType;
|
||||
|
||||
LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity):
|
||||
super(makeName(name)),
|
||||
mQueue(capacity)
|
||||
/*****************************************************************************
|
||||
* WorkQueueBase
|
||||
*****************************************************************************/
|
||||
LL::WorkQueueBase::WorkQueueBase(const std::string& name):
|
||||
super(makeName(name))
|
||||
{
|
||||
// TODO: register for "LLApp" events so we can implicitly close() on
|
||||
// viewer shutdown.
|
||||
}
|
||||
|
||||
void LL::WorkQueueBase::runUntilClose()
|
||||
{
|
||||
try
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
callWork(pop_());
|
||||
}
|
||||
}
|
||||
catch (const Closed&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
bool LL::WorkQueueBase::runPending()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
for (Work work; tryPop_(work); )
|
||||
{
|
||||
callWork(work);
|
||||
}
|
||||
return ! done();
|
||||
}
|
||||
|
||||
bool LL::WorkQueueBase::runOne()
|
||||
{
|
||||
Work work;
|
||||
if (tryPop_(work))
|
||||
{
|
||||
callWork(work);
|
||||
}
|
||||
return ! done();
|
||||
}
|
||||
|
||||
bool LL::WorkQueueBase::runUntil(const TimePoint& until)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
// Should we subtract some slop to allow for typical Work execution time?
|
||||
// How much slop?
|
||||
// runUntil() is simply a time-bounded runPending().
|
||||
for (Work work; TimePoint::clock::now() < until && tryPop_(work); )
|
||||
{
|
||||
callWork(work);
|
||||
}
|
||||
return ! done();
|
||||
}
|
||||
|
||||
std::string LL::WorkQueueBase::makeName(const std::string& name)
|
||||
{
|
||||
if (! name.empty())
|
||||
return name;
|
||||
|
||||
static U32 discriminator = 0;
|
||||
static Mutex mutex;
|
||||
U32 num;
|
||||
{
|
||||
// Protect discriminator from concurrent access by different threads.
|
||||
// It can't be thread_local, else two racing threads will come up with
|
||||
// the same name.
|
||||
Lock lk(mutex);
|
||||
num = discriminator++;
|
||||
}
|
||||
return STRINGIZE("WorkQueue" << num);
|
||||
}
|
||||
|
||||
void LL::WorkQueueBase::callWork(const Work& work)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
try
|
||||
{
|
||||
work();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// No matter what goes wrong with any individual work item, the worker
|
||||
// thread must go on! Log our own instance name with the exception.
|
||||
LOG_UNHANDLED_EXCEPTION(getKey());
|
||||
}
|
||||
}
|
||||
|
||||
void LL::WorkQueueBase::error(const std::string& msg)
|
||||
{
|
||||
LL_ERRS("WorkQueue") << msg << LL_ENDL;
|
||||
}
|
||||
|
||||
void LL::WorkQueueBase::checkCoroutine(const std::string& method)
|
||||
{
|
||||
// By convention, the default coroutine on each thread has an empty name
|
||||
// string. See also LLCoros::logname().
|
||||
if (LLCoros::getName().empty())
|
||||
{
|
||||
LLTHROW(Error("Do not call " + method + " from a thread's default coroutine"));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* WorkQueue
|
||||
*****************************************************************************/
|
||||
LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity):
|
||||
super(name),
|
||||
mQueue(capacity)
|
||||
{
|
||||
}
|
||||
|
||||
void LL::WorkQueue::close()
|
||||
{
|
||||
mQueue.close();
|
||||
|
|
@ -54,105 +161,85 @@ bool LL::WorkQueue::done()
|
|||
return mQueue.done();
|
||||
}
|
||||
|
||||
void LL::WorkQueue::runUntilClose()
|
||||
bool LL::WorkQueue::post(const Work& callable)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
callWork(mQueue.pop());
|
||||
}
|
||||
}
|
||||
catch (const Queue::Closed&)
|
||||
{
|
||||
}
|
||||
return mQueue.pushIfOpen(callable);
|
||||
}
|
||||
|
||||
bool LL::WorkQueue::runPending()
|
||||
bool LL::WorkQueue::tryPost(const Work& callable)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
for (Work work; mQueue.tryPop(work); )
|
||||
{
|
||||
callWork(work);
|
||||
}
|
||||
return ! mQueue.done();
|
||||
return mQueue.tryPush(callable);
|
||||
}
|
||||
|
||||
bool LL::WorkQueue::runOne()
|
||||
LL::WorkQueue::Work LL::WorkQueue::pop_()
|
||||
{
|
||||
Work work;
|
||||
if (mQueue.tryPop(work))
|
||||
{
|
||||
callWork(work);
|
||||
}
|
||||
return ! mQueue.done();
|
||||
return mQueue.pop();
|
||||
}
|
||||
|
||||
bool LL::WorkQueue::runUntil(const TimePoint& until)
|
||||
bool LL::WorkQueue::tryPop_(Work& work)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
// Should we subtract some slop to allow for typical Work execution time?
|
||||
// How much slop?
|
||||
// runUntil() is simply a time-bounded runPending().
|
||||
for (Work work; TimePoint::clock::now() < until && mQueue.tryPop(work); )
|
||||
{
|
||||
callWork(work);
|
||||
}
|
||||
return ! mQueue.done();
|
||||
return mQueue.tryPop(work);
|
||||
}
|
||||
|
||||
std::string LL::WorkQueue::makeName(const std::string& name)
|
||||
/*****************************************************************************
|
||||
* WorkSchedule
|
||||
*****************************************************************************/
|
||||
LL::WorkSchedule::WorkSchedule(const std::string& name, size_t capacity):
|
||||
super(name),
|
||||
mQueue(capacity)
|
||||
{
|
||||
if (! name.empty())
|
||||
return name;
|
||||
|
||||
static U32 discriminator = 0;
|
||||
static Mutex mutex;
|
||||
U32 num;
|
||||
{
|
||||
// Protect discriminator from concurrent access by different threads.
|
||||
// It can't be thread_local, else two racing threads will come up with
|
||||
// the same name.
|
||||
Lock lk(mutex);
|
||||
num = discriminator++;
|
||||
}
|
||||
return STRINGIZE("WorkQueue" << num);
|
||||
}
|
||||
|
||||
void LL::WorkQueue::callWork(const Queue::DataTuple& work)
|
||||
void LL::WorkSchedule::close()
|
||||
{
|
||||
// ThreadSafeSchedule::pop() always delivers a tuple, even when
|
||||
// there's only one data field per item, as for us.
|
||||
callWork(std::get<0>(work));
|
||||
mQueue.close();
|
||||
}
|
||||
|
||||
void LL::WorkQueue::callWork(const Work& work)
|
||||
size_t LL::WorkSchedule::size()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
try
|
||||
{
|
||||
work();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// No matter what goes wrong with any individual work item, the worker
|
||||
// thread must go on! Log our own instance name with the exception.
|
||||
LOG_UNHANDLED_EXCEPTION(getKey());
|
||||
}
|
||||
return mQueue.size();
|
||||
}
|
||||
|
||||
void LL::WorkQueue::error(const std::string& msg)
|
||||
bool LL::WorkSchedule::isClosed()
|
||||
{
|
||||
LL_ERRS("WorkQueue") << msg << LL_ENDL;
|
||||
return mQueue.isClosed();
|
||||
}
|
||||
|
||||
void LL::WorkQueue::checkCoroutine(const std::string& method)
|
||||
bool LL::WorkSchedule::done()
|
||||
{
|
||||
// By convention, the default coroutine on each thread has an empty name
|
||||
// string. See also LLCoros::logname().
|
||||
if (LLCoros::getName().empty())
|
||||
{
|
||||
LLTHROW(Error("Do not call " + method + " from a thread's default coroutine"));
|
||||
}
|
||||
return mQueue.done();
|
||||
}
|
||||
|
||||
bool LL::WorkSchedule::post(const Work& callable)
|
||||
{
|
||||
// Use TimePoint::clock::now() instead of TimePoint's representation of
|
||||
// the epoch because this WorkSchedule may contain a mix of past-due
|
||||
// TimedWork items and TimedWork items scheduled for the future. Sift this
|
||||
// new item into the correct place.
|
||||
return post(callable, TimePoint::clock::now());
|
||||
}
|
||||
|
||||
bool LL::WorkSchedule::post(const Work& callable, const TimePoint& time)
|
||||
{
|
||||
return mQueue.pushIfOpen(TimedWork(time, callable));
|
||||
}
|
||||
|
||||
bool LL::WorkSchedule::tryPost(const Work& callable)
|
||||
{
|
||||
return tryPost(callable, TimePoint::clock::now());
|
||||
}
|
||||
|
||||
bool LL::WorkSchedule::tryPost(const Work& callable, const TimePoint& time)
|
||||
{
|
||||
return mQueue.tryPush(TimedWork(time, callable));
|
||||
}
|
||||
|
||||
LL::WorkSchedule::Work LL::WorkSchedule::pop_()
|
||||
{
|
||||
return std::get<0>(mQueue.pop());
|
||||
}
|
||||
|
||||
bool LL::WorkSchedule::tryPop_(Work& work)
|
||||
{
|
||||
return mQueue.tryPop(work);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "llcoros.h"
|
||||
#include "llexception.h"
|
||||
#include "llinstancetracker.h"
|
||||
#include "llinstancetrackersubclass.h"
|
||||
#include "threadsafeschedule.h"
|
||||
#include <chrono>
|
||||
#include <exception> // std::current_exception
|
||||
|
|
@ -23,27 +24,23 @@
|
|||
|
||||
namespace LL
|
||||
{
|
||||
|
||||
/*****************************************************************************
|
||||
* WorkQueueBase: API for WorkQueue and WorkSchedule
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* A typical WorkQueue has a string name that can be used to find it.
|
||||
*/
|
||||
class WorkQueue: public LLInstanceTracker<WorkQueue, std::string>
|
||||
class WorkQueueBase: public LLInstanceTracker<WorkQueueBase, std::string>
|
||||
{
|
||||
private:
|
||||
using super = LLInstanceTracker<WorkQueue, std::string>;
|
||||
using super = LLInstanceTracker<WorkQueueBase, std::string>;
|
||||
|
||||
public:
|
||||
using Work = std::function<void()>;
|
||||
|
||||
private:
|
||||
using Queue = ThreadSafeSchedule<Work>;
|
||||
// helper for postEvery()
|
||||
template <typename Rep, typename Period, typename CALLABLE>
|
||||
class BackJack;
|
||||
|
||||
public:
|
||||
using TimePoint = Queue::TimePoint;
|
||||
using TimedWork = Queue::TimeTuple;
|
||||
using Closed = Queue::Closed;
|
||||
using Closed = LLThreadSafeQueueInterrupt;
|
||||
// for runFor()
|
||||
using TimePoint = std::chrono::steady_clock::time_point;
|
||||
|
||||
struct Error: public LLException
|
||||
{
|
||||
|
|
@ -51,18 +48,18 @@ namespace LL
|
|||
};
|
||||
|
||||
/**
|
||||
* You may omit the WorkQueue name, in which case a unique name is
|
||||
* You may omit the WorkQueueBase name, in which case a unique name is
|
||||
* synthesized; for practical purposes that makes it anonymous.
|
||||
*/
|
||||
WorkQueue(const std::string& name = std::string(), size_t capacity=1024);
|
||||
WorkQueueBase(const std::string& name);
|
||||
|
||||
/**
|
||||
* Since the point of WorkQueue is to pass work to some other worker
|
||||
* thread(s) asynchronously, it's important that the WorkQueue continue
|
||||
* to exist until the worker thread(s) have drained it. To communicate
|
||||
* that it's time for them to quit, close() the queue.
|
||||
* thread(s) asynchronously, it's important that it continue to exist
|
||||
* until the worker thread(s) have drained it. To communicate that
|
||||
* it's time for them to quit, close() the queue.
|
||||
*/
|
||||
void close();
|
||||
virtual void close() = 0;
|
||||
|
||||
/**
|
||||
* WorkQueue supports multiple producers and multiple consumers. In
|
||||
|
|
@ -78,152 +75,57 @@ namespace LL
|
|||
* * If you're the only consumer, noticing that size() > 0 is
|
||||
* meaningful.
|
||||
*/
|
||||
size_t size();
|
||||
virtual size_t size() = 0;
|
||||
/// producer end: are we prevented from pushing any additional items?
|
||||
bool isClosed();
|
||||
virtual bool isClosed() = 0;
|
||||
/// consumer end: are we done, is the queue entirely drained?
|
||||
bool done();
|
||||
virtual bool done() = 0;
|
||||
|
||||
/*---------------------- fire and forget API -----------------------*/
|
||||
|
||||
/// fire-and-forget, but at a particular (future?) time
|
||||
template <typename CALLABLE>
|
||||
void post(const TimePoint& time, CALLABLE&& callable)
|
||||
{
|
||||
// Defer reifying an arbitrary CALLABLE until we hit this or
|
||||
// postIfOpen(). All other methods should accept CALLABLEs of
|
||||
// arbitrary type to avoid multiple levels of std::function
|
||||
// indirection.
|
||||
mQueue.push(TimedWork(time, std::move(callable)));
|
||||
}
|
||||
|
||||
/// fire-and-forget
|
||||
template <typename CALLABLE>
|
||||
void post(CALLABLE&& callable)
|
||||
{
|
||||
// We use TimePoint::clock::now() instead of TimePoint's
|
||||
// representation of the epoch because this WorkQueue may contain
|
||||
// a mix of past-due TimedWork items and TimedWork items scheduled
|
||||
// for the future. Sift this new item into the correct place.
|
||||
post(TimePoint::clock::now(), std::move(callable));
|
||||
}
|
||||
|
||||
/**
|
||||
* post work for a particular time, unless the queue is closed before
|
||||
* we can post
|
||||
*/
|
||||
template <typename CALLABLE>
|
||||
bool postIfOpen(const TimePoint& time, CALLABLE&& callable)
|
||||
{
|
||||
// Defer reifying an arbitrary CALLABLE until we hit this or
|
||||
// post(). All other methods should accept CALLABLEs of arbitrary
|
||||
// type to avoid multiple levels of std::function indirection.
|
||||
return mQueue.pushIfOpen(TimedWork(time, std::move(callable)));
|
||||
}
|
||||
|
||||
/**
|
||||
* post work, unless the queue is closed before we can post
|
||||
*/
|
||||
template <typename CALLABLE>
|
||||
bool postIfOpen(CALLABLE&& callable)
|
||||
{
|
||||
return postIfOpen(TimePoint::clock::now(), std::move(callable));
|
||||
}
|
||||
virtual bool post(const Work&) = 0;
|
||||
|
||||
/**
|
||||
* Post work to be run at a specified time to another WorkQueue, which
|
||||
* may or may not still exist and be open. Return true if we were able
|
||||
* to post.
|
||||
* post work, unless the queue is full
|
||||
*/
|
||||
template <typename CALLABLE>
|
||||
static bool postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable);
|
||||
virtual bool tryPost(const Work&) = 0;
|
||||
|
||||
/**
|
||||
* Post work to another WorkQueue, which may or may not still exist
|
||||
* and be open. Return true if we were able to post.
|
||||
* and be open. Support any post() overload. Return true if we were
|
||||
* able to post.
|
||||
*/
|
||||
template <typename CALLABLE>
|
||||
static bool postMaybe(weak_t target, CALLABLE&& callable)
|
||||
{
|
||||
return postMaybe(target, TimePoint::clock::now(),
|
||||
std::forward<CALLABLE>(callable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch a callable returning bool that will trigger repeatedly at
|
||||
* specified interval, until the callable returns false.
|
||||
*
|
||||
* If you need to signal that callable from outside, DO NOT bind a
|
||||
* reference to a simple bool! That's not thread-safe. Instead, bind
|
||||
* an LLCond variant, e.g. LLOneShotCond or LLBoolCond.
|
||||
*/
|
||||
template <typename Rep, typename Period, typename CALLABLE>
|
||||
void postEvery(const std::chrono::duration<Rep, Period>& interval,
|
||||
CALLABLE&& callable);
|
||||
|
||||
template <typename CALLABLE>
|
||||
bool tryPost(CALLABLE&& callable)
|
||||
{
|
||||
return mQueue.tryPush(TimedWork(TimePoint::clock::now(), std::move(callable)));
|
||||
}
|
||||
template <typename... ARGS>
|
||||
static bool postMaybe(weak_t target, ARGS&&... args);
|
||||
|
||||
/*------------------------- handshake API --------------------------*/
|
||||
|
||||
/**
|
||||
* Post work to another WorkQueue to be run at a specified time,
|
||||
* requesting a specific callback to be run on this WorkQueue on
|
||||
* completion.
|
||||
*
|
||||
* Returns true if able to post, false if the other WorkQueue is
|
||||
* inaccessible.
|
||||
*/
|
||||
// Apparently some Microsoft header file defines a macro CALLBACK? The
|
||||
// natural template argument name CALLBACK produces very weird Visual
|
||||
// Studio compile errors that seem utterly unrelated to this source
|
||||
// code.
|
||||
template <typename CALLABLE, typename FOLLOWUP>
|
||||
bool postTo(weak_t target,
|
||||
const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback);
|
||||
|
||||
/**
|
||||
* Post work to another WorkQueue, requesting a specific callback to
|
||||
* be run on this WorkQueue on completion.
|
||||
* be run on this WorkQueue on completion. Optional final argument is
|
||||
* TimePoint for WorkSchedule.
|
||||
*
|
||||
* Returns true if able to post, false if the other WorkQueue is
|
||||
* inaccessible.
|
||||
*/
|
||||
template <typename CALLABLE, typename FOLLOWUP>
|
||||
bool postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback)
|
||||
{
|
||||
return postTo(target, TimePoint::clock::now(),
|
||||
std::move(callable), std::move(callback));
|
||||
}
|
||||
|
||||
/**
|
||||
* Post work to another WorkQueue to be run at a specified time,
|
||||
* blocking the calling coroutine until then, returning the result to
|
||||
* caller on completion.
|
||||
*
|
||||
* In general, we assume that each thread's default coroutine is busy
|
||||
* servicing its WorkQueue or whatever. To try to prevent mistakes, we
|
||||
* forbid calling waitForResult() from a thread's default coroutine.
|
||||
*/
|
||||
template <typename CALLABLE>
|
||||
auto waitForResult(const TimePoint& time, CALLABLE&& callable);
|
||||
template <typename CALLABLE, typename FOLLOWUP, typename... ARGS>
|
||||
bool postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback,
|
||||
ARGS&&... args);
|
||||
|
||||
/**
|
||||
* Post work to another WorkQueue, blocking the calling coroutine
|
||||
* until then, returning the result to caller on completion.
|
||||
* until then, returning the result to caller on completion. Optional
|
||||
* final argument is TimePoint for WorkSchedule.
|
||||
*
|
||||
* In general, we assume that each thread's default coroutine is busy
|
||||
* servicing its WorkQueue or whatever. To try to prevent mistakes, we
|
||||
* forbid calling waitForResult() from a thread's default coroutine.
|
||||
*/
|
||||
template <typename CALLABLE>
|
||||
auto waitForResult(CALLABLE&& callable)
|
||||
{
|
||||
return waitForResult(TimePoint::clock::now(), std::move(callable));
|
||||
}
|
||||
template <typename CALLABLE, typename... ARGS>
|
||||
auto waitForResult(CALLABLE&& callable, ARGS&&... args);
|
||||
|
||||
/*--------------------------- worker API ---------------------------*/
|
||||
|
||||
|
|
@ -270,7 +172,7 @@ namespace LL
|
|||
*/
|
||||
bool runUntil(const TimePoint& until);
|
||||
|
||||
private:
|
||||
protected:
|
||||
template <typename CALLABLE, typename FOLLOWUP>
|
||||
static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback);
|
||||
/// general case: arbitrary C++ return type
|
||||
|
|
@ -290,13 +192,170 @@ namespace LL
|
|||
static void checkCoroutine(const std::string& method);
|
||||
static void error(const std::string& msg);
|
||||
static std::string makeName(const std::string& name);
|
||||
void callWork(const Queue::DataTuple& work);
|
||||
void callWork(const Work& work);
|
||||
|
||||
private:
|
||||
virtual Work pop_() = 0;
|
||||
virtual bool tryPop_(Work&) = 0;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* WorkQueue: no timestamped task support
|
||||
*****************************************************************************/
|
||||
class WorkQueue: public LLInstanceTrackerSubclass<WorkQueue, WorkQueueBase>
|
||||
{
|
||||
private:
|
||||
using super = LLInstanceTrackerSubclass<WorkQueue, WorkQueueBase>;
|
||||
|
||||
public:
|
||||
/**
|
||||
* You may omit the WorkQueue name, in which case a unique name is
|
||||
* synthesized; for practical purposes that makes it anonymous.
|
||||
*/
|
||||
WorkQueue(const std::string& name = std::string(), size_t capacity=1024);
|
||||
|
||||
/**
|
||||
* Since the point of WorkQueue is to pass work to some other worker
|
||||
* thread(s) asynchronously, it's important that it continue to exist
|
||||
* until the worker thread(s) have drained it. To communicate that
|
||||
* it's time for them to quit, close() the queue.
|
||||
*/
|
||||
void close() override;
|
||||
|
||||
/**
|
||||
* WorkQueue supports multiple producers and multiple consumers. In
|
||||
* the general case it's misleading to test size(), since any other
|
||||
* thread might change it the nanosecond the lock is released. On that
|
||||
* basis, some might argue against publishing a size() method at all.
|
||||
*
|
||||
* But there are two specific cases in which a test based on size()
|
||||
* might be reasonable:
|
||||
*
|
||||
* * If you're the only producer, noticing that size() == 0 is
|
||||
* meaningful.
|
||||
* * If you're the only consumer, noticing that size() > 0 is
|
||||
* meaningful.
|
||||
*/
|
||||
size_t size() override;
|
||||
/// producer end: are we prevented from pushing any additional items?
|
||||
bool isClosed() override;
|
||||
/// consumer end: are we done, is the queue entirely drained?
|
||||
bool done() override;
|
||||
|
||||
/*---------------------- fire and forget API -----------------------*/
|
||||
|
||||
/**
|
||||
* post work, unless the queue is closed before we can post
|
||||
*/
|
||||
bool post(const Work&) override;
|
||||
|
||||
/**
|
||||
* post work, unless the queue is full
|
||||
*/
|
||||
bool tryPost(const Work&) override;
|
||||
|
||||
private:
|
||||
using Queue = LLThreadSafeQueue<Work>;
|
||||
Queue mQueue;
|
||||
|
||||
Work pop_() override;
|
||||
bool tryPop_(Work&) override;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* WorkSchedule: add support for timestamped tasks
|
||||
*****************************************************************************/
|
||||
class WorkSchedule: public LLInstanceTrackerSubclass<WorkSchedule, WorkQueueBase>
|
||||
{
|
||||
private:
|
||||
using super = LLInstanceTrackerSubclass<WorkSchedule, WorkQueueBase>;
|
||||
using Queue = ThreadSafeSchedule<Work>;
|
||||
// helper for postEvery()
|
||||
template <typename Rep, typename Period, typename CALLABLE>
|
||||
class BackJack;
|
||||
|
||||
public:
|
||||
using TimePoint = Queue::TimePoint;
|
||||
using TimedWork = Queue::TimeTuple;
|
||||
|
||||
/**
|
||||
* You may omit the WorkSchedule name, in which case a unique name is
|
||||
* synthesized; for practical purposes that makes it anonymous.
|
||||
*/
|
||||
WorkSchedule(const std::string& name = std::string(), size_t capacity=1024);
|
||||
|
||||
/**
|
||||
* Since the point of WorkSchedule is to pass work to some other worker
|
||||
* thread(s) asynchronously, it's important that the WorkSchedule continue
|
||||
* to exist until the worker thread(s) have drained it. To communicate
|
||||
* that it's time for them to quit, close() the queue.
|
||||
*/
|
||||
void close() override;
|
||||
|
||||
/**
|
||||
* WorkSchedule supports multiple producers and multiple consumers. In
|
||||
* the general case it's misleading to test size(), since any other
|
||||
* thread might change it the nanosecond the lock is released. On that
|
||||
* basis, some might argue against publishing a size() method at all.
|
||||
*
|
||||
* But there are two specific cases in which a test based on size()
|
||||
* might be reasonable:
|
||||
*
|
||||
* * If you're the only producer, noticing that size() == 0 is
|
||||
* meaningful.
|
||||
* * If you're the only consumer, noticing that size() > 0 is
|
||||
* meaningful.
|
||||
*/
|
||||
size_t size() override;
|
||||
/// producer end: are we prevented from pushing any additional items?
|
||||
bool isClosed() override;
|
||||
/// consumer end: are we done, is the queue entirely drained?
|
||||
bool done() override;
|
||||
|
||||
/*---------------------- fire and forget API -----------------------*/
|
||||
|
||||
/**
|
||||
* post work, unless the queue is closed before we can post
|
||||
*/
|
||||
bool post(const Work& callable) override;
|
||||
|
||||
/**
|
||||
* post work for a particular time, unless the queue is closed before
|
||||
* we can post
|
||||
*/
|
||||
bool post(const Work& callable, const TimePoint& time);
|
||||
|
||||
/**
|
||||
* post work, unless the queue is full
|
||||
*/
|
||||
bool tryPost(const Work& callable) override;
|
||||
|
||||
/**
|
||||
* post work for a particular time, unless the queue is full
|
||||
*/
|
||||
bool tryPost(const Work& callable, const TimePoint& time);
|
||||
|
||||
/**
|
||||
* Launch a callable returning bool that will trigger repeatedly at
|
||||
* specified interval, until the callable returns false.
|
||||
*
|
||||
* If you need to signal that callable from outside, DO NOT bind a
|
||||
* reference to a simple bool! That's not thread-safe. Instead, bind
|
||||
* an LLCond variant, e.g. LLOneShotCond or LLBoolCond.
|
||||
*/
|
||||
template <typename Rep, typename Period, typename CALLABLE>
|
||||
bool postEvery(const std::chrono::duration<Rep, Period>& interval,
|
||||
CALLABLE&& callable);
|
||||
|
||||
private:
|
||||
Queue mQueue;
|
||||
|
||||
Work pop_() override;
|
||||
bool tryPop_(Work&) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* BackJack is, in effect, a hand-rolled lambda, binding a WorkQueue, a
|
||||
* BackJack is, in effect, a hand-rolled lambda, binding a WorkSchedule, a
|
||||
* CALLABLE that returns bool, a TimePoint and an interval at which to
|
||||
* relaunch it. As long as the callable continues returning true, BackJack
|
||||
* keeps resubmitting it to the target WorkQueue.
|
||||
|
|
@ -305,7 +364,7 @@ namespace LL
|
|||
// class method gets its own 'this' pointer -- which we need to resubmit
|
||||
// the whole BackJack callable.
|
||||
template <typename Rep, typename Period, typename CALLABLE>
|
||||
class WorkQueue::BackJack
|
||||
class WorkSchedule::BackJack
|
||||
{
|
||||
public:
|
||||
// bind the desired data
|
||||
|
|
@ -319,9 +378,10 @@ namespace LL
|
|||
mCallable(std::move(callable))
|
||||
{}
|
||||
|
||||
// Call by target WorkQueue -- note that although WE require a
|
||||
// callable returning bool, WorkQueue wants a void callable. We
|
||||
// consume the bool.
|
||||
// This operator() method, called by target WorkSchedule, is what
|
||||
// makes this object a Work item. Although WE require a callable
|
||||
// returning bool, WorkSchedule wants a void callable. We consume the
|
||||
// bool.
|
||||
void operator()()
|
||||
{
|
||||
// If mCallable() throws an exception, don't catch it here: if it
|
||||
|
|
@ -337,7 +397,7 @@ namespace LL
|
|||
// register our intent to fire at exact mIntervals.
|
||||
mStart += mInterval;
|
||||
|
||||
// We're being called at this moment by the target WorkQueue.
|
||||
// We're being called at this moment by the target WorkSchedule.
|
||||
// Assume it still exists, rather than checking the result of
|
||||
// lock().
|
||||
// Resubmit the whole *this callable: that's why we're a class
|
||||
|
|
@ -345,14 +405,10 @@ namespace LL
|
|||
// move-only callable; but naturally this statement must be
|
||||
// the last time we reference this instance, which may become
|
||||
// moved-from.
|
||||
try
|
||||
{
|
||||
mTarget.lock()->post(mStart, std::move(*this));
|
||||
}
|
||||
catch (const Closed&)
|
||||
{
|
||||
// Once this queue is closed, oh well, just stop
|
||||
}
|
||||
auto target{ std::dynamic_pointer_cast<WorkSchedule>(mTarget.lock()) };
|
||||
// Discard bool return: once this queue is closed, oh well,
|
||||
// just stop
|
||||
target->post(std::move(*this), mStart);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +420,7 @@ namespace LL
|
|||
};
|
||||
|
||||
template <typename Rep, typename Period, typename CALLABLE>
|
||||
void WorkQueue::postEvery(const std::chrono::duration<Rep, Period>& interval,
|
||||
bool WorkSchedule::postEvery(const std::chrono::duration<Rep, Period>& interval,
|
||||
CALLABLE&& callable)
|
||||
{
|
||||
if (interval.count() <= 0)
|
||||
|
|
@ -381,14 +437,14 @@ namespace LL
|
|||
// Instantiate and post a suitable BackJack, binding a weak_ptr to
|
||||
// self, the current time, the desired interval and the desired
|
||||
// callable.
|
||||
post(
|
||||
return post(
|
||||
BackJack<Rep, Period, CALLABLE>(
|
||||
getWeak(), TimePoint::clock::now(), interval, std::move(callable)));
|
||||
}
|
||||
|
||||
/// general case: arbitrary C++ return type
|
||||
template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
|
||||
struct WorkQueue::MakeReplyLambda
|
||||
struct WorkQueueBase::MakeReplyLambda
|
||||
{
|
||||
auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
|
||||
{
|
||||
|
|
@ -409,7 +465,7 @@ namespace LL
|
|||
|
||||
/// specialize for CALLABLE returning void
|
||||
template <typename CALLABLE, typename FOLLOWUP>
|
||||
struct WorkQueue::MakeReplyLambda<CALLABLE, FOLLOWUP, void>
|
||||
struct WorkQueueBase::MakeReplyLambda<CALLABLE, FOLLOWUP, void>
|
||||
{
|
||||
auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
|
||||
{
|
||||
|
|
@ -421,16 +477,16 @@ namespace LL
|
|||
};
|
||||
|
||||
template <typename CALLABLE, typename FOLLOWUP>
|
||||
auto WorkQueue::makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback)
|
||||
auto WorkQueueBase::makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback)
|
||||
{
|
||||
return MakeReplyLambda<CALLABLE, FOLLOWUP,
|
||||
decltype(std::forward<CALLABLE>(callable)())>()
|
||||
(std::move(callable), std::move(callback));
|
||||
}
|
||||
|
||||
template <typename CALLABLE, typename FOLLOWUP>
|
||||
bool WorkQueue::postTo(weak_t target,
|
||||
const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback)
|
||||
template <typename CALLABLE, typename FOLLOWUP, typename... ARGS>
|
||||
bool WorkQueueBase::postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback,
|
||||
ARGS&&... args)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
// We're being asked to post to the WorkQueue at target.
|
||||
|
|
@ -443,13 +499,12 @@ namespace LL
|
|||
// Here we believe target WorkQueue still exists. Post to it a
|
||||
// lambda that packages our callable, our callback and a weak_ptr
|
||||
// to this originating WorkQueue.
|
||||
tptr->post(
|
||||
time,
|
||||
return tptr->post(
|
||||
[reply = super::getWeak(),
|
||||
callable = std::move(callable),
|
||||
callback = std::move(callback)]
|
||||
()
|
||||
mutable {
|
||||
() mutable
|
||||
{
|
||||
// Use postMaybe() below in case this originating WorkQueue
|
||||
// has been closed or destroyed. Remember, the outer lambda is
|
||||
// now running on a thread servicing the target WorkQueue, and
|
||||
|
|
@ -472,44 +527,34 @@ namespace LL
|
|||
// originating WorkQueue. Once there, rethrow it.
|
||||
[exc = std::current_exception()](){ std::rethrow_exception(exc); });
|
||||
}
|
||||
});
|
||||
|
||||
// looks like we were able to post()
|
||||
return true;
|
||||
},
|
||||
// if caller passed a TimePoint, pass it along to post()
|
||||
std::forward<ARGS>(args)...);
|
||||
}
|
||||
|
||||
template <typename CALLABLE>
|
||||
bool WorkQueue::postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable)
|
||||
template <typename... ARGS>
|
||||
bool WorkQueueBase::postMaybe(weak_t target, ARGS&&... args)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
// target is a weak_ptr: have to lock it to check it
|
||||
auto tptr = target.lock();
|
||||
if (tptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
tptr->post(time, std::forward<CALLABLE>(callable));
|
||||
// we were able to post()
|
||||
return true;
|
||||
return tptr->post(std::forward<ARGS>(args)...);
|
||||
}
|
||||
catch (const Closed&)
|
||||
{
|
||||
// target WorkQueue still exists, but is Closed
|
||||
}
|
||||
}
|
||||
// either target no longer exists, or its WorkQueue is Closed
|
||||
// target no longer exists
|
||||
return false;
|
||||
}
|
||||
|
||||
/// general case: arbitrary C++ return type
|
||||
template <typename CALLABLE, typename RETURNTYPE>
|
||||
struct WorkQueue::WaitForResult
|
||||
struct WorkQueueBase::WaitForResult
|
||||
{
|
||||
auto operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable)
|
||||
template <typename... ARGS>
|
||||
auto operator()(WorkQueueBase* self, CALLABLE&& callable, ARGS&&... args)
|
||||
{
|
||||
LLCoros::Promise<RETURNTYPE> promise;
|
||||
self->post(
|
||||
time,
|
||||
bool posted = self->post(
|
||||
// We dare to bind a reference to Promise because it's
|
||||
// specifically designed for cross-thread communication.
|
||||
[&promise, callable = std::move(callable)]()
|
||||
|
|
@ -523,7 +568,13 @@ namespace LL
|
|||
{
|
||||
promise.set_exception(std::current_exception());
|
||||
}
|
||||
});
|
||||
},
|
||||
// if caller passed a TimePoint, pass it to post()
|
||||
std::forward<ARGS>(args)...);
|
||||
if (! posted)
|
||||
{
|
||||
LLTHROW(WorkQueueBase::Closed());
|
||||
}
|
||||
auto future{ LLCoros::getFuture(promise) };
|
||||
// now, on the calling thread, wait for that result
|
||||
LLCoros::TempStatus st("waiting for WorkQueue::waitForResult()");
|
||||
|
|
@ -533,13 +584,13 @@ namespace LL
|
|||
|
||||
/// specialize for CALLABLE returning void
|
||||
template <typename CALLABLE>
|
||||
struct WorkQueue::WaitForResult<CALLABLE, void>
|
||||
struct WorkQueueBase::WaitForResult<CALLABLE, void>
|
||||
{
|
||||
void operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable)
|
||||
template <typename... ARGS>
|
||||
void operator()(WorkQueueBase* self, CALLABLE&& callable, ARGS&&... args)
|
||||
{
|
||||
LLCoros::Promise<void> promise;
|
||||
self->post(
|
||||
time,
|
||||
bool posted = self->post(
|
||||
// &promise is designed for cross-thread access
|
||||
[&promise, callable = std::move(callable)]()
|
||||
mutable {
|
||||
|
|
@ -552,7 +603,13 @@ namespace LL
|
|||
{
|
||||
promise.set_exception(std::current_exception());
|
||||
}
|
||||
});
|
||||
},
|
||||
// if caller passed a TimePoint, pass it to post()
|
||||
std::forward<ARGS>(args)...);
|
||||
if (! posted)
|
||||
{
|
||||
LLTHROW(WorkQueueBase::Closed());
|
||||
}
|
||||
auto future{ LLCoros::getFuture(promise) };
|
||||
// block until set_value()
|
||||
LLCoros::TempStatus st("waiting for void WorkQueue::waitForResult()");
|
||||
|
|
@ -560,13 +617,13 @@ namespace LL
|
|||
}
|
||||
};
|
||||
|
||||
template <typename CALLABLE>
|
||||
auto WorkQueue::waitForResult(const TimePoint& time, CALLABLE&& callable)
|
||||
template <typename CALLABLE, typename... ARGS>
|
||||
auto WorkQueueBase::waitForResult(CALLABLE&& callable, ARGS&&... args)
|
||||
{
|
||||
checkCoroutine("waitForResult()");
|
||||
// derive callable's return type so we can specialize for void
|
||||
return WaitForResult<CALLABLE, decltype(std::forward<CALLABLE>(callable)())>()
|
||||
(this, time, std::forward<CALLABLE>(callable));
|
||||
(this, std::forward<CALLABLE>(callable), std::forward<ARGS>(args)...);
|
||||
}
|
||||
|
||||
} // namespace LL
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ void HttpLibcurl::shutdown()
|
|||
|
||||
void HttpLibcurl::start(int policy_count)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
llassert_always(policy_count <= HTTP_POLICY_CLASS_LIMIT);
|
||||
llassert_always(! mMultiHandles); // One-time call only
|
||||
|
||||
|
|
@ -143,6 +144,7 @@ void HttpLibcurl::start(int policy_count)
|
|||
// sleep otherwise ask for a normal polling interval.
|
||||
HttpService::ELoopSpeed HttpLibcurl::processTransport()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpService::ELoopSpeed ret(HttpService::REQUEST_SLEEP);
|
||||
|
||||
// Give libcurl some cycles to do I/O & callbacks
|
||||
|
|
@ -168,6 +170,7 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport()
|
|||
CURLMcode status(CURLM_CALL_MULTI_PERFORM);
|
||||
do
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("httppt - curl_multi_perform");
|
||||
running = 0;
|
||||
status = curl_multi_perform(mMultiHandles[policy_class], &running);
|
||||
}
|
||||
|
|
@ -176,11 +179,13 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport()
|
|||
// Run completion on anything done
|
||||
CURLMsg * msg(NULL);
|
||||
int msgs_in_queue(0);
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("httppt - curl_multi_info_read");
|
||||
while ((msg = curl_multi_info_read(mMultiHandles[policy_class], &msgs_in_queue)))
|
||||
{
|
||||
if (CURLMSG_DONE == msg->msg)
|
||||
{
|
||||
CURL * handle(msg->easy_handle);
|
||||
CURL* handle(msg->easy_handle);
|
||||
CURLcode result(msg->data.result);
|
||||
|
||||
completeRequest(mMultiHandles[policy_class], handle, result);
|
||||
|
|
@ -202,6 +207,7 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport()
|
|||
msgs_in_queue = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! mActiveOps.empty())
|
||||
{
|
||||
|
|
@ -214,6 +220,7 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport()
|
|||
// Caller has provided us with a ref count on op.
|
||||
void HttpLibcurl::addOp(const HttpOpRequest::ptr_t &op)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
llassert_always(op->mReqPolicy < mPolicyCount);
|
||||
llassert_always(mMultiHandles[op->mReqPolicy] != NULL);
|
||||
|
||||
|
|
@ -257,6 +264,7 @@ void HttpLibcurl::addOp(const HttpOpRequest::ptr_t &op)
|
|||
// method to kill the request.
|
||||
bool HttpLibcurl::cancel(HttpHandle handle)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpOpRequest::ptr_t op = HttpOpRequest::fromHandle<HttpOpRequest>(handle);
|
||||
active_set_t::iterator it(mActiveOps.find(op));
|
||||
if (mActiveOps.end() == it)
|
||||
|
|
@ -282,6 +290,7 @@ bool HttpLibcurl::cancel(HttpHandle handle)
|
|||
// op to the reply queue with refcount intact.
|
||||
void HttpLibcurl::cancelRequest(const HttpOpRequest::ptr_t &op)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
// Deactivate request
|
||||
op->mCurlActive = false;
|
||||
|
||||
|
|
@ -308,6 +317,7 @@ void HttpLibcurl::cancelRequest(const HttpOpRequest::ptr_t &op)
|
|||
// Keep them synchronized as necessary.
|
||||
bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpHandle ophandle(NULL);
|
||||
|
||||
CURLcode ccode(CURLE_OK);
|
||||
|
|
@ -445,6 +455,7 @@ int HttpLibcurl::getActiveCountInClass(int policy_class) const
|
|||
|
||||
void HttpLibcurl::policyUpdated(int policy_class)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
if (policy_class < 0 || policy_class >= mPolicyCount || ! mMultiHandles)
|
||||
{
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ HttpOperation::HttpOperation():
|
|||
mReplyQueue(),
|
||||
mUserHandler(),
|
||||
mReqPolicy(HttpRequest::DEFAULT_POLICY_ID),
|
||||
mReqPriority(0U),
|
||||
mTracing(HTTP_TRACE_OFF),
|
||||
mMyHandle(LLCORE_HTTP_HANDLE_INVALID)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -181,7 +181,6 @@ protected:
|
|||
public:
|
||||
// Request Data
|
||||
HttpRequest::policy_t mReqPolicy;
|
||||
HttpRequest::priority_t mReqPriority;
|
||||
|
||||
// Reply Data
|
||||
HttpStatus mStatus;
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ HttpOpRequest::~HttpOpRequest()
|
|||
|
||||
void HttpOpRequest::stageFromRequest(HttpService * service)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast<HttpOpRequest>(shared_from_this()));
|
||||
service->getPolicy().addOp(self); // transfers refcount
|
||||
}
|
||||
|
|
@ -207,6 +208,7 @@ void HttpOpRequest::stageFromRequest(HttpService * service)
|
|||
|
||||
void HttpOpRequest::stageFromReady(HttpService * service)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast<HttpOpRequest>(shared_from_this()));
|
||||
service->getTransport().addOp(self); // transfers refcount
|
||||
}
|
||||
|
|
@ -214,6 +216,7 @@ void HttpOpRequest::stageFromReady(HttpService * service)
|
|||
|
||||
void HttpOpRequest::stageFromActive(HttpService * service)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
if (mReplyLength)
|
||||
{
|
||||
// If non-zero, we received and processed a Content-Range
|
||||
|
|
@ -250,6 +253,7 @@ void HttpOpRequest::stageFromActive(HttpService * service)
|
|||
|
||||
void HttpOpRequest::visitNotifier(HttpRequest * request)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
if (mUserHandler)
|
||||
{
|
||||
HttpResponse * response = new HttpResponse();
|
||||
|
|
@ -292,6 +296,7 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
|
|||
|
||||
HttpStatus HttpOpRequest::cancel()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
mStatus = HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED);
|
||||
|
||||
addAsReply();
|
||||
|
|
@ -301,12 +306,12 @@ HttpStatus HttpOpRequest::cancel()
|
|||
|
||||
|
||||
HttpStatus HttpOpRequest::setupGet(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers)
|
||||
{
|
||||
setupCommon(policy_id, priority, url, NULL, options, headers);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
setupCommon(policy_id, url, NULL, options, headers);
|
||||
mReqMethod = HOR_GET;
|
||||
|
||||
return HttpStatus();
|
||||
|
|
@ -314,14 +319,14 @@ HttpStatus HttpOpRequest::setupGet(HttpRequest::policy_t policy_id,
|
|||
|
||||
|
||||
HttpStatus HttpOpRequest::setupGetByteRange(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
size_t offset,
|
||||
size_t len,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers)
|
||||
{
|
||||
setupCommon(policy_id, priority, url, NULL, options, headers);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
setupCommon(policy_id, url, NULL, options, headers);
|
||||
mReqMethod = HOR_GET;
|
||||
mReqOffset = offset;
|
||||
mReqLength = len;
|
||||
|
|
@ -335,13 +340,13 @@ HttpStatus HttpOpRequest::setupGetByteRange(HttpRequest::policy_t policy_id,
|
|||
|
||||
|
||||
HttpStatus HttpOpRequest::setupPost(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers)
|
||||
{
|
||||
setupCommon(policy_id, priority, url, body, options, headers);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
setupCommon(policy_id, url, body, options, headers);
|
||||
mReqMethod = HOR_POST;
|
||||
|
||||
return HttpStatus();
|
||||
|
|
@ -349,13 +354,13 @@ HttpStatus HttpOpRequest::setupPost(HttpRequest::policy_t policy_id,
|
|||
|
||||
|
||||
HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers)
|
||||
{
|
||||
setupCommon(policy_id, priority, url, body, options, headers);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
setupCommon(policy_id, url, body, options, headers);
|
||||
mReqMethod = HOR_PUT;
|
||||
|
||||
return HttpStatus();
|
||||
|
|
@ -363,12 +368,12 @@ HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,
|
|||
|
||||
|
||||
HttpStatus HttpOpRequest::setupDelete(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers)
|
||||
{
|
||||
setupCommon(policy_id, priority, url, NULL, options, headers);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
setupCommon(policy_id, url, NULL, options, headers);
|
||||
mReqMethod = HOR_DELETE;
|
||||
|
||||
return HttpStatus();
|
||||
|
|
@ -376,13 +381,13 @@ HttpStatus HttpOpRequest::setupDelete(HttpRequest::policy_t policy_id,
|
|||
|
||||
|
||||
HttpStatus HttpOpRequest::setupPatch(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers)
|
||||
{
|
||||
setupCommon(policy_id, priority, url, body, options, headers);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
setupCommon(policy_id, url, body, options, headers);
|
||||
mReqMethod = HOR_PATCH;
|
||||
|
||||
return HttpStatus();
|
||||
|
|
@ -390,12 +395,12 @@ HttpStatus HttpOpRequest::setupPatch(HttpRequest::policy_t policy_id,
|
|||
|
||||
|
||||
HttpStatus HttpOpRequest::setupCopy(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t &headers)
|
||||
{
|
||||
setupCommon(policy_id, priority, url, NULL, options, headers);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
setupCommon(policy_id, url, NULL, options, headers);
|
||||
mReqMethod = HOR_COPY;
|
||||
|
||||
return HttpStatus();
|
||||
|
|
@ -403,12 +408,12 @@ HttpStatus HttpOpRequest::setupCopy(HttpRequest::policy_t policy_id,
|
|||
|
||||
|
||||
HttpStatus HttpOpRequest::setupMove(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t &headers)
|
||||
{
|
||||
setupCommon(policy_id, priority, url, NULL, options, headers);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
setupCommon(policy_id, url, NULL, options, headers);
|
||||
mReqMethod = HOR_MOVE;
|
||||
|
||||
return HttpStatus();
|
||||
|
|
@ -416,15 +421,14 @@ HttpStatus HttpOpRequest::setupMove(HttpRequest::policy_t policy_id,
|
|||
|
||||
|
||||
void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
mProcFlags = 0U;
|
||||
mReqPolicy = policy_id;
|
||||
mReqPriority = priority;
|
||||
mReqURL = url;
|
||||
if (body)
|
||||
{
|
||||
|
|
@ -465,6 +469,7 @@ void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
|
|||
// *TODO: Move this to _httplibcurl where it belongs.
|
||||
HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
// Scrub transport and result data for retried op case
|
||||
mCurlActive = false;
|
||||
mCurlHandle = NULL;
|
||||
|
|
@ -773,6 +778,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
|
|||
|
||||
size_t HttpOpRequest::writeCallback(void * data, size_t size, size_t nmemb, void * userdata)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
||||
|
||||
if (! op->mReplyBody)
|
||||
|
|
@ -788,6 +794,7 @@ size_t HttpOpRequest::writeCallback(void * data, size_t size, size_t nmemb, void
|
|||
|
||||
size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void * userdata)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
||||
|
||||
if (! op->mReqBody)
|
||||
|
|
@ -819,6 +826,7 @@ size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void
|
|||
|
||||
int HttpOpRequest::seekCallback(void *userdata, curl_off_t offset, int origin)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
||||
|
||||
if (!op->mReqBody)
|
||||
|
|
@ -850,6 +858,7 @@ int HttpOpRequest::seekCallback(void *userdata, curl_off_t offset, int origin)
|
|||
|
||||
size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, void * userdata)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
static const char status_line[] = "HTTP/";
|
||||
static const size_t status_line_len = sizeof(status_line) - 1;
|
||||
static const char con_ran_line[] = "content-range";
|
||||
|
|
@ -999,6 +1008,7 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
|
|||
|
||||
CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userdata)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
||||
|
||||
if (op->mCallbackSSLVerify)
|
||||
|
|
@ -1025,6 +1035,7 @@ CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userd
|
|||
|
||||
int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(param));
|
||||
|
||||
if (op->mCallbackSSLVerify)
|
||||
|
|
@ -1037,6 +1048,7 @@ int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
|
|||
|
||||
int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffer, size_t len, void * userdata)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
||||
|
||||
std::string safe_line;
|
||||
|
|
|
|||
|
|
@ -105,13 +105,11 @@ public:
|
|||
/// Threading: called by application thread
|
||||
///
|
||||
HttpStatus setupGet(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers);
|
||||
|
||||
HttpStatus setupGetByteRange(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
size_t offset,
|
||||
size_t len,
|
||||
|
|
@ -119,40 +117,34 @@ public:
|
|||
const HttpHeaders::ptr_t & headers);
|
||||
|
||||
HttpStatus setupPost(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers);
|
||||
|
||||
HttpStatus setupPut(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers);
|
||||
|
||||
HttpStatus setupDelete(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers);
|
||||
|
||||
HttpStatus setupPatch(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers);
|
||||
|
||||
HttpStatus setupCopy(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers);
|
||||
|
||||
HttpStatus setupMove(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers);
|
||||
|
|
@ -172,7 +164,6 @@ protected:
|
|||
// Threading: called by application thread
|
||||
//
|
||||
void setupCommon(HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
|
|
@ -239,19 +230,6 @@ public:
|
|||
|
||||
|
||||
|
||||
/// HttpOpRequestCompare isn't an operation but a uniform comparison
|
||||
/// functor for STL containers that order by priority. Mainly
|
||||
/// used for the ready queue container but defined here.
|
||||
class HttpOpRequestCompare
|
||||
{
|
||||
public:
|
||||
bool operator()(const HttpOpRequest * lhs, const HttpOpRequest * rhs)
|
||||
{
|
||||
return lhs->mReqPriority > rhs->mReqPriority;
|
||||
}
|
||||
}; // end class HttpOpRequestCompare
|
||||
|
||||
|
||||
// ---------------------------------------
|
||||
// Free functions
|
||||
// ---------------------------------------
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if 0 // DEPRECATED
|
||||
#include "_httpopsetpriority.h"
|
||||
|
||||
#include "httpresponse.h"
|
||||
|
|
@ -61,3 +62,5 @@ void HttpOpSetPriority::stageFromRequest(HttpService * service)
|
|||
|
||||
|
||||
} // end namespace LLCore
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#ifndef _LLCORE_HTTP_SETPRIORITY_H_
|
||||
#define _LLCORE_HTTP_SETPRIORITY_H_
|
||||
|
||||
|
||||
#if 0 // DEPRECATED
|
||||
#include "httpcommon.h"
|
||||
#include "httprequest.h"
|
||||
#include "_httpoperation.h"
|
||||
|
|
@ -49,7 +49,7 @@ namespace LLCore
|
|||
class HttpOpSetPriority : public HttpOperation
|
||||
{
|
||||
public:
|
||||
HttpOpSetPriority(HttpHandle handle, HttpRequest::priority_t priority);
|
||||
HttpOpSetPriority(HttpHandle handle);
|
||||
|
||||
virtual ~HttpOpSetPriority();
|
||||
|
||||
|
|
@ -63,10 +63,10 @@ public:
|
|||
protected:
|
||||
// Request Data
|
||||
HttpHandle mHandle;
|
||||
HttpRequest::priority_t mPriority;
|
||||
}; // end class HttpOpSetPriority
|
||||
|
||||
} // end namespace LLCore
|
||||
#endif
|
||||
|
||||
#endif // _LLCORE_HTTP_SETPRIORITY_H_
|
||||
|
||||
|
|
|
|||
|
|
@ -330,37 +330,6 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue()
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool HttpPolicy::changePriority(HttpHandle handle, HttpRequest::priority_t priority)
|
||||
{
|
||||
for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
|
||||
{
|
||||
ClassState & state(*mClasses[policy_class]);
|
||||
// We don't scan retry queue because a priority change there
|
||||
// is meaningless. The request will be issued based on retry
|
||||
// intervals not priority value, which is now moot.
|
||||
|
||||
// Scan ready queue for requests that match policy
|
||||
HttpReadyQueue::container_type & c(state.mReadyQueue.get_container());
|
||||
for (HttpReadyQueue::container_type::iterator iter(c.begin()); c.end() != iter;)
|
||||
{
|
||||
HttpReadyQueue::container_type::iterator cur(iter++);
|
||||
|
||||
if ((*cur)->getHandle() == handle)
|
||||
{
|
||||
HttpOpRequest::ptr_t op(*cur);
|
||||
c.erase(cur); // All iterators are now invalidated
|
||||
op->mReqPriority = priority;
|
||||
state.mReadyQueue.push(op); // Re-insert using adapter class
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool HttpPolicy::cancel(HttpHandle handle)
|
||||
{
|
||||
for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
|
||||
|
|
|
|||
|
|
@ -110,12 +110,6 @@ public:
|
|||
/// Threading: called by worker thread
|
||||
void retryOp(const opReqPtr_t &);
|
||||
|
||||
/// Attempt to change the priority of an earlier request.
|
||||
/// Request that Shadows HttpService's method
|
||||
///
|
||||
/// Threading: called by worker thread
|
||||
bool changePriority(HttpHandle handle, HttpRequest::priority_t priority);
|
||||
|
||||
/// Attempt to cancel a previous request.
|
||||
/// Shadows HttpService's method as well
|
||||
///
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ HttpService::HttpService()
|
|||
|
||||
HttpService::~HttpService()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
mExitRequested = 1U;
|
||||
if (RUNNING == sState)
|
||||
{
|
||||
|
|
@ -131,6 +132,7 @@ HttpService::~HttpService()
|
|||
|
||||
void HttpService::init(HttpRequestQueue * queue)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
llassert_always(! sInstance);
|
||||
llassert_always(NOT_INITIALIZED == sState);
|
||||
sInstance = new HttpService();
|
||||
|
|
@ -145,6 +147,7 @@ void HttpService::init(HttpRequestQueue * queue)
|
|||
|
||||
void HttpService::term()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
if (sInstance)
|
||||
{
|
||||
if (RUNNING == sState && sInstance->mThread)
|
||||
|
|
@ -196,6 +199,7 @@ bool HttpService::isStopped()
|
|||
/// Threading: callable by consumer thread *once*.
|
||||
void HttpService::startThread()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
llassert_always(! mThread || STOPPED == sState);
|
||||
llassert_always(INITIALIZED == sState || STOPPED == sState);
|
||||
|
||||
|
|
@ -220,22 +224,6 @@ void HttpService::stopRequested()
|
|||
}
|
||||
|
||||
|
||||
/// Threading: callable by worker thread.
|
||||
bool HttpService::changePriority(HttpHandle handle, HttpRequest::priority_t priority)
|
||||
{
|
||||
bool found(false);
|
||||
|
||||
// Skip the request queue as we currently don't leave earlier
|
||||
// requests sitting there. Start with the ready queue...
|
||||
found = mPolicy->changePriority(handle, priority);
|
||||
|
||||
// If not there, we could try the transport/active queue but priority
|
||||
// doesn't really have much effect there so we don't waste cycles.
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
/// Try to find the given request handle on any of the request
|
||||
/// queues and cancel the operation.
|
||||
///
|
||||
|
|
@ -244,6 +232,7 @@ bool HttpService::changePriority(HttpHandle handle, HttpRequest::priority_t prio
|
|||
/// Threading: callable by worker thread.
|
||||
bool HttpService::cancel(HttpHandle handle)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
bool canceled(false);
|
||||
|
||||
// Request can't be on request queue so skip that.
|
||||
|
|
@ -264,6 +253,7 @@ bool HttpService::cancel(HttpHandle handle)
|
|||
/// Threading: callable by worker thread.
|
||||
void HttpService::shutdown()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
// Disallow future enqueue of requests
|
||||
mRequestQueue->stopQueue();
|
||||
|
||||
|
|
@ -293,6 +283,8 @@ void HttpService::shutdown()
|
|||
// requested to stop.
|
||||
void HttpService::threadRun(LLCoreInt::HttpThread * thread)
|
||||
{
|
||||
LL_PROFILER_SET_THREAD_NAME("HttpService");
|
||||
|
||||
boost::this_thread::disable_interruption di;
|
||||
|
||||
LLThread::registerThreadID();
|
||||
|
|
@ -300,6 +292,7 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread)
|
|||
ELoopSpeed loop(REQUEST_SLEEP);
|
||||
while (! mExitRequested)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
try
|
||||
{
|
||||
loop = processRequestQueue(loop);
|
||||
|
|
@ -344,6 +337,7 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread)
|
|||
|
||||
HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpRequestQueue::OpContainer ops;
|
||||
const bool wait_for_req(REQUEST_SLEEP == loop);
|
||||
|
||||
|
|
@ -384,6 +378,7 @@ HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop)
|
|||
HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||
long * ret_value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
||||
|| opt >= HttpRequest::PO_LAST // ditto
|
||||
|| (! sOptionDesc[opt].mIsLong) // datatype is long
|
||||
|
|
@ -416,6 +411,7 @@ HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
|
|||
HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||
std::string * ret_value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||
|
||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
||||
|
|
@ -443,6 +439,7 @@ HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
|
|||
HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||
HttpRequest::policyCallback_t * ret_value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||
|
||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
||||
|
|
@ -472,6 +469,7 @@ HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
|
|||
HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||
long value, long * ret_value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||
|
||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
||||
|
|
@ -517,6 +515,7 @@ HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
|
|||
HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||
const std::string & value, std::string * ret_value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||
|
||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
||||
|
|
@ -548,6 +547,7 @@ HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
|
|||
HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||
HttpRequest::policyCallback_t value, HttpRequest::policyCallback_t * ret_value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||
|
||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
||||
|
|
|
|||
|
|
@ -146,15 +146,6 @@ public:
|
|||
/// Threading: callable by worker thread.
|
||||
void shutdown();
|
||||
|
||||
/// Try to find the given request handle on any of the request
|
||||
/// queues and reset the priority (and queue position) of the
|
||||
/// request if found.
|
||||
///
|
||||
/// @return True if the request was found somewhere.
|
||||
///
|
||||
/// Threading: callable by worker thread.
|
||||
bool changePriority(HttpHandle handle, HttpRequest::priority_t priority);
|
||||
|
||||
/// Try to find the given request handle on any of the request
|
||||
/// queues and cancel the operation.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -469,11 +469,11 @@ bool WorkingSet::reload(LLCore::HttpRequest * hr, LLCore::HttpOptions::ptr_t & o
|
|||
LLCore::HttpHandle handle;
|
||||
if (offset || length)
|
||||
{
|
||||
handle = hr->requestGetByteRange(0, 0, buffer, offset, length, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor));
|
||||
handle = hr->requestGetByteRange(0, buffer, offset, length, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor));
|
||||
}
|
||||
else
|
||||
{
|
||||
handle = hr->requestGet(0, 0, buffer, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor));
|
||||
handle = hr->requestGet(0, buffer, opt, mHeaders, LLCore::HttpHandler::ptr_t(this, NoOpDeletor));
|
||||
}
|
||||
if (! handle)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
#include "_httppolicy.h"
|
||||
#include "_httpoperation.h"
|
||||
#include "_httpoprequest.h"
|
||||
#include "_httpopsetpriority.h"
|
||||
#include "_httpopcancel.h"
|
||||
#include "_httpopsetget.h"
|
||||
|
||||
|
|
@ -183,16 +182,16 @@ HttpStatus HttpRequest::getStatus() const
|
|||
|
||||
|
||||
HttpHandle HttpRequest::requestGet(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers,
|
||||
HttpHandler::ptr_t user_handler)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpStatus status;
|
||||
|
||||
HttpOpRequest::ptr_t op(new HttpOpRequest());
|
||||
if (! (status = op->setupGet(policy_id, priority, url, options, headers)))
|
||||
if (! (status = op->setupGet(policy_id, url, options, headers)))
|
||||
{
|
||||
mLastReqStatus = status;
|
||||
return LLCORE_HTTP_HANDLE_INVALID;
|
||||
|
|
@ -210,7 +209,6 @@ HttpHandle HttpRequest::requestGet(policy_t policy_id,
|
|||
|
||||
|
||||
HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
size_t offset,
|
||||
size_t len,
|
||||
|
|
@ -218,10 +216,11 @@ HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
|
|||
const HttpHeaders::ptr_t & headers,
|
||||
HttpHandler::ptr_t user_handler)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||
HttpStatus status;
|
||||
|
||||
HttpOpRequest::ptr_t op(new HttpOpRequest());
|
||||
if (! (status = op->setupGetByteRange(policy_id, priority, url, offset, len, options, headers)))
|
||||
if (! (status = op->setupGetByteRange(policy_id, url, offset, len, options, headers)))
|
||||
{
|
||||
mLastReqStatus = status;
|
||||
return LLCORE_HTTP_HANDLE_INVALID;
|
||||
|
|
@ -239,7 +238,6 @@ HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
|
|||
|
||||
|
||||
HttpHandle HttpRequest::requestPost(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
|
|
@ -249,7 +247,7 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id,
|
|||
HttpStatus status;
|
||||
|
||||
HttpOpRequest::ptr_t op(new HttpOpRequest());
|
||||
if (! (status = op->setupPost(policy_id, priority, url, body, options, headers)))
|
||||
if (! (status = op->setupPost(policy_id, url, body, options, headers)))
|
||||
{
|
||||
mLastReqStatus = status;
|
||||
return LLCORE_HTTP_HANDLE_INVALID;
|
||||
|
|
@ -267,7 +265,6 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id,
|
|||
|
||||
|
||||
HttpHandle HttpRequest::requestPut(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
|
|
@ -277,7 +274,7 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,
|
|||
HttpStatus status;
|
||||
|
||||
HttpOpRequest::ptr_t op (new HttpOpRequest());
|
||||
if (! (status = op->setupPut(policy_id, priority, url, body, options, headers)))
|
||||
if (! (status = op->setupPut(policy_id, url, body, options, headers)))
|
||||
{
|
||||
mLastReqStatus = status;
|
||||
return LLCORE_HTTP_HANDLE_INVALID;
|
||||
|
|
@ -294,7 +291,6 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,
|
|||
}
|
||||
|
||||
HttpHandle HttpRequest::requestDelete(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers,
|
||||
|
|
@ -303,7 +299,7 @@ HttpHandle HttpRequest::requestDelete(policy_t policy_id,
|
|||
HttpStatus status;
|
||||
|
||||
HttpOpRequest::ptr_t op(new HttpOpRequest());
|
||||
if (!(status = op->setupDelete(policy_id, priority, url, options, headers)))
|
||||
if (!(status = op->setupDelete(policy_id, url, options, headers)))
|
||||
{
|
||||
mLastReqStatus = status;
|
||||
return LLCORE_HTTP_HANDLE_INVALID;
|
||||
|
|
@ -320,7 +316,6 @@ HttpHandle HttpRequest::requestDelete(policy_t policy_id,
|
|||
}
|
||||
|
||||
HttpHandle HttpRequest::requestPatch(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
|
|
@ -330,7 +325,7 @@ HttpHandle HttpRequest::requestPatch(policy_t policy_id,
|
|||
HttpStatus status;
|
||||
|
||||
HttpOpRequest::ptr_t op (new HttpOpRequest());
|
||||
if (!(status = op->setupPatch(policy_id, priority, url, body, options, headers)))
|
||||
if (!(status = op->setupPatch(policy_id, url, body, options, headers)))
|
||||
{
|
||||
mLastReqStatus = status;
|
||||
return LLCORE_HTTP_HANDLE_INVALID;
|
||||
|
|
@ -347,7 +342,6 @@ HttpHandle HttpRequest::requestPatch(policy_t policy_id,
|
|||
}
|
||||
|
||||
HttpHandle HttpRequest::requestCopy(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers,
|
||||
|
|
@ -356,7 +350,7 @@ HttpHandle HttpRequest::requestCopy(policy_t policy_id,
|
|||
HttpStatus status;
|
||||
|
||||
HttpOpRequest::ptr_t op(new HttpOpRequest());
|
||||
if (!(status = op->setupCopy(policy_id, priority, url, options, headers)))
|
||||
if (!(status = op->setupCopy(policy_id, url, options, headers)))
|
||||
{
|
||||
mLastReqStatus = status;
|
||||
return LLCORE_HTTP_HANDLE_INVALID;
|
||||
|
|
@ -374,7 +368,6 @@ HttpHandle HttpRequest::requestCopy(policy_t policy_id,
|
|||
}
|
||||
|
||||
HttpHandle HttpRequest::requestMove(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers,
|
||||
|
|
@ -383,7 +376,7 @@ HttpHandle HttpRequest::requestMove(policy_t policy_id,
|
|||
HttpStatus status;
|
||||
|
||||
HttpOpRequest::ptr_t op (new HttpOpRequest());
|
||||
if (!(status = op->setupMove(policy_id, priority, url, options, headers)))
|
||||
if (!(status = op->setupMove(policy_id, url, options, headers)))
|
||||
{
|
||||
mLastReqStatus = status;
|
||||
return LLCORE_HTTP_HANDLE_INVALID;
|
||||
|
|
@ -483,24 +476,6 @@ HttpHandle HttpRequest::requestCancel(HttpHandle request, HttpHandler::ptr_t use
|
|||
}
|
||||
|
||||
|
||||
HttpHandle HttpRequest::requestSetPriority(HttpHandle request, priority_t priority,
|
||||
HttpHandler::ptr_t handler)
|
||||
{
|
||||
HttpStatus status;
|
||||
|
||||
HttpOperation::ptr_t op (new HttpOpSetPriority(request, priority));
|
||||
op->setReplyPath(mReplyQueue, handler);
|
||||
if (! (status = mRequestQueue->addOp(op))) // transfers refcount
|
||||
{
|
||||
mLastReqStatus = status;
|
||||
return LLCORE_HTTP_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
mLastReqStatus = status;
|
||||
return op->getHandle();
|
||||
}
|
||||
|
||||
|
||||
// ====================================
|
||||
// Utility Methods
|
||||
// ====================================
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@ private:
|
|||
|
||||
public:
|
||||
typedef unsigned int policy_t;
|
||||
typedef unsigned int priority_t;
|
||||
|
||||
typedef boost::shared_ptr<HttpRequest> ptr_t;
|
||||
typedef boost::weak_ptr<HttpRequest> wptr_t;
|
||||
|
|
@ -316,8 +315,6 @@ public:
|
|||
///
|
||||
/// @param policy_id Default or user-defined policy class under
|
||||
/// which this request is to be serviced.
|
||||
/// @param priority Standard priority scheme inherited from
|
||||
/// Indra code base (U32-type scheme).
|
||||
/// @param url URL with any encoded query parameters to
|
||||
/// be accessed.
|
||||
/// @param options Optional instance of an HttpOptions object
|
||||
|
|
@ -346,7 +343,6 @@ public:
|
|||
/// case, @see getStatus() will return more info.
|
||||
///
|
||||
HttpHandle requestGet(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers,
|
||||
|
|
@ -377,7 +373,6 @@ public:
|
|||
/// - Referer:
|
||||
///
|
||||
/// @param policy_id @see requestGet()
|
||||
/// @param priority "
|
||||
/// @param url "
|
||||
/// @param offset Offset of first byte into resource to be returned.
|
||||
/// @param len Count of bytes to be returned
|
||||
|
|
@ -387,7 +382,6 @@ public:
|
|||
/// @return "
|
||||
///
|
||||
HttpHandle requestGetByteRange(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
size_t offset,
|
||||
size_t len,
|
||||
|
|
@ -418,7 +412,6 @@ public:
|
|||
/// - Expect:
|
||||
///
|
||||
/// @param policy_id @see requestGet()
|
||||
/// @param priority "
|
||||
/// @param url "
|
||||
/// @param body Byte stream to be sent as the body. No
|
||||
/// further encoding or escaping will be done
|
||||
|
|
@ -429,7 +422,6 @@ public:
|
|||
/// @return "
|
||||
///
|
||||
HttpHandle requestPost(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
|
|
@ -459,7 +451,6 @@ public:
|
|||
/// - Content-Type:
|
||||
///
|
||||
/// @param policy_id @see requestGet()
|
||||
/// @param priority "
|
||||
/// @param url "
|
||||
/// @param body Byte stream to be sent as the body. No
|
||||
/// further encoding or escaping will be done
|
||||
|
|
@ -470,7 +461,6 @@ public:
|
|||
/// @return "
|
||||
///
|
||||
HttpHandle requestPut(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
|
|
@ -483,7 +473,6 @@ public:
|
|||
/// encoding and communicating the content types.
|
||||
///
|
||||
/// @param policy_id @see requestGet()
|
||||
/// @param priority "
|
||||
/// @param url "
|
||||
/// @param options @see requestGet()K(optional)
|
||||
/// @param headers "
|
||||
|
|
@ -491,7 +480,6 @@ public:
|
|||
/// @return "
|
||||
///
|
||||
HttpHandle requestDelete(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers,
|
||||
|
|
@ -502,7 +490,6 @@ public:
|
|||
/// encoding and communicating the content types.
|
||||
///
|
||||
/// @param policy_id @see requestGet()
|
||||
/// @param priority "
|
||||
/// @param url "
|
||||
/// @param body Byte stream to be sent as the body. No
|
||||
/// further encoding or escaping will be done
|
||||
|
|
@ -513,7 +500,6 @@ public:
|
|||
/// @return "
|
||||
///
|
||||
HttpHandle requestPatch(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
BufferArray * body,
|
||||
const HttpOptions::ptr_t & options,
|
||||
|
|
@ -525,7 +511,6 @@ public:
|
|||
/// encoding and communicating the content types.
|
||||
///
|
||||
/// @param policy_id @see requestGet()
|
||||
/// @param priority "
|
||||
/// @param url "
|
||||
/// @param options @see requestGet()K(optional)
|
||||
/// @param headers "
|
||||
|
|
@ -533,7 +518,6 @@ public:
|
|||
/// @return "
|
||||
///
|
||||
HttpHandle requestCopy(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers,
|
||||
|
|
@ -544,7 +528,6 @@ public:
|
|||
/// encoding and communicating the content types.
|
||||
///
|
||||
/// @param policy_id @see requestGet()
|
||||
/// @param priority "
|
||||
/// @param url "
|
||||
/// @param options @see requestGet()K(optional)
|
||||
/// @param headers "
|
||||
|
|
@ -552,7 +535,6 @@ public:
|
|||
/// @return "
|
||||
///
|
||||
HttpHandle requestMove(policy_t policy_id,
|
||||
priority_t priority,
|
||||
const std::string & url,
|
||||
const HttpOptions::ptr_t & options,
|
||||
const HttpHeaders::ptr_t & headers,
|
||||
|
|
@ -593,18 +575,6 @@ public:
|
|||
|
||||
HttpHandle requestCancel(HttpHandle request, HttpHandler::ptr_t);
|
||||
|
||||
/// Request that a previously-issued request be reprioritized.
|
||||
/// The status of whether the change itself succeeded arrives
|
||||
/// via notification.
|
||||
///
|
||||
/// @param request Handle of previously-issued request to
|
||||
/// be changed.
|
||||
/// @param priority New priority value.
|
||||
/// @param handler @see requestGet()
|
||||
/// @return "
|
||||
///
|
||||
HttpHandle requestSetPriority(HttpHandle request, priority_t priority, HttpHandler::ptr_t handler);
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name UtilityMethods
|
||||
|
|
|
|||
|
|
@ -614,7 +614,6 @@ void HttpRequestTestObjectType::test<7>()
|
|||
// Issue a GET that can't connect
|
||||
mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT);
|
||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
"http://127.0.0.1:2/nothing/here",
|
||||
0,
|
||||
0,
|
||||
|
|
@ -716,7 +715,6 @@ void HttpRequestTestObjectType::test<8>()
|
|||
// Issue a GET that *can* connect
|
||||
mStatus = HttpStatus(200);
|
||||
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base,
|
||||
HttpOptions::ptr_t(),
|
||||
HttpHeaders::ptr_t(),
|
||||
|
|
@ -812,7 +810,6 @@ void HttpRequestTestObjectType::test<9>()
|
|||
// Issue a GET that *can* connect
|
||||
mStatus = HttpStatus(200);
|
||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base,
|
||||
0,
|
||||
0,
|
||||
|
|
@ -913,7 +910,6 @@ void HttpRequestTestObjectType::test<10>()
|
|||
body->append(body_text, strlen(body_text));
|
||||
mStatus = HttpStatus(200);
|
||||
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base,
|
||||
body,
|
||||
HttpOptions::ptr_t(),
|
||||
|
|
@ -1020,7 +1016,6 @@ void HttpRequestTestObjectType::test<11>()
|
|||
body->append(body_text, strlen(body_text));
|
||||
mStatus = HttpStatus(200);
|
||||
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base,
|
||||
body,
|
||||
HttpOptions::ptr_t(),
|
||||
|
|
@ -1127,7 +1122,6 @@ void HttpRequestTestObjectType::test<12>()
|
|||
// Issue a GET that *can* connect
|
||||
mStatus = HttpStatus(200);
|
||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base,
|
||||
0,
|
||||
0,
|
||||
|
|
@ -1240,7 +1234,6 @@ void HttpRequestTestObjectType::test<13>()
|
|||
regex_container_t::value_type(boost::regex("X-LL-Special", boost::regex::icase),
|
||||
boost::regex(".*", boost::regex::icase)));
|
||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base,
|
||||
0,
|
||||
0,
|
||||
|
|
@ -1346,7 +1339,6 @@ void HttpRequestTestObjectType::test<14>()
|
|||
// Issue a GET that sleeps
|
||||
mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT);
|
||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base,
|
||||
0,
|
||||
0,
|
||||
|
|
@ -1454,7 +1446,6 @@ void HttpRequestTestObjectType::test<15>()
|
|||
mStatus = HttpStatus(200);
|
||||
handler.mCheckContentType = "application/llsd+xml";
|
||||
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base,
|
||||
HttpOptions::ptr_t(),
|
||||
HttpHeaders::ptr_t(),
|
||||
|
|
@ -1609,7 +1600,6 @@ void HttpRequestTestObjectType::test<16>()
|
|||
boost::regex("X-Reflect-content-encoding", boost::regex::icase),
|
||||
boost::regex(".*", boost::regex::icase)));
|
||||
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base + "reflect/",
|
||||
options,
|
||||
HttpHeaders::ptr_t(),
|
||||
|
|
@ -1684,7 +1674,6 @@ void HttpRequestTestObjectType::test<16>()
|
|||
boost::regex("X-Reflect-content-encoding", boost::regex::icase),
|
||||
boost::regex(".*", boost::regex::icase)));
|
||||
handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base + "reflect/",
|
||||
0,
|
||||
47,
|
||||
|
|
@ -1863,7 +1852,6 @@ void HttpRequestTestObjectType::test<17>()
|
|||
boost::regex("X-Reflect-transfer_encoding", boost::regex::icase),
|
||||
boost::regex(".*chunked.*", boost::regex::icase)));
|
||||
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base + "reflect/",
|
||||
ba,
|
||||
options,
|
||||
|
|
@ -2049,7 +2037,6 @@ void HttpRequestTestObjectType::test<18>()
|
|||
boost::regex(".*", boost::regex::icase)));
|
||||
|
||||
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base + "reflect/",
|
||||
ba,
|
||||
options,
|
||||
|
|
@ -2249,7 +2236,6 @@ void HttpRequestTestObjectType::test<19>()
|
|||
boost::regex("X-Reflect-content-encoding", boost::regex::icase),
|
||||
boost::regex(".*", boost::regex::icase)));
|
||||
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base + "reflect/",
|
||||
options,
|
||||
headers,
|
||||
|
|
@ -2457,7 +2443,6 @@ void HttpRequestTestObjectType::test<20>()
|
|||
boost::regex(".*", boost::regex::icase)));
|
||||
|
||||
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base + "reflect/",
|
||||
ba,
|
||||
options,
|
||||
|
|
@ -2666,7 +2651,6 @@ void HttpRequestTestObjectType::test<21>()
|
|||
boost::regex("X-Reflect-content-type", boost::regex::icase),
|
||||
boost::regex("text/html", boost::regex::icase)));
|
||||
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base + "reflect/",
|
||||
ba,
|
||||
options,
|
||||
|
|
@ -2797,7 +2781,6 @@ void HttpRequestTestObjectType::test<22>()
|
|||
char buffer[128];
|
||||
sprintf(buffer, "/bug2295/%d/", i);
|
||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base + buffer,
|
||||
0,
|
||||
25,
|
||||
|
|
@ -2829,7 +2812,6 @@ void HttpRequestTestObjectType::test<22>()
|
|||
char buffer[128];
|
||||
sprintf(buffer, "/bug2295/00000012/%d/", i);
|
||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base + buffer,
|
||||
0,
|
||||
25,
|
||||
|
|
@ -2861,7 +2843,6 @@ void HttpRequestTestObjectType::test<22>()
|
|||
char buffer[128];
|
||||
sprintf(buffer, "/bug2295/inv_cont_range/%d/", i);
|
||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url_base + buffer,
|
||||
0,
|
||||
25,
|
||||
|
|
@ -2984,7 +2965,6 @@ void HttpRequestTestObjectType::test<23>()
|
|||
std::ostringstream url;
|
||||
url << url_base << i << "/";
|
||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||
0U,
|
||||
url.str(),
|
||||
0,
|
||||
0,
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg
|
|||
updateApplication(llformat("%s, try %d...", msg.c_str(), i+1));
|
||||
|
||||
LL_INFOS("CRASHREPORT") << "POST crash data to " << host << LL_ENDL;
|
||||
LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(httpRequest.get(), LLCore::HttpRequest::DEFAULT_POLICY_ID, 0,
|
||||
LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(httpRequest.get(), LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
host, data, httpOpts, LLCore::HttpHeaders::ptr_t(), LLCore::HttpHandler::ptr_t(new LLCrashLoggerHandler));
|
||||
|
||||
if (handle == LLCORE_HTTP_HANDLE_INVALID)
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ const std::string LLDiskCache::assetTypeToString(LLAssetType::EType at)
|
|||
{ LLAssetType::AT_PERSON, "PERSON" },
|
||||
{ LLAssetType::AT_MESH, "MESH" },
|
||||
{ LLAssetType::AT_SETTINGS, "SETTINGS" },
|
||||
{ LLAssetType::AT_MATERIAL, "MATERIAL" },
|
||||
{ LLAssetType::AT_UNKNOWN, "UNKNOWN" }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -45,8 +45,7 @@ void LLLFSThread::initClass(bool local_is_threaded)
|
|||
//static
|
||||
S32 LLLFSThread::updateClass(U32 ms_elapsed)
|
||||
{
|
||||
sLocal->update((F32)ms_elapsed);
|
||||
return sLocal->getPending();
|
||||
return sLocal->update((F32)ms_elapsed);
|
||||
}
|
||||
|
||||
//static
|
||||
|
|
@ -58,6 +57,7 @@ void LLLFSThread::cleanupClass()
|
|||
{
|
||||
sLocal->update(0);
|
||||
}
|
||||
sLocal->shutdown();
|
||||
delete sLocal;
|
||||
sLocal = NULL;
|
||||
}
|
||||
|
|
@ -65,8 +65,7 @@ void LLLFSThread::cleanupClass()
|
|||
//----------------------------------------------------------------------------
|
||||
|
||||
LLLFSThread::LLLFSThread(bool threaded) :
|
||||
LLQueuedThread("LFS", threaded),
|
||||
mPriorityCounter(PRIORITY_LOWBITS)
|
||||
LLQueuedThread("LFS", threaded)
|
||||
{
|
||||
if(!mLocalAPRFilePoolp)
|
||||
{
|
||||
|
|
@ -84,14 +83,12 @@ LLLFSThread::~LLLFSThread()
|
|||
|
||||
LLLFSThread::handle_t LLLFSThread::read(const std::string& filename, /* Flawfinder: ignore */
|
||||
U8* buffer, S32 offset, S32 numbytes,
|
||||
Responder* responder, U32 priority)
|
||||
Responder* responder)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
handle_t handle = generateHandle();
|
||||
|
||||
if (priority == 0) priority = PRIORITY_NORMAL | priorityCounter();
|
||||
else if (priority < PRIORITY_LOW) priority |= PRIORITY_LOW; // All reads are at least PRIORITY_LOW
|
||||
|
||||
Request* req = new Request(this, handle, priority,
|
||||
Request* req = new Request(this, handle,
|
||||
FILE_READ, filename,
|
||||
buffer, offset, numbytes,
|
||||
responder);
|
||||
|
|
@ -107,13 +104,12 @@ LLLFSThread::handle_t LLLFSThread::read(const std::string& filename, /* Flawfind
|
|||
|
||||
LLLFSThread::handle_t LLLFSThread::write(const std::string& filename,
|
||||
U8* buffer, S32 offset, S32 numbytes,
|
||||
Responder* responder, U32 priority)
|
||||
Responder* responder)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
handle_t handle = generateHandle();
|
||||
|
||||
if (priority == 0) priority = PRIORITY_LOW | priorityCounter();
|
||||
|
||||
Request* req = new Request(this, handle, priority,
|
||||
Request* req = new Request(this, handle,
|
||||
FILE_WRITE, filename,
|
||||
buffer, offset, numbytes,
|
||||
responder);
|
||||
|
|
@ -130,11 +126,11 @@ LLLFSThread::handle_t LLLFSThread::write(const std::string& filename,
|
|||
//============================================================================
|
||||
|
||||
LLLFSThread::Request::Request(LLLFSThread* thread,
|
||||
handle_t handle, U32 priority,
|
||||
handle_t handle,
|
||||
operation_t op, const std::string& filename,
|
||||
U8* buffer, S32 offset, S32 numbytes,
|
||||
Responder* responder) :
|
||||
QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE),
|
||||
QueuedRequest(handle, FLAG_AUTO_COMPLETE),
|
||||
mThread(thread),
|
||||
mOperation(op),
|
||||
mFileName(filename),
|
||||
|
|
@ -157,6 +153,7 @@ LLLFSThread::Request::~Request()
|
|||
// virtual, called from own thread
|
||||
void LLLFSThread::Request::finishRequest(bool completed)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
if (mResponder.notNull())
|
||||
{
|
||||
mResponder->completed(completed ? mBytesRead : 0);
|
||||
|
|
@ -166,6 +163,7 @@ void LLLFSThread::Request::finishRequest(bool completed)
|
|||
|
||||
void LLLFSThread::Request::deleteRequest()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
if (getStatus() == STATUS_QUEUED)
|
||||
{
|
||||
LL_ERRS() << "Attempt to delete a queued LLLFSThread::Request!" << LL_ENDL;
|
||||
|
|
@ -180,6 +178,7 @@ void LLLFSThread::Request::deleteRequest()
|
|||
|
||||
bool LLLFSThread::Request::processRequest()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
bool complete = false;
|
||||
if (mOperation == FILE_READ)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public:
|
|||
|
||||
public:
|
||||
Request(LLLFSThread* thread,
|
||||
handle_t handle, U32 priority,
|
||||
handle_t handle,
|
||||
operation_t op, const std::string& filename,
|
||||
U8* buffer, S32 offset, S32 numbytes,
|
||||
Responder* responder);
|
||||
|
|
@ -120,23 +120,16 @@ public:
|
|||
// Return a Request handle
|
||||
handle_t read(const std::string& filename, /* Flawfinder: ignore */
|
||||
U8* buffer, S32 offset, S32 numbytes,
|
||||
Responder* responder, U32 pri=0);
|
||||
Responder* responder);
|
||||
handle_t write(const std::string& filename,
|
||||
U8* buffer, S32 offset, S32 numbytes,
|
||||
Responder* responder, U32 pri=0);
|
||||
|
||||
// Misc
|
||||
U32 priorityCounter() { return mPriorityCounter-- & PRIORITY_LOWBITS; } // Use to order IO operations
|
||||
Responder* responder);
|
||||
|
||||
// static initializers
|
||||
static void initClass(bool local_is_threaded = TRUE); // Setup sLocal
|
||||
static S32 updateClass(U32 ms_elapsed);
|
||||
static void cleanupClass(); // Delete sLocal
|
||||
|
||||
|
||||
private:
|
||||
U32 mPriorityCounter;
|
||||
|
||||
public:
|
||||
static LLLFSThread* sLocal; // Default local file thread
|
||||
};
|
||||
|
|
|
|||
|
|
@ -798,7 +798,6 @@ U8* LLImageBase::allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 si
|
|||
// LLImageRaw
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
S32 LLImageRaw::sGlobalRawMemory = 0;
|
||||
S32 LLImageRaw::sRawImageCount = 0;
|
||||
|
||||
LLImageRaw::LLImageRaw()
|
||||
|
|
@ -815,6 +814,15 @@ LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components)
|
|||
++sRawImageCount;
|
||||
}
|
||||
|
||||
LLImageRaw::LLImageRaw(const U8* data, U16 width, U16 height, S8 components)
|
||||
: LLImageBase()
|
||||
{
|
||||
if (allocateDataSize(width, height, components))
|
||||
{
|
||||
memcpy(getData(), data, width * height * components);
|
||||
}
|
||||
}
|
||||
|
||||
LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components, bool no_copy)
|
||||
: LLImageBase()
|
||||
{
|
||||
|
|
@ -847,16 +855,13 @@ LLImageRaw::~LLImageRaw()
|
|||
U8* LLImageRaw::allocateData(S32 size)
|
||||
{
|
||||
U8* res = LLImageBase::allocateData(size);
|
||||
sGlobalRawMemory += getDataSize();
|
||||
return res;
|
||||
}
|
||||
|
||||
// virtual
|
||||
U8* LLImageRaw::reallocateData(S32 size)
|
||||
{
|
||||
sGlobalRawMemory -= getDataSize();
|
||||
U8* res = LLImageBase::reallocateData(size);
|
||||
sGlobalRawMemory += getDataSize();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -869,7 +874,6 @@ void LLImageRaw::releaseData()
|
|||
// virtual
|
||||
void LLImageRaw::deleteData()
|
||||
{
|
||||
sGlobalRawMemory -= getDataSize();
|
||||
LLImageBase::deleteData();
|
||||
}
|
||||
|
||||
|
|
@ -985,6 +989,43 @@ void LLImageRaw::verticalFlip()
|
|||
}
|
||||
|
||||
|
||||
bool LLImageRaw::optimizeAwayAlpha()
|
||||
{
|
||||
if (getComponents() == 4)
|
||||
{
|
||||
U8* data = getData();
|
||||
U32 pixels = getWidth() * getHeight();
|
||||
|
||||
// check alpha channel for all 255
|
||||
for (U32 i = 0; i < pixels; ++i)
|
||||
{
|
||||
if (data[i * 4 + 3] != 255)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// alpha channel is all 255, make a new copy of data without alpha channel
|
||||
U8* new_data = (U8*) ll_aligned_malloc_16(getWidth() * getHeight() * 3);
|
||||
|
||||
for (U32 i = 0; i < pixels; ++i)
|
||||
{
|
||||
U32 di = i * 3;
|
||||
U32 si = i * 4;
|
||||
for (U32 j = 0; j < 3; ++j)
|
||||
{
|
||||
new_data[di+j] = data[si+j];
|
||||
}
|
||||
}
|
||||
|
||||
setDataAndSize(new_data, getWidth(), getHeight(), 3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLImageRaw::expandToPowerOfTwo(S32 max_dim, bool scale_image)
|
||||
{
|
||||
// Find new sizes
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ protected:
|
|||
public:
|
||||
LLImageRaw();
|
||||
LLImageRaw(U16 width, U16 height, S8 components);
|
||||
LLImageRaw(const U8* data, U16 width, U16 height, S8 components);
|
||||
LLImageRaw(U8 *data, U16 width, U16 height, S8 components, bool no_copy = false);
|
||||
// Construct using createFromFile (used by tools)
|
||||
//LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
|
||||
|
|
@ -208,6 +209,10 @@ public:
|
|||
|
||||
void verticalFlip();
|
||||
|
||||
// if the alpha channel is all 100% opaque, delete it
|
||||
// returns true if alpha channel was deleted
|
||||
bool optimizeAwayAlpha();
|
||||
|
||||
static S32 biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
|
||||
static S32 expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
|
||||
static S32 contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim = MIN_IMAGE_SIZE);
|
||||
|
|
@ -275,7 +280,6 @@ protected:
|
|||
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
|
||||
|
||||
public:
|
||||
static S32 sGlobalRawMemory;
|
||||
static S32 sRawImageCount;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ bool LLImageJ2C::initEncode(LLImageRaw &raw_image, int blocks_size, int precinct
|
|||
|
||||
bool LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
return decodeChannels(raw_imagep, decode_time, 0, 4);
|
||||
}
|
||||
|
||||
|
|
@ -153,6 +154,7 @@ bool LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
|
|||
// Returns true to mean done, whether successful or not.
|
||||
bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
LLTimer elapsed;
|
||||
|
||||
bool res = true;
|
||||
|
|
|
|||
|
|
@ -28,64 +28,93 @@
|
|||
|
||||
#include "llimageworker.h"
|
||||
#include "llimagedxt.h"
|
||||
#include "threadpool.h"
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
class ImageRequest
|
||||
{
|
||||
public:
|
||||
ImageRequest(const LLPointer<LLImageFormatted>& image,
|
||||
S32 discard, BOOL needs_aux,
|
||||
const LLPointer<LLImageDecodeThread::Responder>& responder);
|
||||
virtual ~ImageRequest();
|
||||
|
||||
/*virtual*/ bool processRequest();
|
||||
/*virtual*/ void finishRequest(bool completed);
|
||||
|
||||
private:
|
||||
// LLPointers stored in ImageRequest MUST be LLPointer instances rather
|
||||
// than references: we need to increment the refcount when storing these.
|
||||
// input
|
||||
LLPointer<LLImageFormatted> mFormattedImage;
|
||||
S32 mDiscardLevel;
|
||||
BOOL mNeedsAux;
|
||||
// output
|
||||
LLPointer<LLImageRaw> mDecodedImageRaw;
|
||||
LLPointer<LLImageRaw> mDecodedImageAux;
|
||||
BOOL mDecodedRaw;
|
||||
BOOL mDecodedAux;
|
||||
LLPointer<LLImageDecodeThread::Responder> mResponder;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// MAIN THREAD
|
||||
LLImageDecodeThread::LLImageDecodeThread(bool threaded)
|
||||
: LLQueuedThread("imagedecode", threaded)
|
||||
LLImageDecodeThread::LLImageDecodeThread(bool /*threaded*/)
|
||||
{
|
||||
mCreationMutex = new LLMutex();
|
||||
mThreadPool.reset(new LL::ThreadPool("ImageDecode", 8));
|
||||
mThreadPool->start();
|
||||
}
|
||||
|
||||
//virtual
|
||||
LLImageDecodeThread::~LLImageDecodeThread()
|
||||
{
|
||||
delete mCreationMutex ;
|
||||
}
|
||||
{}
|
||||
|
||||
// MAIN THREAD
|
||||
// virtual
|
||||
size_t LLImageDecodeThread::update(F32 max_time_ms)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
LLMutexLock lock(mCreationMutex);
|
||||
for (creation_list_t::iterator iter = mCreationList.begin();
|
||||
iter != mCreationList.end(); ++iter)
|
||||
{
|
||||
creation_info& info = *iter;
|
||||
ImageRequest* req = new ImageRequest(info.handle, info.image,
|
||||
info.priority, info.discard, info.needs_aux,
|
||||
info.responder);
|
||||
|
||||
bool res = addRequest(req);
|
||||
if (!res)
|
||||
{
|
||||
LL_ERRS() << "request added after LLLFSThread::cleanupClass()" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
mCreationList.clear();
|
||||
S32 res = LLQueuedThread::update(max_time_ms);
|
||||
return res;
|
||||
return getPending();
|
||||
}
|
||||
|
||||
LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image,
|
||||
U32 priority, S32 discard, BOOL needs_aux, Responder* responder)
|
||||
size_t LLImageDecodeThread::getPending()
|
||||
{
|
||||
return mThreadPool->getQueue().size();
|
||||
}
|
||||
|
||||
LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(
|
||||
const LLPointer<LLImageFormatted>& image,
|
||||
S32 discard,
|
||||
BOOL needs_aux,
|
||||
const LLPointer<LLImageDecodeThread::Responder>& responder)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
LLMutexLock lock(mCreationMutex);
|
||||
handle_t handle = generateHandle();
|
||||
mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
|
||||
return handle;
|
||||
|
||||
// Instantiate the ImageRequest right in the lambda, why not?
|
||||
bool posted = mThreadPool->getQueue().post(
|
||||
[req = ImageRequest(image, discard, needs_aux, responder)]
|
||||
() mutable
|
||||
{
|
||||
auto done = req.processRequest();
|
||||
req.finishRequest(done);
|
||||
});
|
||||
if (! posted)
|
||||
{
|
||||
LL_DEBUGS() << "Tried to start decoding on shutdown" << LL_ENDL;
|
||||
// should this return 0?
|
||||
}
|
||||
|
||||
// It's important to our consumer (LLTextureFetchWorker) that we return a
|
||||
// nonzero handle. It is NOT important that the nonzero handle be unique:
|
||||
// nothing is ever done with it except to compare it to zero, or zero it.
|
||||
return 17;
|
||||
}
|
||||
|
||||
// Used by unit test only
|
||||
// Returns the size of the mutex guarded list as an indication of sanity
|
||||
S32 LLImageDecodeThread::tut_size()
|
||||
void LLImageDecodeThread::shutdown()
|
||||
{
|
||||
LLMutexLock lock(mCreationMutex);
|
||||
S32 res = mCreationList.size();
|
||||
return res;
|
||||
mThreadPool->close();
|
||||
}
|
||||
|
||||
LLImageDecodeThread::Responder::~Responder()
|
||||
|
|
@ -94,11 +123,10 @@ LLImageDecodeThread::Responder::~Responder()
|
|||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatted* image,
|
||||
U32 priority, S32 discard, BOOL needs_aux,
|
||||
LLImageDecodeThread::Responder* responder)
|
||||
: LLQueuedThread::QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE),
|
||||
mFormattedImage(image),
|
||||
ImageRequest::ImageRequest(const LLPointer<LLImageFormatted>& image,
|
||||
S32 discard, BOOL needs_aux,
|
||||
const LLPointer<LLImageDecodeThread::Responder>& responder)
|
||||
: mFormattedImage(image),
|
||||
mDiscardLevel(discard),
|
||||
mNeedsAux(needs_aux),
|
||||
mDecodedRaw(FALSE),
|
||||
|
|
@ -107,7 +135,7 @@ LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatte
|
|||
{
|
||||
}
|
||||
|
||||
LLImageDecodeThread::ImageRequest::~ImageRequest()
|
||||
ImageRequest::~ImageRequest()
|
||||
{
|
||||
mDecodedImageRaw = NULL;
|
||||
mDecodedImageAux = NULL;
|
||||
|
|
@ -118,10 +146,10 @@ LLImageDecodeThread::ImageRequest::~ImageRequest()
|
|||
|
||||
|
||||
// Returns true when done, whether or not decode was successful.
|
||||
bool LLImageDecodeThread::ImageRequest::processRequest()
|
||||
bool ImageRequest::processRequest()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
const F32 decode_time_slice = .1f;
|
||||
const F32 decode_time_slice = 0.f; //disable time slicing
|
||||
bool done = true;
|
||||
if (!mDecodedRaw && mFormattedImage.notNull())
|
||||
{
|
||||
|
|
@ -145,7 +173,7 @@ bool LLImageDecodeThread::ImageRequest::processRequest()
|
|||
mFormattedImage->getHeight(),
|
||||
mFormattedImage->getComponents());
|
||||
}
|
||||
done = mFormattedImage->decode(mDecodedImageRaw, decode_time_slice); // 1ms
|
||||
done = mFormattedImage->decode(mDecodedImageRaw, decode_time_slice);
|
||||
// some decoders are removing data when task is complete and there were errors
|
||||
mDecodedRaw = done && mDecodedImageRaw->getData();
|
||||
}
|
||||
|
|
@ -158,14 +186,14 @@ bool LLImageDecodeThread::ImageRequest::processRequest()
|
|||
mFormattedImage->getHeight(),
|
||||
1);
|
||||
}
|
||||
done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4); // 1ms
|
||||
done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4);
|
||||
mDecodedAux = done && mDecodedImageAux->getData();
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
|
||||
void ImageRequest::finishRequest(bool completed)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
if (mResponder.notNull())
|
||||
|
|
@ -175,10 +203,3 @@ void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
|
|||
}
|
||||
// Will automatically be deleted
|
||||
}
|
||||
|
||||
// Used by unit test only
|
||||
// Checks that a responder exists for this instance so that something can happen when completion is reached
|
||||
bool LLImageDecodeThread::ImageRequest::tut_isOK()
|
||||
{
|
||||
return mResponder.notNull();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@
|
|||
|
||||
#include "llimage.h"
|
||||
#include "llpointer.h"
|
||||
#include "llworkerthread.h"
|
||||
#include "threadpool_fwd.h"
|
||||
|
||||
class LLImageDecodeThread : public LLQueuedThread
|
||||
class LLImageDecodeThread
|
||||
{
|
||||
public:
|
||||
class Responder : public LLThreadSafeRefCount
|
||||
|
|
@ -42,63 +42,24 @@ public:
|
|||
virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) = 0;
|
||||
};
|
||||
|
||||
class ImageRequest : public LLQueuedThread::QueuedRequest
|
||||
{
|
||||
protected:
|
||||
virtual ~ImageRequest(); // use deleteRequest()
|
||||
|
||||
public:
|
||||
ImageRequest(handle_t handle, LLImageFormatted* image,
|
||||
U32 priority, S32 discard, BOOL needs_aux,
|
||||
LLImageDecodeThread::Responder* responder);
|
||||
|
||||
/*virtual*/ bool processRequest();
|
||||
/*virtual*/ void finishRequest(bool completed);
|
||||
|
||||
// Used by unit tests to check the consitency of the request instance
|
||||
bool tut_isOK();
|
||||
|
||||
private:
|
||||
// input
|
||||
LLPointer<LLImageFormatted> mFormattedImage;
|
||||
S32 mDiscardLevel;
|
||||
BOOL mNeedsAux;
|
||||
// output
|
||||
LLPointer<LLImageRaw> mDecodedImageRaw;
|
||||
LLPointer<LLImageRaw> mDecodedImageAux;
|
||||
BOOL mDecodedRaw;
|
||||
BOOL mDecodedAux;
|
||||
LLPointer<LLImageDecodeThread::Responder> mResponder;
|
||||
};
|
||||
|
||||
public:
|
||||
LLImageDecodeThread(bool threaded = true);
|
||||
virtual ~LLImageDecodeThread();
|
||||
|
||||
handle_t decodeImage(LLImageFormatted* image,
|
||||
U32 priority, S32 discard, BOOL needs_aux,
|
||||
Responder* responder);
|
||||
// meant to resemble LLQueuedThread::handle_t
|
||||
typedef U32 handle_t;
|
||||
handle_t decodeImage(const LLPointer<LLImageFormatted>& image,
|
||||
S32 discard, BOOL needs_aux,
|
||||
const LLPointer<Responder>& responder);
|
||||
size_t getPending();
|
||||
size_t update(F32 max_time_ms);
|
||||
|
||||
// Used by unit tests to check the consistency of the thread instance
|
||||
S32 tut_size();
|
||||
void shutdown();
|
||||
|
||||
private:
|
||||
struct creation_info
|
||||
{
|
||||
handle_t handle;
|
||||
LLPointer<LLImageFormatted> image;
|
||||
U32 priority;
|
||||
S32 discard;
|
||||
BOOL needs_aux;
|
||||
LLPointer<Responder> responder;
|
||||
creation_info(handle_t h, LLImageFormatted* i, U32 p, S32 d, BOOL aux, Responder* r)
|
||||
: handle(h), image(i), priority(p), discard(d), needs_aux(aux), responder(r)
|
||||
{}
|
||||
};
|
||||
typedef std::list<creation_info> creation_list_t;
|
||||
creation_list_t mCreationList;
|
||||
LLMutex* mCreationMutex;
|
||||
// As of SL-17483, LLImageDecodeThread is no longer itself an
|
||||
// LLQueuedThread - instead this is the API by which we submit work to the
|
||||
// "ImageDecode" ThreadPool.
|
||||
std::unique_ptr<LL::ThreadPool> mThreadPool;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -125,42 +125,11 @@ namespace tut
|
|||
}
|
||||
};
|
||||
|
||||
// Test wrapper declaration : image worker
|
||||
// Note: this class is not meant to be instantiated outside an LLImageDecodeThread instance
|
||||
// but it's not a bad idea to get its public API a good shake as part of a thorough unit test set.
|
||||
// Some gotcha with the destructor though (see below).
|
||||
struct imagerequest_test
|
||||
{
|
||||
// Instance to be tested
|
||||
LLImageDecodeThread::ImageRequest* mRequest;
|
||||
bool done;
|
||||
|
||||
// Constructor and destructor of the test wrapper
|
||||
imagerequest_test()
|
||||
{
|
||||
done = false;
|
||||
|
||||
mRequest = new LLImageDecodeThread::ImageRequest(0, 0,
|
||||
LLQueuedThread::PRIORITY_NORMAL, 0, FALSE,
|
||||
new responder_test(&done));
|
||||
}
|
||||
~imagerequest_test()
|
||||
{
|
||||
// We should delete the object *but*, because its destructor is protected, that cannot be
|
||||
// done from outside an LLImageDecodeThread instance... So we leak memory here... It's fine...
|
||||
//delete mRequest;
|
||||
}
|
||||
};
|
||||
|
||||
// Tut templating thingamagic: test group, object and test instance
|
||||
typedef test_group<imagedecodethread_test> imagedecodethread_t;
|
||||
typedef imagedecodethread_t::object imagedecodethread_object_t;
|
||||
tut::imagedecodethread_t tut_imagedecodethread("LLImageDecodeThread");
|
||||
|
||||
typedef test_group<imagerequest_test> imagerequest_t;
|
||||
typedef imagerequest_t::object imagerequest_object_t;
|
||||
tut::imagerequest_t tut_imagerequest("LLImageRequest");
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Test functions
|
||||
// Notes:
|
||||
|
|
@ -172,64 +141,18 @@ namespace tut
|
|||
// ---------------------------------------------------------------------------------------
|
||||
// Test the LLImageDecodeThread interface
|
||||
// ---------------------------------------------------------------------------------------
|
||||
//
|
||||
// Note on Unit Testing Queued Thread Classes
|
||||
//
|
||||
// Since methods on such a class are called on a separate loop and that we can't insert tut
|
||||
// ensure() calls in there, we exercise the class with 2 sets of tests:
|
||||
// - 1: Test as a single threaded instance: We declare the class but ask for no thread
|
||||
// to be spawned (easy with LLThreads since there's a boolean argument on the constructor
|
||||
// just for that). We can then unit test each public method like we do on a normal class.
|
||||
// - 2: Test as a threaded instance: We let the thread launch and check that its external
|
||||
// behavior is as expected (i.e. it runs, can accept a work order and processes
|
||||
// it). Typically though there's no guarantee that this exercises all the methods of the
|
||||
// class which is why we also need the previous "non threaded" set of unit tests for
|
||||
// complete coverage.
|
||||
//
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
template<> template<>
|
||||
void imagedecodethread_object_t::test<1>()
|
||||
{
|
||||
// Test a *non threaded* instance of the class
|
||||
mThread = new LLImageDecodeThread(false);
|
||||
ensure("LLImageDecodeThread: non threaded constructor failed", mThread != NULL);
|
||||
// Test that we start with an empty list right at creation
|
||||
ensure("LLImageDecodeThread: non threaded init state incorrect", mThread->tut_size() == 0);
|
||||
// Insert something in the queue
|
||||
bool done = false;
|
||||
LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done));
|
||||
// Verifies we got a valid handle
|
||||
ensure("LLImageDecodeThread: non threaded decodeImage(), returned handle is null", decodeHandle != 0);
|
||||
// Verifies that we do now have something in the queued list
|
||||
ensure("LLImageDecodeThread: non threaded decodeImage() insertion in threaded list failed", mThread->tut_size() == 1);
|
||||
// Trigger queue handling "manually" (on a threaded instance, this is done on the thread loop)
|
||||
S32 res = mThread->update(0);
|
||||
// Verifies that we successfully handled the list
|
||||
ensure("LLImageDecodeThread: non threaded update() list handling test failed", res == 0);
|
||||
// Verifies that the list is now empty
|
||||
ensure("LLImageDecodeThread: non threaded update() list emptying test failed", mThread->tut_size() == 0);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void imagedecodethread_object_t::test<2>()
|
||||
{
|
||||
// Test a *threaded* instance of the class
|
||||
mThread = new LLImageDecodeThread(true);
|
||||
ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL);
|
||||
// Test that we start with an empty list right at creation
|
||||
ensure("LLImageDecodeThread: threaded init state incorrect", mThread->tut_size() == 0);
|
||||
// Insert something in the queue
|
||||
bool done = false;
|
||||
LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done));
|
||||
LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, 0, FALSE, new responder_test(&done));
|
||||
// Verifies we get back a valid handle
|
||||
ensure("LLImageDecodeThread: threaded decodeImage(), returned handle is null", decodeHandle != 0);
|
||||
// Wait a little so to simulate the main thread doing something on its main loop...
|
||||
ms_sleep(500); // 500 milliseconds
|
||||
// Verifies that the responder has *not* been called yet in the meantime
|
||||
ensure("LLImageDecodeThread: responder creation failed", done == false);
|
||||
// Ask the thread to update: that means tells the queue to check itself and creates work requests
|
||||
mThread->update(1);
|
||||
// Wait till the thread has time to handle the work order (though it doesn't do much per work order...)
|
||||
const U32 INCREMENT_TIME = 500; // 500 milliseconds
|
||||
const U32 MAX_TIME = 20 * INCREMENT_TIME; // Do the loop 20 times max, i.e. wait 10 seconds but no more
|
||||
|
|
@ -242,24 +165,4 @@ namespace tut
|
|||
// Verifies that the responder has now been called
|
||||
ensure("LLImageDecodeThread: threaded work unit not processed", done == true);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Test the LLImageDecodeThread::ImageRequest interface
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
template<> template<>
|
||||
void imagerequest_object_t::test<1>()
|
||||
{
|
||||
// Test that we start with a correct request at creation
|
||||
ensure("LLImageDecodeThread::ImageRequest::ImageRequest() constructor test failed", mRequest->tut_isOK());
|
||||
bool res = mRequest->processRequest();
|
||||
// Verifies that we processed the request successfully
|
||||
ensure("LLImageDecodeThread::ImageRequest::processRequest() processing request test failed", res == true);
|
||||
// Check that we can call the finishing call safely
|
||||
try {
|
||||
mRequest->finishRequest(false);
|
||||
} catch (...) {
|
||||
fail("LLImageDecodeThread::ImageRequest::finishRequest() test failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -726,6 +726,7 @@ bool LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int disca
|
|||
|
||||
bool LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
// No specific implementation for this method in the OpenJpeg case
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ LLFolderDictionary::LLFolderDictionary()
|
|||
addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new FolderEntry("version", FALSE, FALSE, FALSE));
|
||||
|
||||
addEntry(LLFolderType::FT_SETTINGS, new FolderEntry("settings", TRUE, FALSE, TRUE));
|
||||
addEntry(LLFolderType::FT_MATERIAL, new FolderEntry("material", TRUE, FALSE, TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE, FALSE, FALSE));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -93,9 +93,13 @@ public:
|
|||
|
||||
FT_SETTINGS = 56,
|
||||
|
||||
FT_MATERIAL = 57,
|
||||
|
||||
FT_COUNT,
|
||||
|
||||
FT_NONE = -1
|
||||
|
||||
// When adding, see note at bottom of LLAssetType::Etype
|
||||
};
|
||||
|
||||
static EType lookup(const std::string& type_name);
|
||||
|
|
|
|||
|
|
@ -904,24 +904,31 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
|
|||
mInventoryType = LLInventoryType::IT_NONE;
|
||||
mAssetUUID.setNull();
|
||||
}
|
||||
std::string w;
|
||||
|
||||
w = INV_ITEM_ID_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
mUUID = sd[w];
|
||||
}
|
||||
w = INV_PARENT_ID_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
mParentUUID = sd[w];
|
||||
}
|
||||
// TODO - figure out if this should be moved into the noclobber fields above
|
||||
mThumbnailUUID.setNull();
|
||||
w = INV_THUMBNAIL_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
// iterate as map to avoid making unnecessary temp copies of everything
|
||||
LLSD::map_const_iterator i, end;
|
||||
end = sd.endMap();
|
||||
for (i = sd.beginMap(); i != end; ++i)
|
||||
{
|
||||
const LLSD &thumbnail_map = sd[w];
|
||||
w = INV_ASSET_ID_LABEL;
|
||||
if (i->first == INV_ITEM_ID_LABEL)
|
||||
{
|
||||
mUUID = i->second;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i->first == INV_PARENT_ID_LABEL)
|
||||
{
|
||||
mParentUUID = i->second;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i->first == INV_THUMBNAIL_LABEL)
|
||||
{
|
||||
const LLSD &thumbnail_map = i->second;
|
||||
const std::string w = INV_ASSET_ID_LABEL;
|
||||
if (thumbnail_map.has(w))
|
||||
{
|
||||
mThumbnailUUID = thumbnail_map[w];
|
||||
|
|
@ -936,22 +943,22 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
|
|||
<key>version</key>
|
||||
<integer> 1 </key>
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
if (i->first == INV_THUMBNAIL_ID_LABEL)
|
||||
{
|
||||
w = INV_THUMBNAIL_ID_LABEL;
|
||||
if (sd.has(w))
|
||||
mThumbnailUUID = i->second.asUUID();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i->first == INV_PERMISSIONS_LABEL)
|
||||
{
|
||||
mThumbnailUUID = sd[w].asUUID();
|
||||
mPermissions = ll_permissions_from_sd(i->second);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
w = INV_PERMISSIONS_LABEL;
|
||||
if (sd.has(w))
|
||||
{
|
||||
mPermissions = ll_permissions_from_sd(sd[w]);
|
||||
}
|
||||
w = INV_SALE_INFO_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
if (i->first == INV_SALE_INFO_LABEL)
|
||||
{
|
||||
// Sale info used to contain next owner perm. It is now in
|
||||
// the permissions. Thus, we read that out, and fix legacy
|
||||
|
|
@ -959,96 +966,110 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
|
|||
// should pick up the vast majority of the tasks.
|
||||
BOOL has_perm_mask = FALSE;
|
||||
U32 perm_mask = 0;
|
||||
if (!mSaleInfo.fromLLSD(sd[w], has_perm_mask, perm_mask))
|
||||
if (!mSaleInfo.fromLLSD(i->second, has_perm_mask, perm_mask))
|
||||
{
|
||||
goto fail;
|
||||
return false;
|
||||
}
|
||||
if (has_perm_mask)
|
||||
{
|
||||
if(perm_mask == PERM_NONE)
|
||||
if (perm_mask == PERM_NONE)
|
||||
{
|
||||
perm_mask = mPermissions.getMaskOwner();
|
||||
}
|
||||
// fair use fix.
|
||||
if(!(perm_mask & PERM_COPY))
|
||||
if (!(perm_mask & PERM_COPY))
|
||||
{
|
||||
perm_mask |= PERM_TRANSFER;
|
||||
}
|
||||
mPermissions.setMaskNext(perm_mask);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
w = INV_SHADOW_ID_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
if (i->first == INV_SHADOW_ID_LABEL)
|
||||
{
|
||||
mAssetUUID = sd[w];
|
||||
mAssetUUID = i->second;
|
||||
LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
|
||||
cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
|
||||
continue;
|
||||
}
|
||||
w = INV_ASSET_ID_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
if (i->first == INV_ASSET_ID_LABEL)
|
||||
{
|
||||
mAssetUUID = sd[w];
|
||||
mAssetUUID = i->second;
|
||||
continue;
|
||||
}
|
||||
w = INV_LINKED_ID_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
if (i->first == INV_LINKED_ID_LABEL)
|
||||
{
|
||||
mAssetUUID = sd[w];
|
||||
mAssetUUID = i->second;
|
||||
continue;
|
||||
}
|
||||
w = INV_ASSET_TYPE_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
if (i->first == INV_ASSET_TYPE_LABEL)
|
||||
{
|
||||
if (sd[w].isString())
|
||||
LLSD const &label = i->second;
|
||||
if (label.isString())
|
||||
{
|
||||
mType = LLAssetType::lookup(sd[w].asString().c_str());
|
||||
mType = LLAssetType::lookup(label.asString().c_str());
|
||||
}
|
||||
else if (sd[w].isInteger())
|
||||
else if (label.isInteger())
|
||||
{
|
||||
S8 type = (U8)sd[w].asInteger();
|
||||
S8 type = (U8) label.asInteger();
|
||||
mType = static_cast<LLAssetType::EType>(type);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
w = INV_INVENTORY_TYPE_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
if (i->first == INV_INVENTORY_TYPE_LABEL)
|
||||
{
|
||||
if (sd[w].isString())
|
||||
LLSD const &label = i->second;
|
||||
if (label.isString())
|
||||
{
|
||||
mInventoryType = LLInventoryType::lookup(sd[w].asString().c_str());
|
||||
mInventoryType = LLInventoryType::lookup(label.asString().c_str());
|
||||
}
|
||||
else if (sd[w].isInteger())
|
||||
else if (label.isInteger())
|
||||
{
|
||||
S8 type = (U8)sd[w].asInteger();
|
||||
S8 type = (U8) label.asInteger();
|
||||
mInventoryType = static_cast<LLInventoryType::EType>(type);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
w = INV_FLAGS_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
if (i->first == INV_FLAGS_LABEL)
|
||||
{
|
||||
if (sd[w].isBinary())
|
||||
LLSD const &label = i->second;
|
||||
if (label.isBinary())
|
||||
{
|
||||
mFlags = ll_U32_from_sd(sd[w]);
|
||||
mFlags = ll_U32_from_sd(label);
|
||||
}
|
||||
else if(sd[w].isInteger())
|
||||
else if (label.isInteger())
|
||||
{
|
||||
mFlags = sd[w].asInteger();
|
||||
mFlags = label.asInteger();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
w = INV_NAME_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
if (i->first == INV_NAME_LABEL)
|
||||
{
|
||||
mName = sd[w].asString();
|
||||
mName = i->second.asString();
|
||||
LLStringUtil::replaceNonstandardASCII(mName, ' ');
|
||||
LLStringUtil::replaceChar(mName, '|', ' ');
|
||||
continue;
|
||||
}
|
||||
w = INV_DESC_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
if (i->first == INV_DESC_LABEL)
|
||||
{
|
||||
mDescription = sd[w].asString();
|
||||
mDescription = i->second.asString();
|
||||
LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
|
||||
continue;
|
||||
}
|
||||
w = INV_CREATION_DATE_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
if (i->first == INV_CREATION_DATE_LABEL)
|
||||
{
|
||||
mCreationDate = sd[w].asInteger();
|
||||
mCreationDate = i->second.asInteger();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Need to convert 1.0 simstate files to a useful inventory type
|
||||
|
|
@ -1064,9 +1085,6 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
|
|||
mPermissions.initMasks(mInventoryType);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ LLInventoryDictionary::LLInventoryDictionary()
|
|||
addEntry(LLInventoryType::IT_WIDGET, new InventoryEntry("widget", "widget", 1, LLAssetType::AT_WIDGET));
|
||||
addEntry(LLInventoryType::IT_PERSON, new InventoryEntry("person", "person", 1, LLAssetType::AT_PERSON));
|
||||
addEntry(LLInventoryType::IT_SETTINGS, new InventoryEntry("settings", "settings", 1, LLAssetType::AT_SETTINGS));
|
||||
addEntry(LLInventoryType::IT_MATERIAL, new InventoryEntry("material", "render material", 1, LLAssetType::AT_MATERIAL));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -153,7 +154,8 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
|
|||
LLInventoryType::IT_NONE, // 53 AT_RESERVED_4
|
||||
LLInventoryType::IT_NONE, // 54 AT_RESERVED_5
|
||||
|
||||
LLInventoryType::IT_SETTINGS, // 55 AT_SETTINGS
|
||||
LLInventoryType::IT_SETTINGS, // 55 AT_SETTINGS <- why doesnt this match the value in llassettype.h? -brad
|
||||
LLInventoryType::IT_MATERIAL, // 57 AT_MATERIAL
|
||||
};
|
||||
|
||||
// static
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@ public:
|
|||
IT_WIDGET = 23,
|
||||
IT_PERSON = 24,
|
||||
IT_SETTINGS = 25,
|
||||
IT_COUNT = 26,
|
||||
IT_MATERIAL = 26,
|
||||
IT_COUNT = 27,
|
||||
|
||||
IT_UNKNOWN = 255,
|
||||
IT_NONE = -1
|
||||
|
|
@ -118,6 +119,8 @@ public:
|
|||
ICONNAME_SETTINGS_WATER,
|
||||
ICONNAME_SETTINGS_DAY,
|
||||
|
||||
ICONNAME_MATERIAL,
|
||||
|
||||
ICONNAME_INVALID,
|
||||
ICONNAME_UNKNOWN,
|
||||
ICONNAME_COUNT,
|
||||
|
|
|
|||
|
|
@ -694,6 +694,7 @@ void LLSettingsBlender::update(const LLSettingsBase::BlendFactor& blendf)
|
|||
F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_in)
|
||||
{
|
||||
LLSettingsBase::TrackPosition blendf = blendf_in;
|
||||
llassert(!isnan(blendf));
|
||||
if (blendf >= 1.0)
|
||||
{
|
||||
triggerComplete();
|
||||
|
|
|
|||
|
|
@ -467,6 +467,7 @@ protected:
|
|||
|
||||
class LLSettingsBlenderTimeDelta : public LLSettingsBlender
|
||||
{
|
||||
protected:
|
||||
LOG_CLASS(LLSettingsBlenderTimeDelta);
|
||||
public:
|
||||
static const LLSettingsBase::BlendFactor MIN_BLEND_DELTA;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "v3colorutil.h"
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
|
||||
//=========================================================================
|
||||
namespace
|
||||
{
|
||||
|
|
@ -132,7 +133,11 @@ const std::string LLSettingsSky::SETTING_SKY_MOISTURE_LEVEL("moisture_level");
|
|||
const std::string LLSettingsSky::SETTING_SKY_DROPLET_RADIUS("droplet_radius");
|
||||
const std::string LLSettingsSky::SETTING_SKY_ICE_LEVEL("ice_level");
|
||||
|
||||
const LLUUID LLSettingsSky::DEFAULT_ASSET_ID("3ae23978-ac82-bcf3-a9cb-ba6e52dcb9ad");
|
||||
const std::string LLSettingsSky::SETTING_REFLECTION_PROBE_AMBIANCE("reflection_probe_ambiance");
|
||||
|
||||
const LLUUID LLSettingsSky::DEFAULT_ASSET_ID("651510b8-5f4d-8991-1592-e7eeab2a5a06");
|
||||
|
||||
F32 LLSettingsSky::sAutoAdjustProbeAmbiance = 1.f;
|
||||
|
||||
static const LLUUID DEFAULT_SUN_ID("32bfbcea-24b1-fb9d-1ef9-48a28a63730f"); // dataserver
|
||||
static const LLUUID DEFAULT_MOON_ID("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver
|
||||
|
|
@ -402,6 +407,7 @@ LLSettingsSky::LLSettingsSky(const LLSD &data) :
|
|||
mNextRainbowTextureId(),
|
||||
mNextHaloTextureId()
|
||||
{
|
||||
mCanAutoAdjust = !data.has(SETTING_REFLECTION_PROBE_AMBIANCE);
|
||||
}
|
||||
|
||||
LLSettingsSky::LLSettingsSky():
|
||||
|
|
@ -424,6 +430,8 @@ void LLSettingsSky::replaceSettings(LLSD settings)
|
|||
mNextBloomTextureId.setNull();
|
||||
mNextRainbowTextureId.setNull();
|
||||
mNextHaloTextureId.setNull();
|
||||
|
||||
mCanAutoAdjust = !settings.has(SETTING_REFLECTION_PROBE_AMBIANCE);
|
||||
}
|
||||
|
||||
void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
|
||||
|
|
@ -436,6 +444,7 @@ void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
|
|||
mNextBloomTextureId = pother->mNextBloomTextureId;
|
||||
mNextRainbowTextureId = pother->mNextRainbowTextureId;
|
||||
mNextHaloTextureId = pother->mNextHaloTextureId;
|
||||
mCanAutoAdjust = pother->mCanAutoAdjust;
|
||||
}
|
||||
|
||||
void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf)
|
||||
|
|
@ -628,6 +637,9 @@ LLSettingsSky::validation_list_t LLSettingsSky::validationList()
|
|||
validation.push_back(Validator(SETTING_SKY_ICE_LEVEL, false, LLSD::TypeReal,
|
||||
boost::bind(&Validator::verifyFloatRange, _1, _2, llsd::array(0.0f, 1.0f))));
|
||||
|
||||
validation.push_back(Validator(SETTING_REFLECTION_PROBE_AMBIANCE, false, LLSD::TypeReal,
|
||||
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(llsd::array(0.0f, 10.0f)))));
|
||||
|
||||
validation.push_back(Validator(SETTING_RAYLEIGH_CONFIG, true, LLSD::TypeArray, &validateRayleighLayers));
|
||||
validation.push_back(Validator(SETTING_ABSORPTION_CONFIG, true, LLSD::TypeArray, &validateAbsorptionLayers));
|
||||
validation.push_back(Validator(SETTING_MIE_CONFIG, true, LLSD::TypeArray, &validateMieLayers));
|
||||
|
|
@ -753,6 +765,8 @@ LLSD LLSettingsSky::defaults(const LLSettingsBase::TrackPosition& position)
|
|||
dfltsetting[SETTING_SKY_DROPLET_RADIUS] = 800.0f;
|
||||
dfltsetting[SETTING_SKY_ICE_LEVEL] = 0.0f;
|
||||
|
||||
dfltsetting[SETTING_REFLECTION_PROBE_AMBIANCE] = 0.0f;
|
||||
|
||||
dfltsetting[SETTING_RAYLEIGH_CONFIG] = rayleighConfigDefault();
|
||||
dfltsetting[SETTING_MIE_CONFIG] = mieConfigDefault();
|
||||
dfltsetting[SETTING_ABSORPTION_CONFIG] = absorptionConfigDefault();
|
||||
|
|
@ -1130,6 +1144,12 @@ void LLSettingsSky::setSkyIceLevel(F32 ice_level)
|
|||
setValue(SETTING_SKY_ICE_LEVEL, ice_level);
|
||||
}
|
||||
|
||||
void LLSettingsSky::setReflectionProbeAmbiance(F32 ambiance)
|
||||
{
|
||||
mCanAutoAdjust = false; // we've now touched this sky in a "new" way, it can no longer auto adjust
|
||||
setValue(SETTING_REFLECTION_PROBE_AMBIANCE, ambiance);
|
||||
}
|
||||
|
||||
void LLSettingsSky::setAmbientColor(const LLColor3 &val)
|
||||
{
|
||||
mSettings[SETTING_LEGACY_HAZE][SETTING_AMBIENT] = val.getValue();
|
||||
|
|
@ -1418,6 +1438,34 @@ F32 LLSettingsSky::getSkyIceLevel() const
|
|||
return mSettings[SETTING_SKY_ICE_LEVEL].asReal();
|
||||
}
|
||||
|
||||
F32 LLSettingsSky::getReflectionProbeAmbiance(bool auto_adjust) const
|
||||
{
|
||||
if (auto_adjust && canAutoAdjust())
|
||||
{
|
||||
return sAutoAdjustProbeAmbiance;
|
||||
}
|
||||
|
||||
return mSettings[SETTING_REFLECTION_PROBE_AMBIANCE].asReal();
|
||||
}
|
||||
|
||||
F32 LLSettingsSky::getTotalReflectionProbeAmbiance(F32 cloud_shadow_scale, bool auto_adjust) const
|
||||
{
|
||||
#if 0
|
||||
// feed cloud shadow back into reflection probe ambiance to mimic pre-reflection-probe behavior
|
||||
// without brightening dark/interior spaces
|
||||
F32 probe_ambiance = getReflectionProbeAmbiance(auto_adjust);
|
||||
|
||||
if (probe_ambiance > 0.f && probe_ambiance < 1.f)
|
||||
{
|
||||
probe_ambiance += (1.f - probe_ambiance) * getCloudShadow() * cloud_shadow_scale;
|
||||
}
|
||||
|
||||
return probe_ambiance;
|
||||
#else
|
||||
return getReflectionProbeAmbiance(auto_adjust);
|
||||
#endif
|
||||
}
|
||||
|
||||
F32 LLSettingsSky::getSkyBottomRadius() const
|
||||
{
|
||||
return mSettings[SETTING_SKY_BOTTOM_RADIUS].asReal();
|
||||
|
|
|
|||
|
|
@ -97,10 +97,14 @@ public:
|
|||
static const std::string SETTING_SKY_DROPLET_RADIUS;
|
||||
static const std::string SETTING_SKY_ICE_LEVEL;
|
||||
|
||||
static const std::string SETTING_REFLECTION_PROBE_AMBIANCE;
|
||||
|
||||
static const std::string SETTING_LEGACY_HAZE;
|
||||
|
||||
static const LLUUID DEFAULT_ASSET_ID;
|
||||
|
||||
static F32 sAutoAdjustProbeAmbiance;
|
||||
|
||||
typedef PTR_NAMESPACE::shared_ptr<LLSettingsSky> ptr_t;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
|
@ -131,6 +135,14 @@ public:
|
|||
F32 getSkyDropletRadius() const;
|
||||
F32 getSkyIceLevel() const;
|
||||
|
||||
// get the probe ambiance setting as stored in the sky settings asset
|
||||
// auto_adjust - if true and canAutoAdjust() is true, return 1.0
|
||||
F32 getReflectionProbeAmbiance(bool auto_adjust = false) const;
|
||||
|
||||
// get the probe ambiance setting to use for rendering (adjusted by cloud shadow, aka cloud coverage)
|
||||
// auto_adjust - if true and canAutoAdjust() is true, return 1.0
|
||||
F32 getTotalReflectionProbeAmbiance(F32 cloud_shadow_scale, bool auto_adjust = false) const;
|
||||
|
||||
// Return first (only) profile layer represented in LLSD
|
||||
LLSD getRayleighConfig() const;
|
||||
LLSD getMieConfig() const;
|
||||
|
|
@ -159,6 +171,8 @@ public:
|
|||
void setSkyDropletRadius(F32 radius);
|
||||
void setSkyIceLevel(F32 ice_level);
|
||||
|
||||
void setReflectionProbeAmbiance(F32 ambiance);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
LLColor3 getAmbientColor() const;
|
||||
void setAmbientColor(const LLColor3 &val);
|
||||
|
|
@ -324,6 +338,10 @@ public:
|
|||
F32 aniso_factor = 0.0f);
|
||||
|
||||
virtual void updateSettings() SETTINGS_OVERRIDE;
|
||||
|
||||
// if true, this sky is a candidate for auto-adjustment
|
||||
bool canAutoAdjust() const { return mCanAutoAdjust; }
|
||||
|
||||
protected:
|
||||
static const std::string SETTING_LEGACY_EAST_ANGLE;
|
||||
static const std::string SETTING_LEGACY_ENABLE_CLOUD_SCROLL;
|
||||
|
|
@ -367,6 +385,9 @@ private:
|
|||
mutable LLColor4 mTotalAmbient;
|
||||
mutable LLColor4 mHazeColor;
|
||||
|
||||
// if true, this sky is a candidate for auto adjustment
|
||||
bool mCanAutoAdjust = true;
|
||||
|
||||
typedef std::map<std::string, S32> mapNameToUniformId_t;
|
||||
|
||||
static mapNameToUniformId_t sNameToUniformMapping;
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ LLSettingsWater::validation_list_t LLSettingsWater::validationList()
|
|||
llsd::array(0.0f, 0.0f, 0.0f, 1.0f),
|
||||
llsd::array(1.0f, 1.0f, 1.0f, 1.0f))));
|
||||
validation.push_back(Validator(SETTING_FOG_DENSITY, true, LLSD::TypeReal,
|
||||
boost::bind(&Validator::verifyFloatRange, _1, _2, llsd::array(-10.0f, 10.0f))));
|
||||
boost::bind(&Validator::verifyFloatRange, _1, _2, llsd::array(0.001f, 100.0f))));
|
||||
validation.push_back(Validator(SETTING_FOG_MOD, true, LLSD::TypeReal,
|
||||
boost::bind(&Validator::verifyFloatRange, _1, _2, llsd::array(0.0f, 20.0f))));
|
||||
validation.push_back(Validator(SETTING_FRESNEL_OFFSET, true, LLSD::TypeReal,
|
||||
|
|
|
|||
|
|
@ -379,6 +379,7 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod
|
|||
|
||||
void LLImageJ2CKDU::cleanupCodeStream()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
mInputp.reset();
|
||||
mDecodeState.reset();
|
||||
mCodeStreamp.reset();
|
||||
|
|
@ -426,6 +427,7 @@ bool LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int bloc
|
|||
// decodeImpl() usage matters for production.
|
||||
bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level, int* region)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
base.resetLastError();
|
||||
|
||||
// *FIX: kdu calls our callback function if there's an error, and then bombs.
|
||||
|
|
@ -509,6 +511,7 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
|
|||
// Returns true to mean done, whether successful or not.
|
||||
bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
ECodeStreamMode mode = MODE_FAST;
|
||||
|
||||
LLTimer decode_timer;
|
||||
|
|
@ -1332,6 +1335,7 @@ the `buf' pointer may actually point into a larger buffer representing
|
|||
multiple tiles. For this reason, `row_gap' is needed to identify the
|
||||
separation between consecutive rows in the real buffer. */
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||
S32 c;
|
||||
// Now walk through the lines of the buffer, recovering them from the
|
||||
// relevant tile-component processing engines.
|
||||
|
|
@ -1339,17 +1343,26 @@ separation between consecutive rows in the real buffer. */
|
|||
LLTimer decode_timer;
|
||||
while (mDims.size.y--)
|
||||
{
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("kduptc - pull");
|
||||
for (c = 0; c < mNumComponents; c++)
|
||||
{
|
||||
mEngines[c].pull(mLines[c]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((mNumComponents >= 3) && mUseYCC)
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("kduptc - convert");
|
||||
kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
|
||||
}
|
||||
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("kduptc - transfer");
|
||||
for (c = 0; c < mNumComponents; c++)
|
||||
{
|
||||
transfer_bytes(mBuf+c,mLines[c],mNumComponents,mBitDepths[c]);
|
||||
transfer_bytes(mBuf + c, mLines[c], mNumComponents, mBitDepths[c]);
|
||||
}
|
||||
}
|
||||
mBuf += mRowGap;
|
||||
if (mDims.size.y % 10)
|
||||
|
|
|
|||
|
|
@ -311,104 +311,6 @@ int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 rad
|
|||
return 0;
|
||||
}
|
||||
|
||||
// HACK: This version is still around because the version below doesn't work
|
||||
// unless the agent planes are initialized.
|
||||
// Return 1 if sphere is in frustum, 2 if fully in frustum, otherwise 0.
|
||||
// NOTE: 'center' is in absolute frame.
|
||||
int LLCamera::sphereInFrustumOld(const LLVector3 &sphere_center, const F32 radius) const
|
||||
{
|
||||
// Returns 1 if sphere is in frustum, 0 if not.
|
||||
// modified so that default view frust is along X with Z vertical
|
||||
F32 x, y, z, rightDist, leftDist, topDist, bottomDist;
|
||||
|
||||
// Subtract the view position
|
||||
//LLVector3 relative_center;
|
||||
//relative_center = sphere_center - getOrigin();
|
||||
LLVector3 rel_center(sphere_center);
|
||||
rel_center -= mOrigin;
|
||||
|
||||
bool all_in = TRUE;
|
||||
|
||||
// Transform relative_center.x to camera frame
|
||||
x = mXAxis * rel_center;
|
||||
if (x < MIN_NEAR_PLANE - radius)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (x < MIN_NEAR_PLANE + radius)
|
||||
{
|
||||
all_in = FALSE;
|
||||
}
|
||||
|
||||
if (x > mFarPlane + radius)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (x > mFarPlane - radius)
|
||||
{
|
||||
all_in = FALSE;
|
||||
}
|
||||
|
||||
// Transform relative_center.y to camera frame
|
||||
y = mYAxis * rel_center;
|
||||
|
||||
// distance to plane is the dot product of (x, y, 0) * plane_normal
|
||||
rightDist = x * mLocalPlanes[PLANE_RIGHT][VX] + y * mLocalPlanes[PLANE_RIGHT][VY];
|
||||
if (rightDist < -radius)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (rightDist < radius)
|
||||
{
|
||||
all_in = FALSE;
|
||||
}
|
||||
|
||||
leftDist = x * mLocalPlanes[PLANE_LEFT][VX] + y * mLocalPlanes[PLANE_LEFT][VY];
|
||||
if (leftDist < -radius)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (leftDist < radius)
|
||||
{
|
||||
all_in = FALSE;
|
||||
}
|
||||
|
||||
// Transform relative_center.y to camera frame
|
||||
z = mZAxis * rel_center;
|
||||
|
||||
topDist = x * mLocalPlanes[PLANE_TOP][VX] + z * mLocalPlanes[PLANE_TOP][VZ];
|
||||
if (topDist < -radius)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (topDist < radius)
|
||||
{
|
||||
all_in = FALSE;
|
||||
}
|
||||
|
||||
bottomDist = x * mLocalPlanes[PLANE_BOTTOM][VX] + z * mLocalPlanes[PLANE_BOTTOM][VZ];
|
||||
if (bottomDist < -radius)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (bottomDist < radius)
|
||||
{
|
||||
all_in = FALSE;
|
||||
}
|
||||
|
||||
if (all_in)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// HACK: This (presumably faster) version only currently works if you set up the
|
||||
// frustum planes using GL. At some point we should get those planes through another
|
||||
// mechanism, and then we can get rid of the "old" version above.
|
||||
|
||||
// Return 1 if sphere is in frustum, 2 if fully in frustum, otherwise 0.
|
||||
// NOTE: 'center' is in absolute frame.
|
||||
int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) const
|
||||
|
|
@ -463,65 +365,6 @@ F32 LLCamera::heightInPixels(const LLVector3 ¢er, F32 radius ) const
|
|||
}
|
||||
}
|
||||
|
||||
// If pos is visible, return the distance from pos to the camera.
|
||||
// Use fudge distance to scale rad against top/bot/left/right planes
|
||||
// Otherwise, return -distance
|
||||
F32 LLCamera::visibleDistance(const LLVector3 &pos, F32 rad, F32 fudgedist, U32 planemask) const
|
||||
{
|
||||
if (mFixedDistance > 0)
|
||||
{
|
||||
return mFixedDistance;
|
||||
}
|
||||
LLVector3 dvec = pos - mOrigin;
|
||||
// Check visibility
|
||||
F32 dist = dvec.magVec();
|
||||
if (dist > rad)
|
||||
{
|
||||
F32 dp,tdist;
|
||||
dp = dvec * mXAxis;
|
||||
if (dp < -rad)
|
||||
return -dist;
|
||||
|
||||
rad *= fudgedist;
|
||||
LLVector3 tvec(pos);
|
||||
for (int p=0; p<PLANE_NUM; p++)
|
||||
{
|
||||
if (!(planemask & (1<<p)))
|
||||
continue;
|
||||
tdist = -(mWorldPlanes[p].dist(tvec));
|
||||
if (tdist > rad)
|
||||
return -dist;
|
||||
}
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
// Like visibleDistance, except uses mHorizPlanes[], which are left and right
|
||||
// planes perpindicular to (0,0,1) in world space
|
||||
F32 LLCamera::visibleHorizDistance(const LLVector3 &pos, F32 rad, F32 fudgedist, U32 planemask) const
|
||||
{
|
||||
if (mFixedDistance > 0)
|
||||
{
|
||||
return mFixedDistance;
|
||||
}
|
||||
LLVector3 dvec = pos - mOrigin;
|
||||
// Check visibility
|
||||
F32 dist = dvec.magVec();
|
||||
if (dist > rad)
|
||||
{
|
||||
rad *= fudgedist;
|
||||
LLVector3 tvec(pos);
|
||||
for (int p=0; p<HORIZ_PLANE_NUM; p++)
|
||||
{
|
||||
if (!(planemask & (1<<p)))
|
||||
continue;
|
||||
F32 tdist = -(mHorizPlanes[p].dist(tvec));
|
||||
if (tdist > rad)
|
||||
return -dist;
|
||||
}
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
// ---------------- friends and operators ----------------
|
||||
|
||||
|
|
@ -536,18 +379,6 @@ std::ostream& operator<<(std::ostream &s, const LLCamera &C)
|
|||
s << " Aspect = " << C.getAspect() << "\n";
|
||||
s << " NearPlane = " << C.mNearPlane << "\n";
|
||||
s << " FarPlane = " << C.mFarPlane << "\n";
|
||||
s << " TopPlane = " << C.mLocalPlanes[LLCamera::PLANE_TOP][VX] << " "
|
||||
<< C.mLocalPlanes[LLCamera::PLANE_TOP][VY] << " "
|
||||
<< C.mLocalPlanes[LLCamera::PLANE_TOP][VZ] << "\n";
|
||||
s << " BottomPlane = " << C.mLocalPlanes[LLCamera::PLANE_BOTTOM][VX] << " "
|
||||
<< C.mLocalPlanes[LLCamera::PLANE_BOTTOM][VY] << " "
|
||||
<< C.mLocalPlanes[LLCamera::PLANE_BOTTOM][VZ] << "\n";
|
||||
s << " LeftPlane = " << C.mLocalPlanes[LLCamera::PLANE_LEFT][VX] << " "
|
||||
<< C.mLocalPlanes[LLCamera::PLANE_LEFT][VY] << " "
|
||||
<< C.mLocalPlanes[LLCamera::PLANE_LEFT][VZ] << "\n";
|
||||
s << " RightPlane = " << C.mLocalPlanes[LLCamera::PLANE_RIGHT][VX] << " "
|
||||
<< C.mLocalPlanes[LLCamera::PLANE_RIGHT][VY] << " "
|
||||
<< C.mLocalPlanes[LLCamera::PLANE_RIGHT][VZ] << "\n";
|
||||
s << "}";
|
||||
return s;
|
||||
}
|
||||
|
|
@ -675,26 +506,6 @@ void LLCamera::calcRegionFrustumPlanes(const LLVector3& shift, F32 far_clip_dist
|
|||
|
||||
void LLCamera::calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom)
|
||||
{
|
||||
LLVector3 a, b, c;
|
||||
|
||||
// For each plane we need to define 3 points (LLVector3's) in camera view space.
|
||||
// The order in which we pass the points to planeFromPoints() matters, because the
|
||||
// plane normal has a degeneracy of 2; we want it pointing _into_ the frustum.
|
||||
|
||||
a.setVec(0.0f, 0.0f, 0.0f);
|
||||
b.setVec(mFarPlane, right, top);
|
||||
c.setVec(mFarPlane, right, bottom);
|
||||
mLocalPlanes[PLANE_RIGHT].setVec(a, b, c);
|
||||
|
||||
c.setVec(mFarPlane, left, top);
|
||||
mLocalPlanes[PLANE_TOP].setVec(a, c, b);
|
||||
|
||||
b.setVec(mFarPlane, left, bottom);
|
||||
mLocalPlanes[PLANE_LEFT].setVec(a, b, c);
|
||||
|
||||
c.setVec(mFarPlane, right, bottom);
|
||||
mLocalPlanes[PLANE_BOTTOM].setVec( a, c, b);
|
||||
|
||||
//calculate center and radius squared of frustum in world absolute coordinates
|
||||
static LLVector3 const X_AXIS(1.f, 0.f, 0.f);
|
||||
mFrustCenter = X_AXIS*mFarPlane*0.5f;
|
||||
|
|
@ -718,39 +529,6 @@ void LLCamera::calculateFrustumPlanesFromWindow(F32 x1, F32 y1, F32 x2, F32 y2)
|
|||
calculateFrustumPlanes(left, right, top, bottom);
|
||||
}
|
||||
|
||||
void LLCamera::calculateWorldFrustumPlanes()
|
||||
{
|
||||
F32 d;
|
||||
LLVector3 center = mOrigin - mXAxis*mNearPlane;
|
||||
mWorldPlanePos = center;
|
||||
LLVector3 pnorm;
|
||||
for (int p = 0; p < PLANE_NUM; p++)
|
||||
{
|
||||
mLocalPlanes[p].getVector3(pnorm);
|
||||
LLVector3 norm = rotateToAbsolute(pnorm);
|
||||
norm.normVec();
|
||||
d = -(center * norm);
|
||||
mWorldPlanes[p] = LLPlane(norm, d);
|
||||
}
|
||||
// horizontal planes, perpindicular to (0,0,1);
|
||||
LLVector3 zaxis(0, 0, 1.0f);
|
||||
F32 yaw = getYaw();
|
||||
{
|
||||
LLVector3 tnorm;
|
||||
mLocalPlanes[PLANE_LEFT].getVector3(tnorm);
|
||||
tnorm.rotVec(yaw, zaxis);
|
||||
d = -(mOrigin * tnorm);
|
||||
mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);
|
||||
}
|
||||
{
|
||||
LLVector3 tnorm;
|
||||
mLocalPlanes[PLANE_RIGHT].getVector3(tnorm);
|
||||
tnorm.rotVec(yaw, zaxis);
|
||||
d = -(mOrigin * tnorm);
|
||||
mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this is the OpenGL matrix that will transform the default OpenGL view
|
||||
// (-Z=at, Y=up) to the default view of the LLCamera class (X=at, Z=up):
|
||||
//
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ const F32 DEFAULT_NEAR_PLANE = 0.25f;
|
|||
const F32 DEFAULT_FAR_PLANE = 64.f; // far reaches across two horizontal, not diagonal, regions
|
||||
|
||||
const F32 MAX_ASPECT_RATIO = 50.0f;
|
||||
const F32 MAX_NEAR_PLANE = 10.f;
|
||||
const F32 MAX_NEAR_PLANE = 1023.9f; // Clamp the near plane just before the skybox ends
|
||||
const F32 MAX_FAR_PLANE = 100000.0f; //1000000.0f; // Max allowed. Not good Z precision though.
|
||||
const F32 MAX_FAR_CLIP = 512.0f;
|
||||
|
||||
|
|
@ -131,14 +131,10 @@ private:
|
|||
S32 mViewHeightInPixels; // for ViewHeightInPixels() only
|
||||
F32 mNearPlane;
|
||||
F32 mFarPlane;
|
||||
LL_ALIGN_16(LLPlane mLocalPlanes[PLANE_NUM]);
|
||||
F32 mFixedDistance; // Always return this distance, unless < 0
|
||||
LLVector3 mFrustCenter; // center of frustum and radius squared for ultra-quick exclusion test
|
||||
F32 mFrustRadiusSquared;
|
||||
|
||||
LL_ALIGN_16(LLPlane mWorldPlanes[PLANE_NUM]);
|
||||
LL_ALIGN_16(LLPlane mHorizPlanes[HORIZ_PLANE_NUM]);
|
||||
|
||||
U32 mPlaneCount; //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in
|
||||
|
||||
LLVector3 mWorldPlanePos; // Position of World Planes (may be offset from camera)
|
||||
|
|
@ -184,7 +180,6 @@ public:
|
|||
return atan2f(mXAxis[VZ], xylen);
|
||||
}
|
||||
|
||||
const LLPlane& getWorldPlane(S32 index) const { return mWorldPlanes[index]; }
|
||||
const LLVector3& getWorldPlanePos() const { return mWorldPlanePos; }
|
||||
|
||||
// Copy mView, mAspect, mNearPlane, and mFarPlane to buffer.
|
||||
|
|
@ -200,7 +195,6 @@ public:
|
|||
|
||||
// Returns 1 if partly in, 2 if fully in.
|
||||
// NOTE: 'center' is in absolute frame.
|
||||
S32 sphereInFrustumOld(const LLVector3 ¢er, const F32 radius) const;
|
||||
S32 sphereInFrustum(const LLVector3 ¢er, const F32 radius) const;
|
||||
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
|
||||
S32 sphereInFrustumFull(const LLVector3 ¢er, const F32 radius) const { return sphereInFrustum(center, radius); }
|
||||
|
|
@ -217,8 +211,6 @@ public:
|
|||
F32 heightInPixels(const LLVector3 ¢er, F32 radius ) const;
|
||||
|
||||
// return the distance from pos to camera if visible (-distance if not visible)
|
||||
F32 visibleDistance(const LLVector3 &pos, F32 rad, F32 fudgescale = 1.0f, U32 planemask = PLANE_ALL_MASK) const;
|
||||
F32 visibleHorizDistance(const LLVector3 &pos, F32 rad, F32 fudgescale = 1.0f, U32 planemask = HORIZ_PLANE_ALL_MASK) const;
|
||||
void setFixedDistance(F32 distance) { mFixedDistance = distance; }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream &s, const LLCamera &C);
|
||||
|
|
@ -227,7 +219,6 @@ protected:
|
|||
void calculateFrustumPlanes();
|
||||
void calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom);
|
||||
void calculateFrustumPlanesFromWindow(F32 x1, F32 y1, F32 x2, F32 y2);
|
||||
void calculateWorldFrustumPlanes();
|
||||
} LL_ALIGN_POSTFIX(16);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <stdint.h>
|
||||
#endif
|
||||
#include <cmath>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "llerror.h"
|
||||
|
||||
|
|
@ -52,6 +53,11 @@
|
|||
#include "llmeshoptimizer.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
#include "mikktspace/mikktspace.h"
|
||||
#include "mikktspace/mikktspace.c" // insert mikktspace implementation into llvolume object file
|
||||
|
||||
#include "meshoptimizer/meshoptimizer.h"
|
||||
|
||||
#define DEBUG_SILHOUETTE_BINORMALS 0
|
||||
#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
|
||||
#define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette
|
||||
|
|
@ -2050,7 +2056,8 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge
|
|||
mDetail = detail;
|
||||
mSculptLevel = -2;
|
||||
mSurfaceArea = 1.f; //only calculated for sculpts, defaults to 1 for all other prims
|
||||
mIsMeshAssetLoaded = FALSE;
|
||||
mIsMeshAssetLoaded = false;
|
||||
mIsMeshAssetUnavaliable = false;
|
||||
mLODScaleBias.setVec(1,1,1);
|
||||
mHullPoints = NULL;
|
||||
mHullIndices = NULL;
|
||||
|
|
@ -2093,6 +2100,8 @@ void LLVolume::regen()
|
|||
|
||||
void LLVolume::genTangents(S32 face)
|
||||
{
|
||||
// generate legacy tangents for the specified face
|
||||
llassert(!isMeshAssetLoaded() || mVolumeFaces[face].mTangents != nullptr); // if this is a complete mesh asset, we should already have tangents
|
||||
mVolumeFaces[face].createTangents();
|
||||
}
|
||||
|
||||
|
|
@ -2433,11 +2442,10 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
|
|||
|
||||
LLSD::Binary pos = mdl[i]["Position"];
|
||||
LLSD::Binary norm = mdl[i]["Normal"];
|
||||
LLSD::Binary tangent = mdl[i]["Tangent"];
|
||||
LLSD::Binary tc = mdl[i]["TexCoord0"];
|
||||
LLSD::Binary idx = mdl[i]["TriangleList"];
|
||||
|
||||
|
||||
|
||||
//copy out indices
|
||||
S32 num_indices = idx.size() / 2;
|
||||
const S32 indices_to_discard = num_indices % 3;
|
||||
|
|
@ -2492,6 +2500,16 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
|
|||
min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
|
||||
max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
|
||||
|
||||
//unpack normalized scale/translation
|
||||
if (mdl[i].has("NormalizedScale"))
|
||||
{
|
||||
face.mNormalizedScale.setValue(mdl[i]["NormalizedScale"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
face.mNormalizedScale.set(1, 1, 1);
|
||||
}
|
||||
|
||||
LLVector4a pos_range;
|
||||
pos_range.setSub(max_pos, min_pos);
|
||||
LLVector2 tc_range2 = max_tc - min_tc;
|
||||
|
|
@ -2542,6 +2560,34 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0 // keep this code for now in case we decide to add support for on-the-wire tangents
|
||||
{
|
||||
if (!tangent.empty())
|
||||
{
|
||||
face.allocateTangents(face.mNumVertices);
|
||||
U16* t = (U16*)&(tangent[0]);
|
||||
|
||||
// NOTE: tangents coming from the asset may not be mikkt space, but they should always be used by the GLTF shaders to
|
||||
// maintain compliance with the GLTF spec
|
||||
LLVector4a* t_out = face.mTangents;
|
||||
|
||||
for (U32 j = 0; j < num_verts; ++j)
|
||||
{
|
||||
t_out->set((F32)t[0], (F32)t[1], (F32)t[2], (F32) t[3]);
|
||||
t_out->div(65535.f);
|
||||
t_out->mul(2.f);
|
||||
t_out->sub(1.f);
|
||||
|
||||
F32* tp = t_out->getF32ptr();
|
||||
tp[3] = tp[3] < 0.f ? -1.f : 1.f;
|
||||
|
||||
t_out++;
|
||||
t += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
if (!tc.empty())
|
||||
{
|
||||
|
|
@ -2745,7 +2791,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
|
|||
}
|
||||
}
|
||||
|
||||
if (!cacheOptimize())
|
||||
if (!cacheOptimize(true))
|
||||
{
|
||||
// Out of memory?
|
||||
LL_WARNS() << "Failed to optimize!" << LL_ENDL;
|
||||
|
|
@ -2759,14 +2805,32 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
|
|||
}
|
||||
|
||||
|
||||
BOOL LLVolume::isMeshAssetLoaded()
|
||||
bool LLVolume::isMeshAssetLoaded()
|
||||
{
|
||||
return mIsMeshAssetLoaded;
|
||||
}
|
||||
|
||||
void LLVolume::setMeshAssetLoaded(BOOL loaded)
|
||||
void LLVolume::setMeshAssetLoaded(bool loaded)
|
||||
{
|
||||
mIsMeshAssetLoaded = loaded;
|
||||
if (loaded)
|
||||
{
|
||||
mIsMeshAssetUnavaliable = false;
|
||||
}
|
||||
}
|
||||
|
||||
void LLVolume::setMeshAssetUnavaliable(bool unavaliable)
|
||||
{
|
||||
// Don't set it if at least one lod loaded
|
||||
if (!mIsMeshAssetLoaded)
|
||||
{
|
||||
mIsMeshAssetUnavaliable = unavaliable;
|
||||
}
|
||||
}
|
||||
|
||||
bool LLVolume::isMeshAssetUnavaliable()
|
||||
{
|
||||
return mIsMeshAssetUnavaliable;
|
||||
}
|
||||
|
||||
void LLVolume::copyFacesTo(std::vector<LLVolumeFace> &faces) const
|
||||
|
|
@ -2786,11 +2850,11 @@ void LLVolume::copyVolumeFaces(const LLVolume* volume)
|
|||
mSculptLevel = 0;
|
||||
}
|
||||
|
||||
bool LLVolume::cacheOptimize()
|
||||
bool LLVolume::cacheOptimize(bool gen_tangents)
|
||||
{
|
||||
for (S32 i = 0; i < mVolumeFaces.size(); ++i)
|
||||
{
|
||||
if (!mVolumeFaces[i].cacheOptimize())
|
||||
if (!mVolumeFaces[i].cacheOptimize(gen_tangents))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3306,12 +3370,12 @@ BOOL LLVolume::isFlat(S32 face)
|
|||
|
||||
bool LLVolumeParams::isSculpt() const
|
||||
{
|
||||
return mSculptID.notNull();
|
||||
return (mSculptType & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_NONE;
|
||||
}
|
||||
|
||||
bool LLVolumeParams::isMeshSculpt() const
|
||||
{
|
||||
return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
|
||||
return (mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH;
|
||||
}
|
||||
|
||||
bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const
|
||||
|
|
@ -3726,6 +3790,7 @@ bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 h
|
|||
void LLVolume::getLoDTriangleCounts(const LLVolumeParams& params, S32* counts)
|
||||
{ //attempt to approximate the number of triangles that will result from generating a volume LoD set for the
|
||||
//supplied LLVolumeParams -- inaccurate, but a close enough approximation for determining streaming cost
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
|
||||
F32 detail[] = {1.f, 1.5f, 2.5f, 4.f};
|
||||
for (S32 i = 0; i < 4; i++)
|
||||
{
|
||||
|
|
@ -4861,6 +4926,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
|||
}
|
||||
|
||||
mOptimized = src.mOptimized;
|
||||
mNormalizedScale = src.mNormalizedScale;
|
||||
|
||||
//delete
|
||||
return *this;
|
||||
|
|
@ -5383,256 +5449,218 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// data structures for tangent generation
|
||||
|
||||
bool LLVolumeFace::cacheOptimize()
|
||||
{ //optimize for vertex cache according to Forsyth method:
|
||||
// http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html
|
||||
struct MikktData
|
||||
{
|
||||
LLVolumeFace* face;
|
||||
std::vector<LLVector3> p;
|
||||
std::vector<LLVector3> n;
|
||||
std::vector<LLVector2> tc;
|
||||
std::vector<LLVector4> w;
|
||||
std::vector<LLVector4> t;
|
||||
|
||||
llassert(!mOptimized);
|
||||
mOptimized = TRUE;
|
||||
MikktData(LLVolumeFace* f)
|
||||
: face(f)
|
||||
{
|
||||
U32 count = face->mNumIndices;
|
||||
|
||||
LLVCacheLRU cache;
|
||||
p.resize(count);
|
||||
n.resize(count);
|
||||
tc.resize(count);
|
||||
t.resize(count);
|
||||
|
||||
if (mNumVertices < 3 || mNumIndices < 3)
|
||||
{ //nothing to do
|
||||
return true;
|
||||
if (face->mWeights)
|
||||
{
|
||||
w.resize(count);
|
||||
}
|
||||
|
||||
//mapping of vertices to triangles and indices
|
||||
std::vector<LLVCacheVertexData> vertex_data;
|
||||
|
||||
//mapping of triangles do vertices
|
||||
std::vector<LLVCacheTriangleData> triangle_data;
|
||||
LLVector3 inv_scale(1.f / face->mNormalizedScale.mV[0], 1.f / face->mNormalizedScale.mV[1], 1.f / face->mNormalizedScale.mV[2]);
|
||||
|
||||
try
|
||||
|
||||
for (int i = 0; i < face->mNumIndices; ++i)
|
||||
{
|
||||
triangle_data.resize(mNumIndices / 3);
|
||||
vertex_data.resize(mNumVertices);
|
||||
U32 idx = face->mIndices[i];
|
||||
|
||||
for (U32 i = 0; i < mNumIndices; i++)
|
||||
{ //populate vertex data and triangle data arrays
|
||||
U16 idx = mIndices[i];
|
||||
U32 tri_idx = i / 3;
|
||||
p[i].set(face->mPositions[idx].getF32ptr());
|
||||
p[i].scaleVec(face->mNormalizedScale); //put mesh in original coordinate frame when reconstructing tangents
|
||||
n[i].set(face->mNormals[idx].getF32ptr());
|
||||
n[i].scaleVec(inv_scale);
|
||||
n[i].normalize();
|
||||
tc[i].set(face->mTexCoords[idx]);
|
||||
|
||||
if (idx >= mNumVertices)
|
||||
if (idx >= face->mNumVertices)
|
||||
{
|
||||
// invalid index
|
||||
// replace with a valid index to avoid crashes
|
||||
idx = mNumVertices - 1;
|
||||
mIndices[i] = idx;
|
||||
idx = face->mNumVertices - 1;
|
||||
face->mIndices[i] = idx;
|
||||
|
||||
// Needs better logging
|
||||
LL_DEBUGS_ONCE("LLVOLUME") << "Invalid index, substituting" << LL_ENDL;
|
||||
}
|
||||
|
||||
vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
|
||||
vertex_data[idx].mIdx = idx;
|
||||
triangle_data[tri_idx].mVertex[i % 3] = &(vertex_data[idx]);
|
||||
}
|
||||
}
|
||||
catch (std::bad_alloc&)
|
||||
if (face->mWeights)
|
||||
{
|
||||
// resize or push_back failed
|
||||
LL_WARNS("LLVOLUME") << "Resize for " << mNumVertices << " vertices failed" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*F32 pre_acmr = 1.f;
|
||||
//measure cache misses from before rebuild
|
||||
{
|
||||
LLVCacheFIFO test_cache;
|
||||
for (U32 i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
test_cache.addVertex(&vertex_data[mIndices[i]]);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mNumVertices; i++)
|
||||
{
|
||||
vertex_data[i].mCacheTag = -1;
|
||||
}
|
||||
|
||||
pre_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
|
||||
}*/
|
||||
|
||||
for (U32 i = 0; i < mNumVertices; i++)
|
||||
{ //initialize score values (no cache -- might try a fifo cache here)
|
||||
LLVCacheVertexData& data = vertex_data[i];
|
||||
|
||||
data.mScore = find_vertex_score(data);
|
||||
data.mActiveTriangles = data.mTriangles.size();
|
||||
|
||||
for (U32 j = 0; j < data.mActiveTriangles; ++j)
|
||||
{
|
||||
data.mTriangles[j]->mScore += data.mScore;
|
||||
}
|
||||
}
|
||||
|
||||
//sort triangle data by score
|
||||
std::sort(triangle_data.begin(), triangle_data.end());
|
||||
|
||||
std::vector<U16> new_indices;
|
||||
|
||||
LLVCacheTriangleData* tri;
|
||||
|
||||
//prime pump by adding first triangle to cache;
|
||||
tri = &(triangle_data[0]);
|
||||
cache.addTriangle(tri);
|
||||
new_indices.push_back(tri->mVertex[0]->mIdx);
|
||||
new_indices.push_back(tri->mVertex[1]->mIdx);
|
||||
new_indices.push_back(tri->mVertex[2]->mIdx);
|
||||
tri->complete();
|
||||
|
||||
//U32 breaks = 0;
|
||||
for (U32 i = 1; i < mNumIndices/3; ++i)
|
||||
{
|
||||
cache.updateScores();
|
||||
tri = cache.mBestTriangle;
|
||||
if (!tri)
|
||||
{
|
||||
//breaks++;
|
||||
for (U32 j = 0; j < triangle_data.size(); ++j)
|
||||
{
|
||||
if (triangle_data[j].mActive)
|
||||
{
|
||||
tri = &(triangle_data[j]);
|
||||
break;
|
||||
w[i].set(face->mWeights[idx].getF32ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cache.addTriangle(tri);
|
||||
new_indices.push_back(tri->mVertex[0]->mIdx);
|
||||
new_indices.push_back(tri->mVertex[1]->mIdx);
|
||||
new_indices.push_back(tri->mVertex[2]->mIdx);
|
||||
tri->complete();
|
||||
|
||||
bool LLVolumeFace::cacheOptimize(bool gen_tangents)
|
||||
{ //optimize for vertex cache according to Forsyth method:
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
|
||||
llassert(!mOptimized);
|
||||
mOptimized = TRUE;
|
||||
|
||||
if (gen_tangents && mNormals && mTexCoords)
|
||||
{ // generate mikkt space tangents before cache optimizing since the index buffer may change
|
||||
// a bit of a hack to do this here, but this function gets called exactly once for the lifetime of a mesh
|
||||
// and is executed on a background thread
|
||||
SMikkTSpaceInterface ms;
|
||||
|
||||
ms.m_getNumFaces = [](const SMikkTSpaceContext* pContext)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
return face->mNumIndices / 3;
|
||||
};
|
||||
|
||||
ms.m_getNumVerticesOfFace = [](const SMikkTSpaceContext* pContext, const int iFace)
|
||||
{
|
||||
return 3;
|
||||
};
|
||||
|
||||
ms.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
F32* v = data->p[iFace * 3 + iVert].mV;
|
||||
fvPosOut[0] = v[0];
|
||||
fvPosOut[1] = v[1];
|
||||
fvPosOut[2] = v[2];
|
||||
};
|
||||
|
||||
ms.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
F32* n = data->n[iFace * 3 + iVert].mV;
|
||||
fvNormOut[0] = n[0];
|
||||
fvNormOut[1] = n[1];
|
||||
fvNormOut[2] = n[2];
|
||||
};
|
||||
|
||||
ms.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
F32* tc = data->tc[iFace * 3 + iVert].mV;
|
||||
fvTexcOut[0] = tc[0];
|
||||
fvTexcOut[1] = tc[1];
|
||||
};
|
||||
|
||||
ms.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
S32 i = iFace * 3 + iVert;
|
||||
|
||||
data->t[i].set(fvTangent);
|
||||
data->t[i].mV[3] = fSign;
|
||||
};
|
||||
|
||||
ms.m_setTSpace = nullptr;
|
||||
|
||||
MikktData data(this);
|
||||
|
||||
SMikkTSpaceContext ctx = { &ms, &data };
|
||||
|
||||
genTangSpaceDefault(&ctx);
|
||||
|
||||
//re-weld
|
||||
meshopt_Stream mos[] =
|
||||
{
|
||||
{ &data.p[0], sizeof(LLVector3), sizeof(LLVector3) },
|
||||
{ &data.n[0], sizeof(LLVector3), sizeof(LLVector3) },
|
||||
{ &data.t[0], sizeof(LLVector4), sizeof(LLVector4) },
|
||||
{ &data.tc[0], sizeof(LLVector2), sizeof(LLVector2) },
|
||||
{ data.w.empty() ? nullptr : &data.w[0], sizeof(LLVector4), sizeof(LLVector4) }
|
||||
};
|
||||
|
||||
std::vector<U32> remap;
|
||||
remap.resize(data.p.size());
|
||||
|
||||
U32 stream_count = data.w.empty() ? 4 : 5;
|
||||
|
||||
U32 vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count);
|
||||
|
||||
if (vert_count < 65535)
|
||||
{
|
||||
std::vector<U32> indices;
|
||||
indices.resize(mNumIndices);
|
||||
|
||||
//copy results back into volume
|
||||
resizeVertices(vert_count);
|
||||
|
||||
if (!data.w.empty())
|
||||
{
|
||||
allocateWeights(vert_count);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mNumIndices; ++i)
|
||||
allocateTangents(mNumVertices);
|
||||
|
||||
for (int i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
mIndices[i] = new_indices[i];
|
||||
}
|
||||
U32 src_idx = i;
|
||||
U32 dst_idx = remap[i];
|
||||
mIndices[i] = dst_idx;
|
||||
|
||||
/*F32 post_acmr = 1.f;
|
||||
//measure cache misses from after rebuild
|
||||
{
|
||||
LLVCacheFIFO test_cache;
|
||||
for (U32 i = 0; i < mNumVertices; i++)
|
||||
{
|
||||
vertex_data[i].mCacheTag = -1;
|
||||
}
|
||||
mPositions[dst_idx].load3(data.p[src_idx].mV);
|
||||
mNormals[dst_idx].load3(data.n[src_idx].mV);
|
||||
mTexCoords[dst_idx] = data.tc[src_idx];
|
||||
|
||||
for (U32 i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
test_cache.addVertex(&vertex_data[mIndices[i]]);
|
||||
}
|
||||
mTangents[dst_idx].loadua(data.t[src_idx].mV);
|
||||
|
||||
post_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
|
||||
}*/
|
||||
|
||||
//optimize for pre-TnL cache
|
||||
|
||||
//allocate space for new buffer
|
||||
S32 num_verts = mNumVertices;
|
||||
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
LLVector4a* pos = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+size);
|
||||
if (pos == NULL)
|
||||
{
|
||||
LL_WARNS("LLVOLUME") << "Allocation of positions vector[" << sizeof(LLVector4a) * 2 * num_verts + size << "] failed. " << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
LLVector4a* norm = pos + num_verts;
|
||||
LLVector2* tc = (LLVector2*) (norm + num_verts);
|
||||
|
||||
LLVector4a* wght = NULL;
|
||||
if (mWeights)
|
||||
{
|
||||
wght = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
if (wght == NULL)
|
||||
mWeights[dst_idx].loadua(data.w[src_idx].mV);
|
||||
}
|
||||
}
|
||||
|
||||
// put back in normalized coordinate frame
|
||||
LLVector4a inv_scale(1.f/mNormalizedScale.mV[0], 1.f / mNormalizedScale.mV[1], 1.f / mNormalizedScale.mV[2]);
|
||||
LLVector4a scale;
|
||||
scale.load3(mNormalizedScale.mV);
|
||||
scale.getF32ptr()[3] = 1.f;
|
||||
|
||||
for (int i = 0; i < mNumVertices; ++i)
|
||||
{
|
||||
ll_aligned_free<64>(pos);
|
||||
LL_WARNS("LLVOLUME") << "Allocation of weights[" << sizeof(LLVector4a) * num_verts << "] failed" << LL_ENDL;
|
||||
return false;
|
||||
mPositions[i].mul(inv_scale);
|
||||
mNormals[i].mul(scale);
|
||||
mNormals[i].normalize3();
|
||||
F32 w = mTangents[i].getF32ptr()[3];
|
||||
mTangents[i].mul(scale);
|
||||
mTangents[i].normalize3();
|
||||
mTangents[i].getF32ptr()[3] = w;
|
||||
}
|
||||
}
|
||||
|
||||
LLVector4a* binorm = NULL;
|
||||
if (mTangents)
|
||||
else
|
||||
{
|
||||
binorm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
if (binorm == NULL)
|
||||
{
|
||||
ll_aligned_free<64>(pos);
|
||||
ll_aligned_free_16(wght);
|
||||
LL_WARNS("LLVOLUME") << "Allocation of binormals[" << sizeof(LLVector4a)*num_verts << "] failed" << LL_ENDL;
|
||||
return false;
|
||||
// blew past the max vertex size limit, use legacy tangent generation which never adds verts
|
||||
createTangents();
|
||||
}
|
||||
}
|
||||
|
||||
//allocate mapping of old indices to new indices
|
||||
std::vector<S32> new_idx;
|
||||
// cache optimize index buffer
|
||||
|
||||
try
|
||||
{
|
||||
new_idx.resize(mNumVertices, -1);
|
||||
}
|
||||
catch (std::bad_alloc&)
|
||||
{
|
||||
ll_aligned_free<64>(pos);
|
||||
ll_aligned_free_16(wght);
|
||||
ll_aligned_free_16(binorm);
|
||||
LL_WARNS("LLVOLUME") << "Resize failed: " << mNumVertices << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
// meshopt needs scratch space, do some pointer shuffling to avoid an extra index buffer copy
|
||||
U16* src_indices = mIndices;
|
||||
mIndices = nullptr;
|
||||
resizeIndices(mNumIndices);
|
||||
|
||||
S32 cur_idx = 0;
|
||||
for (U32 i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
U16 idx = mIndices[i];
|
||||
if (new_idx[idx] == -1)
|
||||
{ //this vertex hasn't been added yet
|
||||
new_idx[idx] = cur_idx;
|
||||
meshopt_optimizeVertexCache<U16>(mIndices, src_indices, mNumIndices, mNumVertices);
|
||||
|
||||
//copy vertex data
|
||||
pos[cur_idx] = mPositions[idx];
|
||||
norm[cur_idx] = mNormals[idx];
|
||||
tc[cur_idx] = mTexCoords[idx];
|
||||
if (mWeights)
|
||||
{
|
||||
wght[cur_idx] = mWeights[idx];
|
||||
}
|
||||
if (mTangents)
|
||||
{
|
||||
binorm[cur_idx] = mTangents[idx];
|
||||
}
|
||||
|
||||
cur_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
mIndices[i] = new_idx[mIndices[i]];
|
||||
}
|
||||
|
||||
ll_aligned_free<64>(mPositions);
|
||||
// DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
|
||||
ll_aligned_free_16(mWeights);
|
||||
ll_aligned_free_16(mTangents);
|
||||
#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS
|
||||
ll_aligned_free_16(mJointIndices);
|
||||
ll_aligned_free_16(mJustWeights);
|
||||
mJustWeights = NULL;
|
||||
mJointIndices = NULL; // filled in later as necessary by skinning code for acceleration
|
||||
#endif
|
||||
|
||||
mPositions = pos;
|
||||
mNormals = norm;
|
||||
mTexCoords = tc;
|
||||
mWeights = wght;
|
||||
mTangents = binorm;
|
||||
|
||||
//std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
|
||||
//LL_INFOS() << result << LL_ENDL;
|
||||
ll_aligned_free_16(src_indices);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -6442,35 +6470,31 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe
|
|||
|
||||
void LLVolumeFace::createTangents()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
|
||||
|
||||
if (!mTangents)
|
||||
{
|
||||
allocateTangents(mNumVertices);
|
||||
|
||||
//generate tangents
|
||||
//LLVector4a* pos = mPositions;
|
||||
//LLVector2* tc = (LLVector2*) mTexCoords;
|
||||
LLVector4a* binorm = (LLVector4a*) mTangents;
|
||||
LLVector4a* ptr = (LLVector4a*)mTangents;
|
||||
|
||||
LLVector4a* end = mTangents+mNumVertices;
|
||||
while (binorm < end)
|
||||
LLVector4a* end = mTangents + mNumVertices;
|
||||
while (ptr < end)
|
||||
{
|
||||
(*binorm++).clear();
|
||||
(*ptr++).clear();
|
||||
}
|
||||
|
||||
binorm = mTangents;
|
||||
CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices / 3, mIndices, mTangents);
|
||||
|
||||
CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices/3, mIndices, mTangents);
|
||||
|
||||
//normalize tangents
|
||||
//normalize normals
|
||||
for (U32 i = 0; i < mNumVertices; i++)
|
||||
{
|
||||
//binorm[i].normalize3fast();
|
||||
//bump map/planar projection code requires normals to be normalized
|
||||
mNormals[i].normalize3fast();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLVolumeFace::resizeVertices(S32 num_verts)
|
||||
|
|
|
|||
|
|
@ -908,7 +908,7 @@ public:
|
|||
void remap();
|
||||
|
||||
void optimize(F32 angle_cutoff = 2.f);
|
||||
bool cacheOptimize();
|
||||
bool cacheOptimize(bool gen_tangents = false);
|
||||
|
||||
void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f));
|
||||
void destroyOctree();
|
||||
|
|
@ -960,10 +960,6 @@ public:
|
|||
// indexes for mPositions/mNormals/mTexCoords
|
||||
U16* mIndices;
|
||||
|
||||
// vertex buffer filled in by LLFace to cache this volume face geometry in vram
|
||||
// (declared as a LLPointer to LLRefCount to avoid dependency on LLVertexBuffer)
|
||||
mutable LLPointer<LLRefCount> mVertexBuffer;
|
||||
|
||||
std::vector<S32> mEdge;
|
||||
|
||||
//list of skin weights for rigged volumes
|
||||
|
|
@ -985,6 +981,11 @@ public:
|
|||
//whether or not face has been cache optimized
|
||||
BOOL mOptimized;
|
||||
|
||||
// if this is a mesh asset, scale and translation that were applied
|
||||
// when encoding the source mesh into a unit cube
|
||||
// used for regenerating tangents
|
||||
LLVector3 mNormalizedScale = LLVector3(1,1,1);
|
||||
|
||||
private:
|
||||
LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* mOctree;
|
||||
LLVolumeTriangle* mOctreeTriangles;
|
||||
|
|
@ -1087,7 +1088,10 @@ public:
|
|||
void copyVolumeFaces(const LLVolume* volume);
|
||||
void copyFacesTo(std::vector<LLVolumeFace> &faces) const;
|
||||
void copyFacesFrom(const std::vector<LLVolumeFace> &faces);
|
||||
bool cacheOptimize();
|
||||
|
||||
// use meshoptimizer to optimize index buffer for vertex shader cache
|
||||
// gen_tangents - if true, generate MikkTSpace tangents if needed before optimizing index buffer
|
||||
bool cacheOptimize(bool gen_tangents = false);
|
||||
|
||||
private:
|
||||
void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type);
|
||||
|
|
@ -1107,15 +1111,18 @@ private:
|
|||
bool unpackVolumeFacesInternal(const LLSD& mdl);
|
||||
|
||||
public:
|
||||
virtual void setMeshAssetLoaded(BOOL loaded);
|
||||
virtual BOOL isMeshAssetLoaded();
|
||||
virtual void setMeshAssetLoaded(bool loaded);
|
||||
virtual bool isMeshAssetLoaded();
|
||||
virtual void setMeshAssetUnavaliable(bool unavaliable);
|
||||
virtual bool isMeshAssetUnavaliable();
|
||||
|
||||
protected:
|
||||
BOOL mUnique;
|
||||
F32 mDetail;
|
||||
S32 mSculptLevel;
|
||||
F32 mSurfaceArea; //unscaled surface area
|
||||
BOOL mIsMeshAssetLoaded;
|
||||
bool mIsMeshAssetLoaded;
|
||||
bool mIsMeshAssetUnavaliable;
|
||||
|
||||
const LLVolumeParams mParams;
|
||||
LLPath *mPathp;
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ BOOL LLVolumeMgr::cleanup()
|
|||
// Note however that LLVolumeLODGroup that contains the volume
|
||||
// also holds a LLPointer so the volume will only go away after
|
||||
// anything holding the volume and the LODGroup are destroyed
|
||||
LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 detail)
|
||||
LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 lod)
|
||||
{
|
||||
LLVolumeLODGroup* volgroupp;
|
||||
if (mDataMutex)
|
||||
|
|
@ -109,7 +109,7 @@ LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32
|
|||
{
|
||||
mDataMutex->unlock();
|
||||
}
|
||||
return volgroupp->refLOD(detail);
|
||||
return volgroupp->refLOD(lod);
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
|
@ -287,18 +287,18 @@ bool LLVolumeLODGroup::cleanupRefs()
|
|||
return res;
|
||||
}
|
||||
|
||||
LLVolume* LLVolumeLODGroup::refLOD(const S32 detail)
|
||||
LLVolume* LLVolumeLODGroup::refLOD(const S32 lod)
|
||||
{
|
||||
llassert(detail >=0 && detail < NUM_LODS);
|
||||
mAccessCount[detail]++;
|
||||
llassert(lod >=0 && lod < NUM_LODS);
|
||||
mAccessCount[lod]++;
|
||||
|
||||
mRefs++;
|
||||
if (mVolumeLODs[detail].isNull())
|
||||
if (mVolumeLODs[lod].isNull())
|
||||
{
|
||||
mVolumeLODs[detail] = new LLVolume(mVolumeParams, mDetailScales[detail]);
|
||||
mVolumeLODs[lod] = new LLVolume(mVolumeParams, mDetailScales[lod]);
|
||||
}
|
||||
mLODRefs[detail]++;
|
||||
return mVolumeLODs[detail];
|
||||
mLODRefs[lod]++;
|
||||
return mVolumeLODs[lod];
|
||||
}
|
||||
|
||||
BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ class LLVector4;
|
|||
#include "llerror.h"
|
||||
#include "llmath.h"
|
||||
#include "llsd.h"
|
||||
#include "v3math.h" // needed for linearColor3v implemtation below
|
||||
#include <string.h>
|
||||
|
||||
// LLColor3 = |r g b|
|
||||
|
|
@ -88,6 +89,16 @@ public:
|
|||
const LLColor3& set(const LLColor3 &vec); // Sets LLColor3 to vec
|
||||
const LLColor3& set(const F32 *vec); // Sets LLColor3 to vec
|
||||
|
||||
// set from a vector of unknown type and size
|
||||
// may leave some data unmodified
|
||||
template<typename T>
|
||||
const LLColor3& set(const std::vector<T>& v);
|
||||
|
||||
// write to a vector of unknown type and size
|
||||
// maye leave some data unmodified
|
||||
template<typename T>
|
||||
void write(std::vector<T>& v) const;
|
||||
|
||||
F32 magVec() const; // deprecated
|
||||
F32 magVecSquared() const; // deprecated
|
||||
F32 normVec(); // deprecated
|
||||
|
|
@ -484,13 +495,45 @@ inline const LLColor3 srgbColor3(const LLColor3 &a) {
|
|||
return srgbColor;
|
||||
}
|
||||
|
||||
inline const LLColor3 linearColor3(const LLColor3 &a) {
|
||||
inline const LLColor3 linearColor3p(const F32* v) {
|
||||
LLColor3 linearColor;
|
||||
linearColor.mV[0] = sRGBtoLinear(a.mV[0]);
|
||||
linearColor.mV[1] = sRGBtoLinear(a.mV[1]);
|
||||
linearColor.mV[2] = sRGBtoLinear(a.mV[2]);
|
||||
linearColor.mV[0] = sRGBtoLinear(v[0]);
|
||||
linearColor.mV[1] = sRGBtoLinear(v[1]);
|
||||
linearColor.mV[2] = sRGBtoLinear(v[2]);
|
||||
|
||||
return linearColor;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline const LLColor3 linearColor3(const T& a) {
|
||||
return linearColor3p(a.mV);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline const LLVector3 linearColor3v(const T& a) {
|
||||
return LLVector3(linearColor3p(a.mV).mV);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const LLColor3& LLColor3::set(const std::vector<T>& v)
|
||||
{
|
||||
for (S32 i = 0; i < llmin((S32)v.size(), 3); ++i)
|
||||
{
|
||||
mV[i] = v[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// write to a vector of unknown type and size
|
||||
// maye leave some data unmodified
|
||||
template<typename T>
|
||||
void LLColor3::write(std::vector<T>& v) const
|
||||
{
|
||||
for (int i = 0; i < llmin((S32)v.size(), 3); ++i)
|
||||
{
|
||||
v[i] = mV[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -88,8 +88,18 @@ class LLColor4
|
|||
const LLColor4& set(const LLColor3 &vec); // Sets LLColor4 to LLColor3 vec (no change in alpha)
|
||||
const LLColor4& set(const LLColor3 &vec, F32 a); // Sets LLColor4 to LLColor3 vec, with alpha specified
|
||||
const LLColor4& set(const F32 *vec); // Sets LLColor4 to vec
|
||||
const LLColor4& set(const F64 *vec); // Sets LLColor4 to (double)vec
|
||||
const LLColor4& set(const LLColor4U& color4u); // Sets LLColor4 to color4u, rescaled.
|
||||
|
||||
// set from a vector of unknown type and size
|
||||
// may leave some data unmodified
|
||||
template<typename T>
|
||||
const LLColor4& set(const std::vector<T>& v);
|
||||
|
||||
// write to a vector of unknown type and size
|
||||
// maye leave some data unmodified
|
||||
template<typename T>
|
||||
void write(std::vector<T>& v) const;
|
||||
|
||||
const LLColor4& setAlpha(F32 a);
|
||||
|
||||
|
|
@ -334,6 +344,15 @@ inline const LLColor4& LLColor4::set(const F32 *vec)
|
|||
return (*this);
|
||||
}
|
||||
|
||||
inline const LLColor4& LLColor4::set(const F64 *vec)
|
||||
{
|
||||
mV[VX] = static_cast<F32>(vec[VX]);
|
||||
mV[VY] = static_cast<F32>(vec[VY]);
|
||||
mV[VZ] = static_cast<F32>(vec[VZ]);
|
||||
mV[VW] = static_cast<F32>(vec[VW]);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
// deprecated
|
||||
inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z)
|
||||
{
|
||||
|
|
@ -680,5 +699,25 @@ inline const LLColor4 linearColor4(const LLColor4 &a)
|
|||
return linearColor;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const LLColor4& LLColor4::set(const std::vector<T>& v)
|
||||
{
|
||||
for (S32 i = 0; i < llmin((S32)v.size(), 4); ++i)
|
||||
{
|
||||
mV[i] = v[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LLColor4::write(std::vector<T>& v) const
|
||||
{
|
||||
for (int i = 0; i < llmin((S32)v.size(), 4); ++i)
|
||||
{
|
||||
v[i] = mV[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ set(llmessage_SOURCE_FILES
|
|||
lldispatcher.cpp
|
||||
llexperiencecache.cpp
|
||||
llfiltersd2xmlrpc.cpp
|
||||
llgenericstreamingmessage.cpp
|
||||
llhost.cpp
|
||||
llhttpnode.cpp
|
||||
llhttpsdhandler.cpp
|
||||
|
|
@ -114,6 +115,7 @@ set(llmessage_HEADER_FILES
|
|||
llextendedstatus.h
|
||||
llfiltersd2xmlrpc.h
|
||||
llfollowcamparams.h
|
||||
llgenericstreamingmessage.h
|
||||
llhost.h
|
||||
llhttpnode.h
|
||||
llhttpnodeadapter.h
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ LLCore::HttpRequest::ptr_t sHttpRequest;
|
|||
LLCore::HttpHeaders::ptr_t sHttpHeaders;
|
||||
LLCore::HttpOptions::ptr_t sHttpOptions;
|
||||
LLCore::HttpRequest::policy_t sHttpPolicy;
|
||||
LLCore::HttpRequest::priority_t sHttpPriority;
|
||||
|
||||
/* Sample response:
|
||||
<?xml version="1.0"?>
|
||||
|
|
@ -121,7 +120,6 @@ LLAvatarNameCache::LLAvatarNameCache()
|
|||
sHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
|
||||
sHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());
|
||||
sHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID;
|
||||
sHttpPriority = 0;
|
||||
}
|
||||
|
||||
LLAvatarNameCache::~LLAvatarNameCache()
|
||||
|
|
|
|||
|
|
@ -131,7 +131,6 @@ bool responseToLLSD(HttpResponse * response, bool log, LLSD & out_llsd)
|
|||
|
||||
HttpHandle requestPostWithLLSD(HttpRequest * request,
|
||||
HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const LLSD & body,
|
||||
const HttpOptions::ptr_t &options,
|
||||
|
|
@ -145,7 +144,6 @@ HttpHandle requestPostWithLLSD(HttpRequest * request,
|
|||
LLSDSerialize::toXML(body, bas);
|
||||
|
||||
handle = request->requestPost(policy_id,
|
||||
priority,
|
||||
url,
|
||||
ba,
|
||||
options,
|
||||
|
|
@ -158,7 +156,6 @@ HttpHandle requestPostWithLLSD(HttpRequest * request,
|
|||
|
||||
HttpHandle requestPutWithLLSD(HttpRequest * request,
|
||||
HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const LLSD & body,
|
||||
const HttpOptions::ptr_t &options,
|
||||
|
|
@ -172,7 +169,6 @@ HttpHandle requestPutWithLLSD(HttpRequest * request,
|
|||
LLSDSerialize::toXML(body, bas);
|
||||
|
||||
handle = request->requestPut(policy_id,
|
||||
priority,
|
||||
url,
|
||||
ba,
|
||||
options,
|
||||
|
|
@ -184,7 +180,6 @@ HttpHandle requestPutWithLLSD(HttpRequest * request,
|
|||
|
||||
HttpHandle requestPatchWithLLSD(HttpRequest * request,
|
||||
HttpRequest::policy_t policy_id,
|
||||
HttpRequest::priority_t priority,
|
||||
const std::string & url,
|
||||
const LLSD & body,
|
||||
const HttpOptions::ptr_t &options,
|
||||
|
|
@ -198,7 +193,6 @@ HttpHandle requestPatchWithLLSD(HttpRequest * request,
|
|||
LLSDSerialize::toXML(body, bas);
|
||||
|
||||
handle = request->requestPatch(policy_id,
|
||||
priority,
|
||||
url,
|
||||
ba,
|
||||
options,
|
||||
|
|
@ -672,10 +666,9 @@ const std::string HttpCoroutineAdapter::HTTP_RESULTS_CONTENT("content");
|
|||
const std::string HttpCoroutineAdapter::HTTP_RESULTS_RAW("raw");
|
||||
|
||||
HttpCoroutineAdapter::HttpCoroutineAdapter(const std::string &name,
|
||||
LLCore::HttpRequest::policy_t policyId, LLCore::HttpRequest::priority_t priority) :
|
||||
LLCore::HttpRequest::policy_t policyId) :
|
||||
mAdapterName(name),
|
||||
mPolicyId(policyId),
|
||||
mPriority(priority),
|
||||
mYieldingHandle(LLCORE_HTTP_HANDLE_INVALID),
|
||||
mWeakRequest(),
|
||||
mWeakHandler()
|
||||
|
|
@ -709,7 +702,7 @@ LLSD HttpCoroutineAdapter::postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
|
|||
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||
// pointer from the smart pointer is safe in this case.
|
||||
LLCore::HttpHandle hhandle = requestPostWithLLSD(request,
|
||||
mPolicyId, mPriority, url, body, options, headers,
|
||||
mPolicyId, url, body, options, headers,
|
||||
handler);
|
||||
|
||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
||||
|
|
@ -832,7 +825,7 @@ LLSD HttpCoroutineAdapter::postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
|
|||
|
||||
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||
// pointer from the smart pointer is safe in this case.
|
||||
LLCore::HttpHandle hhandle = request->requestPost(mPolicyId, mPriority, url, rawbody.get(),
|
||||
LLCore::HttpHandle hhandle = request->requestPost(mPolicyId, url, rawbody.get(),
|
||||
options, headers, handler);
|
||||
|
||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
||||
|
|
@ -890,7 +883,7 @@ LLSD HttpCoroutineAdapter::putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
|
|||
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||
// pointer from the smart pointer is safe in this case.
|
||||
LLCore::HttpHandle hhandle = requestPutWithLLSD(request,
|
||||
mPolicyId, mPriority, url, body, options, headers,
|
||||
mPolicyId, url, body, options, headers,
|
||||
handler);
|
||||
|
||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
||||
|
|
@ -916,7 +909,7 @@ LLSD HttpCoroutineAdapter::putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
|
|||
|
||||
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||
// pointer from the smart pointer is safe in this case.
|
||||
LLCore::HttpHandle hhandle = request->requestPut(mPolicyId, mPriority,
|
||||
LLCore::HttpHandle hhandle = request->requestPut(mPolicyId,
|
||||
url, rawbody.get(), options, headers, handler);
|
||||
|
||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
||||
|
|
@ -972,7 +965,7 @@ LLSD HttpCoroutineAdapter::getAndSuspend_(LLCore::HttpRequest::ptr_t &request,
|
|||
|
||||
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||
// pointer from the smart pointer is safe in this case.
|
||||
LLCore::HttpHandle hhandle = request->requestGet(mPolicyId, mPriority,
|
||||
LLCore::HttpHandle hhandle = request->requestGet(mPolicyId,
|
||||
url, options, headers, handler);
|
||||
|
||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
||||
|
|
@ -1018,7 +1011,7 @@ LLSD HttpCoroutineAdapter::deleteAndSuspend_(LLCore::HttpRequest::ptr_t &request
|
|||
checkDefaultHeaders(headers);
|
||||
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||
// pointer from the smart pointer is safe in this case.
|
||||
LLCore::HttpHandle hhandle = request->requestDelete(mPolicyId, mPriority,
|
||||
LLCore::HttpHandle hhandle = request->requestDelete(mPolicyId,
|
||||
url, options, headers, handler);
|
||||
|
||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
||||
|
|
@ -1056,7 +1049,7 @@ LLSD HttpCoroutineAdapter::patchAndSuspend_(LLCore::HttpRequest::ptr_t &request,
|
|||
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||
// pointer from the smart pointer is safe in this case.
|
||||
LLCore::HttpHandle hhandle = requestPatchWithLLSD(request,
|
||||
mPolicyId, mPriority, url, body, options, headers,
|
||||
mPolicyId, url, body, options, headers,
|
||||
handler);
|
||||
|
||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
||||
|
|
@ -1098,7 +1091,7 @@ LLSD HttpCoroutineAdapter::copyAndSuspend_(LLCore::HttpRequest::ptr_t &request,
|
|||
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||
// pointer from the smart pointer is safe in this case.
|
||||
//
|
||||
LLCore::HttpHandle hhandle = request->requestCopy(mPolicyId, mPriority, url,
|
||||
LLCore::HttpHandle hhandle = request->requestCopy(mPolicyId, url,
|
||||
options, headers, handler);
|
||||
|
||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
||||
|
|
@ -1140,7 +1133,7 @@ LLSD HttpCoroutineAdapter::moveAndSuspend_(LLCore::HttpRequest::ptr_t &request,
|
|||
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||
// pointer from the smart pointer is safe in this case.
|
||||
//
|
||||
LLCore::HttpHandle hhandle = request->requestMove(mPolicyId, mPriority, url,
|
||||
LLCore::HttpHandle hhandle = request->requestMove(mPolicyId, url,
|
||||
options, headers, handler);
|
||||
|
||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue