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
|
*.pyc
|
||||||
*.rej
|
*.rej
|
||||||
*.swp
|
*.swp
|
||||||
|
*.vcxproj
|
||||||
|
*.filters
|
||||||
|
*.sln
|
||||||
|
*.depend
|
||||||
|
*.stamp
|
||||||
|
*.rc
|
||||||
|
|
||||||
*~
|
*~
|
||||||
|
|
||||||
# Specific paths and/or names
|
# Specific paths and/or names
|
||||||
|
CMakeCache.txt
|
||||||
|
cmake_install.cmake
|
||||||
LICENSES
|
LICENSES
|
||||||
build-darwin-*
|
build-darwin-*
|
||||||
build-linux-*
|
build-linux-*
|
||||||
|
|
@ -17,6 +26,10 @@ debian/files
|
||||||
debian/secondlife-appearance-utility*
|
debian/secondlife-appearance-utility*
|
||||||
debian/secondlife-viewer*
|
debian/secondlife-viewer*
|
||||||
indra/.distcc
|
indra/.distcc
|
||||||
|
indra/cmake/*
|
||||||
|
indra/out/*
|
||||||
|
|
||||||
|
indra/packages/*
|
||||||
build-vc80/
|
build-vc80/
|
||||||
build-vc100/
|
build-vc100/
|
||||||
build-vc120/
|
build-vc120/
|
||||||
|
|
|
||||||
170
autobuild.xml
170
autobuild.xml
|
|
@ -702,11 +702,11 @@
|
||||||
<key>archive</key>
|
<key>archive</key>
|
||||||
<map>
|
<map>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<string>34af0a90a3015b7e7ec2486090bc4ce6ee5be758</string>
|
<string>7cc58b3acb230a7e65ea5f0ff800be393eb4aa1b</string>
|
||||||
<key>hash_algorithm</key>
|
<key>hash_algorithm</key>
|
||||||
<string>sha1</string>
|
<string>sha1</string>
|
||||||
<key>url</key>
|
<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>
|
</map>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>common</string>
|
<string>common</string>
|
||||||
|
|
@ -1732,6 +1732,62 @@
|
||||||
<key>description</key>
|
<key>description</key>
|
||||||
<string>Meshoptimizer. Mesh optimization library.</string>
|
<string>Meshoptimizer. Mesh optimization library.</string>
|
||||||
</map>
|
</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>
|
<key>minizip-ng</key>
|
||||||
<map>
|
<map>
|
||||||
<key>platforms</key>
|
<key>platforms</key>
|
||||||
|
|
@ -2318,6 +2374,42 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>threejs</string>
|
<string>threejs</string>
|
||||||
</map>
|
</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>
|
<key>tracy</key>
|
||||||
<map>
|
<map>
|
||||||
<key>platforms</key>
|
<key>platforms</key>
|
||||||
|
|
@ -2327,11 +2419,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<key>archive</key>
|
<key>archive</key>
|
||||||
<map>
|
<map>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<string>b84ccb1606b3fc5b216d0123a23a4922e02b6bd8</string>
|
<string>9b6e1a1f4b0969d38a1ca8ee00aeb548</string>
|
||||||
<key>hash_algorithm</key>
|
|
||||||
<string>sha1</string>
|
|
||||||
<key>url</key>
|
<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>
|
</map>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>darwin64</string>
|
<string>darwin64</string>
|
||||||
|
|
@ -2341,11 +2431,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<key>archive</key>
|
<key>archive</key>
|
||||||
<map>
|
<map>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<string>54f126b85f179362cf0b6024e3cd621b53d68703</string>
|
<string>05b72ae5d733aed7d3bf142287601cc6</string>
|
||||||
<key>hash_algorithm</key>
|
<key>hash_algorithm</key>
|
||||||
<string>sha1</string>
|
<string>md5</string>
|
||||||
<key>url</key>
|
<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>
|
</map>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>windows64</string>
|
<string>windows64</string>
|
||||||
|
|
@ -2369,6 +2459,8 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<string>https://bitbucket.org/lindenlab/3p-tracy</string>
|
<string>https://bitbucket.org/lindenlab/3p-tracy</string>
|
||||||
<key>source_type</key>
|
<key>source_type</key>
|
||||||
<string>git</string>
|
<string>git</string>
|
||||||
|
<key>version</key>
|
||||||
|
<string>v0.8.1.578241</string>
|
||||||
</map>
|
</map>
|
||||||
<key>tut</key>
|
<key>tut</key>
|
||||||
<map>
|
<map>
|
||||||
|
|
@ -2630,6 +2722,62 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<key>description</key>
|
<key>description</key>
|
||||||
<string>XMLRPC Library</string>
|
<string>XMLRPC Library</string>
|
||||||
</map>
|
</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>
|
<key>xxhash</key>
|
||||||
<map>
|
<map>
|
||||||
<key>platforms</key>
|
<key>platforms</key>
|
||||||
|
|
@ -2887,6 +3035,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<string>RelWithDebInfo</string>
|
<string>RelWithDebInfo</string>
|
||||||
<string>-project</string>
|
<string>-project</string>
|
||||||
<string>SecondLife.xcodeproj</string>
|
<string>SecondLife.xcodeproj</string>
|
||||||
|
<string>-parallelizeTargets</string>
|
||||||
</array>
|
</array>
|
||||||
</map>
|
</map>
|
||||||
<key>default</key>
|
<key>default</key>
|
||||||
|
|
@ -2914,6 +3063,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<string>RelWithDebInfo</string>
|
<string>RelWithDebInfo</string>
|
||||||
<string>-project</string>
|
<string>-project</string>
|
||||||
<string>SecondLife.xcodeproj</string>
|
<string>SecondLife.xcodeproj</string>
|
||||||
|
<string>-parallelizeTargets</string>
|
||||||
</array>
|
</array>
|
||||||
</map>
|
</map>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
|
|
@ -2943,6 +3093,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<string>Release</string>
|
<string>Release</string>
|
||||||
<string>-project</string>
|
<string>-project</string>
|
||||||
<string>SecondLife.xcodeproj</string>
|
<string>SecondLife.xcodeproj</string>
|
||||||
|
<string>-parallelizeTargets</string>
|
||||||
</array>
|
</array>
|
||||||
</map>
|
</map>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
|
|
@ -2968,6 +3119,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<string>Release</string>
|
<string>Release</string>
|
||||||
<string>-project</string>
|
<string>-project</string>
|
||||||
<string>SecondLife.xcodeproj</string>
|
<string>SecondLife.xcodeproj</string>
|
||||||
|
<string>-parallelizeTargets</string>
|
||||||
</array>
|
</array>
|
||||||
</map>
|
</map>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ Agathos Frascati
|
||||||
CT-317
|
CT-317
|
||||||
CT-352
|
CT-352
|
||||||
Ai Austin
|
Ai Austin
|
||||||
|
SL-19399
|
||||||
Aiko Ying
|
Aiko Ying
|
||||||
Aimee Trescothick
|
Aimee Trescothick
|
||||||
SNOW-227
|
SNOW-227
|
||||||
|
|
@ -1421,6 +1422,7 @@ Sovereign Engineer
|
||||||
SL-18497
|
SL-18497
|
||||||
SL-18525
|
SL-18525
|
||||||
SL-18534
|
SL-18534
|
||||||
|
SL-19690
|
||||||
SL-19336
|
SL-19336
|
||||||
SpacedOut Frye
|
SpacedOut Frye
|
||||||
VWR-34
|
VWR-34
|
||||||
|
|
|
||||||
|
|
@ -187,3 +187,4 @@ if (LINUX OR DARWIN)
|
||||||
endif (LINUX OR DARWIN)
|
endif (LINUX OR DARWIN)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ set(cmake_SOURCE_FILES
|
||||||
VisualLeakDetector.cmake
|
VisualLeakDetector.cmake
|
||||||
LibVLCPlugin.cmake
|
LibVLCPlugin.cmake
|
||||||
XmlRpcEpi.cmake
|
XmlRpcEpi.cmake
|
||||||
|
xxHash.cmake
|
||||||
ZLIBNG.cmake
|
ZLIBNG.cmake
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
include_guard()
|
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),
|
# When building using proprietary binaries though (i.e. having access to LL private servers),
|
||||||
# we always build with FMODSTUDIO.
|
# we always build with FMODSTUDIO.
|
||||||
if (INSTALL_PROPRIETARY)
|
if (INSTALL_PROPRIETARY)
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,7 @@ include(Prebuilt)
|
||||||
include(GLH)
|
include(GLH)
|
||||||
|
|
||||||
add_library( ll::glext INTERFACE IMPORTED )
|
add_library( ll::glext INTERFACE IMPORTED )
|
||||||
if (WINDOWS OR LINUX)
|
use_system_binary(glext)
|
||||||
use_system_binary(glext)
|
use_prebuilt_binary(glext)
|
||||||
use_prebuilt_binary(glext)
|
|
||||||
endif (WINDOWS OR LINUX)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}")
|
message("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_CFLAGS ${${name}_test_additional_CFLAGS}")
|
||||||
endif()
|
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
|
# Setup test targets
|
||||||
#
|
#
|
||||||
|
|
@ -221,6 +228,13 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
|
||||||
)
|
)
|
||||||
endif ()
|
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
|
# Add link deps to the executable
|
||||||
if(TEST_DEBUG)
|
if(TEST_DEBUG)
|
||||||
message(STATUS "TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})")
|
message(STATUS "TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})")
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,5 @@
|
||||||
# -*- cmake -*-
|
# -*- 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)
|
use_prebuilt_binary(tracy)
|
||||||
|
|
||||||
target_include_directories( ll::tracy SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/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
|
# See: indra/llcommon/llprofiler.h
|
||||||
target_compile_definitions(ll::tracy INTERFACE LL_PROFILER_CONFIGURATION=3 )
|
add_compile_definitions(LL_PROFILER_CONFIGURATION=3)
|
||||||
endif (USE_TRACY)
|
endif (USE_TRACY)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ set(LIBS_OPEN_PREFIX)
|
||||||
set(SCRIPTS_PREFIX ../scripts)
|
set(SCRIPTS_PREFIX ../scripts)
|
||||||
set(VIEWER_PREFIX)
|
set(VIEWER_PREFIX)
|
||||||
set(INTEGRATION_TESTS_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(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(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")
|
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
|
// clear buffer area to ensure we don't pick up UI elements
|
||||||
{
|
{
|
||||||
gGL.flush();
|
gGL.flush();
|
||||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
|
||||||
gAlphaMaskProgram.setMinimumAlpha(0.0f);
|
gAlphaMaskProgram.setMinimumAlpha(0.0f);
|
||||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||||
gGL.color4f( 0.f, 0.f, 0.f, 1.f );
|
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.flush();
|
||||||
|
|
||||||
gGL.setSceneBlendType(LLRender::BT_REPLACE);
|
gGL.setSceneBlendType(LLRender::BT_REPLACE);
|
||||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
|
||||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||||
|
|
||||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
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)
|
// Set the alpha channel to one (clean up after previous blending)
|
||||||
gGL.flush();
|
gGL.flush();
|
||||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
|
||||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||||
gGL.color4f( 0.f, 0.f, 0.f, 1.f );
|
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)
|
BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target)
|
||||||
{
|
{
|
||||||
LLGLEnable color_mat(GL_COLOR_MATERIAL);
|
|
||||||
// *TODO: Is this correct?
|
// *TODO: Is this correct?
|
||||||
//gPipeline.disableLights();
|
//gPipeline.disableLights();
|
||||||
stop_glerror();
|
stop_glerror();
|
||||||
|
|
@ -1112,7 +1108,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
|
||||||
if( tex )
|
if( tex )
|
||||||
{
|
{
|
||||||
bool no_alpha_test = getInfo()->mWriteAllChannels;
|
bool no_alpha_test = getInfo()->mWriteAllChannels;
|
||||||
LLGLDisable alpha_test(no_alpha_test ? GL_ALPHA_TEST : 0);
|
|
||||||
if (no_alpha_test)
|
if (no_alpha_test)
|
||||||
{
|
{
|
||||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||||
|
|
@ -1162,7 +1157,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
|
||||||
getInfo()->mStaticImageFileName.empty() &&
|
getInfo()->mStaticImageFileName.empty() &&
|
||||||
color_specified )
|
color_specified )
|
||||||
{
|
{
|
||||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
|
||||||
gAlphaMaskProgram.setMinimumAlpha(0.000f);
|
gAlphaMaskProgram.setMinimumAlpha(0.000f);
|
||||||
|
|
||||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
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 );
|
LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask );
|
||||||
if( tex )
|
if( tex )
|
||||||
{
|
{
|
||||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
|
||||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||||
gGL.getTexUnit(0)->bind(tex, TRUE);
|
gGL.getTexUnit(0)->bind(tex, TRUE);
|
||||||
gl_rect_2d_simple_tex( width, height );
|
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();
|
LLGLTexture* tex = mLocalTextureObject->getImage();
|
||||||
if (tex)
|
if (tex)
|
||||||
{
|
{
|
||||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
|
||||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||||
gGL.getTexUnit(0)->bind(tex);
|
gGL.getTexUnit(0)->bind(tex);
|
||||||
gl_rect_2d_simple_tex( width, height );
|
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
|
// Note: if the first param is a mulitply, multiply against the current buffer's alpha
|
||||||
if( !first_param || !first_param->getMultiplyBlend() )
|
if( !first_param || !first_param->getMultiplyBlend() )
|
||||||
{
|
{
|
||||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
|
||||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||||
|
|
||||||
// Clear the alpha
|
// Clear the alpha
|
||||||
|
|
@ -1328,7 +1319,6 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accumulate alphas
|
// Accumulate alphas
|
||||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
|
||||||
gGL.color4f( 1.f, 1.f, 1.f, 1.f );
|
gGL.color4f( 1.f, 1.f, 1.f, 1.f );
|
||||||
for (LLTexLayerParamAlpha* param : mParamAlphaList)
|
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();
|
LLGLTexture* tex = mLocalTextureObject->getImage();
|
||||||
if( tex && (tex->getComponents() == 4) )
|
if( tex && (tex->getComponents() == 4) )
|
||||||
{
|
{
|
||||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
|
||||||
LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
|
LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
|
||||||
|
|
||||||
gGL.getTexUnit(0)->bind(tex, TRUE);
|
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) )
|
if( (tex->getComponents() == 4) || (tex->getComponents() == 1) )
|
||||||
{
|
{
|
||||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
|
||||||
gGL.getTexUnit(0)->bind(tex, TRUE);
|
gGL.getTexUnit(0)->bind(tex, TRUE);
|
||||||
gl_rect_2d_simple_tex( width, height );
|
gl_rect_2d_simple_tex( width, height );
|
||||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
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 );
|
// Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO );
|
||||||
if ( !is_approx_equal(layer_color.mV[VW], 1.f) )
|
if ( !is_approx_equal(layer_color.mV[VW], 1.f) )
|
||||||
{
|
{
|
||||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
|
||||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||||
gGL.color4fv(layer_color.mV);
|
gGL.color4fv(layer_color.mV);
|
||||||
gl_rect_2d_simple( width, height );
|
gl_rect_2d_simple( width, height );
|
||||||
|
|
@ -1472,7 +1459,14 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // platforms with working drivers...
|
{ // 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
|
else
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther)
|
||||||
mCachedProcessedTexture(pOther.mCachedProcessedTexture),
|
mCachedProcessedTexture(pOther.mCachedProcessedTexture),
|
||||||
mStaticImageTGA(pOther.mStaticImageTGA),
|
mStaticImageTGA(pOther.mStaticImageTGA),
|
||||||
mStaticImageRaw(pOther.mStaticImageRaw),
|
mStaticImageRaw(pOther.mStaticImageRaw),
|
||||||
mNeedsCreateTexture(pOther.mNeedsCreateTexture),
|
mNeedsCreateTexture(pOther.mNeedsCreateTexture.load()),
|
||||||
mStaticImageInvalid(pOther.mStaticImageInvalid),
|
mStaticImageInvalid(pOther.mStaticImageInvalid),
|
||||||
mAvgDistortionVec(pOther.mAvgDistortionVec),
|
mAvgDistortionVec(pOther.mAvgDistortionVec),
|
||||||
mCachedEffectiveWeight(pOther.mCachedEffectiveWeight)
|
mCachedEffectiveWeight(pOther.mCachedEffectiveWeight)
|
||||||
|
|
@ -344,7 +344,6 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
|
||||||
mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
|
mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
|
||||||
gGL.getTexUnit(0)->bind(mCachedProcessedTexture);
|
gGL.getTexUnit(0)->bind(mCachedProcessedTexture);
|
||||||
gl_rect_2d_simple_tex(width, height);
|
gl_rect_2d_simple_tex(width, height);
|
||||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||||
|
|
@ -361,7 +360,6 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
|
||||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||||
gGL.color4f(0.f, 0.f, 0.f, effective_weight);
|
gGL.color4f(0.f, 0.f, 0.f, effective_weight);
|
||||||
gl_rect_2d_simple(width, height);
|
gl_rect_2d_simple(width, height);
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ private:
|
||||||
LLPointer<LLGLTexture> mCachedProcessedTexture;
|
LLPointer<LLGLTexture> mCachedProcessedTexture;
|
||||||
LLPointer<LLImageTGA> mStaticImageTGA;
|
LLPointer<LLImageTGA> mStaticImageTGA;
|
||||||
LLPointer<LLImageRaw> mStaticImageRaw;
|
LLPointer<LLImageRaw> mStaticImageRaw;
|
||||||
BOOL mNeedsCreateTexture;
|
std::atomic<BOOL> mNeedsCreateTexture;
|
||||||
BOOL mStaticImageInvalid;
|
BOOL mStaticImageInvalid;
|
||||||
LL_ALIGN_16(LLVector4a mAvgDistortionVec);
|
LL_ALIGN_16(LLVector4a mAvgDistortionVec);
|
||||||
F32 mCachedEffectiveWeight;
|
F32 mCachedEffectiveWeight;
|
||||||
|
|
|
||||||
|
|
@ -607,40 +607,37 @@ void LLAudioDecodeMgr::Impl::startMoreDecodes()
|
||||||
|
|
||||||
// Kick off a decode
|
// Kick off a decode
|
||||||
mDecodes[decode_id] = LLPointer<LLVorbisDecodeState>(NULL);
|
mDecodes[decode_id] = LLPointer<LLVorbisDecodeState>(NULL);
|
||||||
try
|
bool posted = main_queue->postTo(
|
||||||
{
|
general_queue,
|
||||||
main_queue->postTo(
|
[decode_id]() // Work done on general queue
|
||||||
general_queue,
|
{
|
||||||
[decode_id]() // Work done on general queue
|
LLPointer<LLVorbisDecodeState> decode_state = beginDecodingAndWritingAudio(decode_id);
|
||||||
|
|
||||||
|
if (!decode_state)
|
||||||
{
|
{
|
||||||
LLPointer<LLVorbisDecodeState> decode_state = beginDecodingAndWritingAudio(decode_id);
|
// Audio decode has errored
|
||||||
|
|
||||||
if (!decode_state)
|
|
||||||
{
|
|
||||||
// Audio decode has errored
|
|
||||||
return decode_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disk write of decoded audio is now in progress off-thread
|
|
||||||
return decode_state;
|
return decode_state;
|
||||||
},
|
}
|
||||||
[decode_id, this](LLPointer<LLVorbisDecodeState> decode_state) // Callback to main thread
|
|
||||||
mutable {
|
|
||||||
if (!gAudiop)
|
|
||||||
{
|
|
||||||
// There is no LLAudioEngine anymore. This might happen if
|
|
||||||
// an audio decode is enqueued just before shutdown.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, we can be certain that the pointer to "this"
|
// Disk write of decoded audio is now in progress off-thread
|
||||||
// is valid because the lifetime of "this" is dependent upon
|
return decode_state;
|
||||||
// the lifetime of gAudiop.
|
},
|
||||||
|
[decode_id, this](LLPointer<LLVorbisDecodeState> decode_state) // Callback to main thread
|
||||||
|
mutable {
|
||||||
|
if (!gAudiop)
|
||||||
|
{
|
||||||
|
// There is no LLAudioEngine anymore. This might happen if
|
||||||
|
// an audio decode is enqueued just before shutdown.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
enqueueFinishAudio(decode_id, decode_state);
|
// At this point, we can be certain that the pointer to "this"
|
||||||
});
|
// is valid because the lifetime of "this" is dependent upon
|
||||||
}
|
// the lifetime of gAudiop.
|
||||||
catch (const LLThreadSafeQueueInterrupt&)
|
|
||||||
|
enqueueFinishAudio(decode_id, decode_state);
|
||||||
|
});
|
||||||
|
if (! posted)
|
||||||
{
|
{
|
||||||
// Shutdown
|
// Shutdown
|
||||||
// Consider making processQueue() do a cleanup instead
|
// Consider making processQueue() do a cleanup instead
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ include(Tracy)
|
||||||
|
|
||||||
set(llcommon_SOURCE_FILES
|
set(llcommon_SOURCE_FILES
|
||||||
apply.cpp
|
apply.cpp
|
||||||
|
commoncontrol.cpp
|
||||||
indra_constants.cpp
|
indra_constants.cpp
|
||||||
lazyeventapi.cpp
|
lazyeventapi.cpp
|
||||||
llallocator.cpp
|
llallocator.cpp
|
||||||
|
|
@ -120,6 +121,7 @@ set(llcommon_HEADER_FILES
|
||||||
apply.h
|
apply.h
|
||||||
chrono.h
|
chrono.h
|
||||||
classic_callback.h
|
classic_callback.h
|
||||||
|
commoncontrol.h
|
||||||
ctype_workaround.h
|
ctype_workaround.h
|
||||||
fix_macros.h
|
fix_macros.h
|
||||||
function_types.h
|
function_types.h
|
||||||
|
|
@ -178,6 +180,7 @@ set(llcommon_HEADER_FILES
|
||||||
llinitdestroyclass.h
|
llinitdestroyclass.h
|
||||||
llinitparam.h
|
llinitparam.h
|
||||||
llinstancetracker.h
|
llinstancetracker.h
|
||||||
|
llinstancetrackersubclass.h
|
||||||
llkeybind.h
|
llkeybind.h
|
||||||
llkeythrottle.h
|
llkeythrottle.h
|
||||||
llleap.h
|
llleap.h
|
||||||
|
|
@ -251,6 +254,7 @@ set(llcommon_HEADER_FILES
|
||||||
stdtypes.h
|
stdtypes.h
|
||||||
stringize.h
|
stringize.h
|
||||||
threadpool.h
|
threadpool.h
|
||||||
|
threadpool_fwd.h
|
||||||
threadsafeschedule.h
|
threadsafeschedule.h
|
||||||
timer.h
|
timer.h
|
||||||
tuple.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
|
//static
|
||||||
S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
|
S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
//*****************************************
|
//*****************************************
|
||||||
LLAPRFilePoolScope scope(pool);
|
LLAPRFilePoolScope scope(pool);
|
||||||
apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), APR_READ|APR_BINARY);
|
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
|
//static
|
||||||
S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
|
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;
|
apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
|
||||||
if (offset < 0)
|
if (offset < 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ LLAssetDictionary::LLAssetDictionary()
|
||||||
addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false));
|
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_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_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_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false));
|
||||||
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", 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_RESERVED_6 = 55,
|
||||||
|
|
||||||
AT_SETTINGS = 56, // Collection of settings
|
AT_SETTINGS = 56, // Collection of settings
|
||||||
|
AT_MATERIAL = 57, // Render Material
|
||||||
|
|
||||||
AT_COUNT = 57,
|
AT_COUNT = 58,
|
||||||
|
|
||||||
// +*********************************************************+
|
// +*********************************************************+
|
||||||
// | TO ADD AN ELEMENT TO THIS ENUM: |
|
// | TO ADD AN ELEMENT TO THIS ENUM: |
|
||||||
|
|
|
||||||
|
|
@ -79,9 +79,9 @@ struct LLContextStatus
|
||||||
|
|
||||||
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status);
|
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status);
|
||||||
|
|
||||||
#define dumpStack(tag) \
|
#define dumpStack(tag) \
|
||||||
if (debugLoggingEnabled(tag)) \
|
LL_DEBUGS(tag) << "STACK:\n" \
|
||||||
{ \
|
<< "====================\n" \
|
||||||
LLCallStack cs; \
|
<< LLCallStack() \
|
||||||
LL_DEBUGS(tag) << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL; \
|
<< "====================" \
|
||||||
}
|
<< LL_ENDL;
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,13 @@ thread_local bool gProfilerEnabled = false;
|
||||||
|
|
||||||
#if (TRACY_ENABLE)
|
#if (TRACY_ENABLE)
|
||||||
// Override new/delete for tracy memory profiling
|
// Override new/delete for tracy memory profiling
|
||||||
void *operator new(size_t size)
|
|
||||||
|
void* ll_tracy_new(size_t size)
|
||||||
{
|
{
|
||||||
void* ptr;
|
void* ptr;
|
||||||
if (gProfilerEnabled)
|
if (gProfilerEnabled)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
//LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||||
ptr = (malloc)(size);
|
ptr = (malloc)(size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -57,12 +58,22 @@ void *operator new(size_t size)
|
||||||
return ptr;
|
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);
|
TracyFree(ptr);
|
||||||
if (gProfilerEnabled)
|
if (gProfilerEnabled)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
//LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||||
(free)(ptr);
|
(free)(ptr);
|
||||||
}
|
}
|
||||||
else
|
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
|
// 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
|
// 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.
|
// 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*))
|
void crashdriver(void (*callback)(int*))
|
||||||
{
|
{
|
||||||
// The LLERROR_CRASH macro used to have inline code of the form:
|
// 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
|
#ifdef SHOW_ASSERT
|
||||||
#define llassert(func) llassert_always_msg(func, #func)
|
#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)
|
#define llverify(func) llassert_always_msg(func, #func)
|
||||||
#else
|
#else
|
||||||
#define llassert(func)
|
#define llassert(func)
|
||||||
|
#define llassert_msg(func, msg)
|
||||||
#define llverify(func) do {if (func) {}} while(0)
|
#define llverify(func) do {if (func) {}} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -462,8 +464,31 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
|
||||||
LLError::CallSite& _site(_sites[which]); \
|
LLError::CallSite& _site(_sites[which]); \
|
||||||
lllog_test_()
|
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);
|
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
|
// used by LLERROR_CRASH
|
||||||
void crashdriver(void (*)(int*));
|
void crashdriver(void (*)(int*));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,6 @@
|
||||||
|
|
||||||
#include "llframetimer.h"
|
#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
|
// Static members
|
||||||
//LLTimer LLFrameTimer::sInternalTimer;
|
//LLTimer LLFrameTimer::sInternalTimer;
|
||||||
U64 LLFrameTimer::sStartTotalTime = totalTime();
|
U64 LLFrameTimer::sStartTotalTime = totalTime();
|
||||||
|
|
|
||||||
|
|
@ -104,22 +104,26 @@ public:
|
||||||
return LockStatic()->mMap.size();
|
return LockStatic()->mMap.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// snapshot of std::pair<const KEY, std::shared_ptr<T>> pairs
|
// snapshot of std::pair<const KEY, std::shared_ptr<SUBCLASS>> pairs, for
|
||||||
class snapshot
|
// some SUBCLASS derived from T
|
||||||
|
template <typename SUBCLASS>
|
||||||
|
class snapshot_of
|
||||||
{
|
{
|
||||||
// It's very important that what we store in this snapshot are
|
// It's very important that what we store in this snapshot are
|
||||||
// weak_ptrs, NOT shared_ptrs. That's how we discover whether any
|
// weak_ptrs, NOT shared_ptrs. That's how we discover whether any
|
||||||
// instance has been deleted during the lifespan of a snapshot.
|
// instance has been deleted during the lifespan of a snapshot.
|
||||||
typedef std::vector<std::pair<const KEY, weak_t>> VectorType;
|
typedef std::vector<std::pair<const KEY, weak_t>> VectorType;
|
||||||
// Dereferencing our iterator produces a std::shared_ptr for each
|
// Dereferencing the iterator we publish produces a
|
||||||
// instance that still exists. Since we store weak_ptrs, that involves
|
// std::shared_ptr<SUBCLASS> for each instance that still exists.
|
||||||
// two chained transformations:
|
// 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 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
|
// It is very important that we filter lazily, that is, during
|
||||||
// traversal. Any one of our stored weak_ptrs might expire during
|
// traversal. Any one of our stored weak_ptrs might expire during
|
||||||
// traversal.
|
// 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
|
// 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-
|
// Boost 1.67) trying to use boost::transform_iterator with a hand-
|
||||||
// coded functor, only with actual functions. In my experience, an
|
// coded functor, only with actual functions. In my experience, an
|
||||||
|
|
@ -127,7 +131,7 @@ public:
|
||||||
// result_type typedef. But this works.
|
// result_type typedef. But this works.
|
||||||
static strong_pair strengthen(typename VectorType::value_type& pair)
|
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)
|
static bool dead_skipper(const strong_pair& pair)
|
||||||
{
|
{
|
||||||
|
|
@ -135,7 +139,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
snapshot():
|
snapshot_of():
|
||||||
// populate our vector with a snapshot of (locked!) InstanceMap
|
// populate our vector with a snapshot of (locked!) InstanceMap
|
||||||
// note, this assigns pair<KEY, shared_ptr> to pair<KEY, weak_ptr>
|
// note, this assigns pair<KEY, shared_ptr> to pair<KEY, weak_ptr>
|
||||||
mData(mLock->mMap.begin(), mLock->mMap.end())
|
mData(mLock->mMap.begin(), mLock->mMap.end())
|
||||||
|
|
@ -184,44 +188,51 @@ public:
|
||||||
#endif // LL_WINDOWS
|
#endif // LL_WINDOWS
|
||||||
VectorType mData;
|
VectorType mData;
|
||||||
};
|
};
|
||||||
|
using snapshot = snapshot_of<T>;
|
||||||
|
|
||||||
// iterate over this for references to each instance
|
// iterate over this for references to each SUBCLASS instance
|
||||||
class instance_snapshot: public snapshot
|
template <typename SUBCLASS>
|
||||||
|
class instance_snapshot_of: public snapshot_of<SUBCLASS>
|
||||||
{
|
{
|
||||||
private:
|
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;
|
return *pair.second;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
typedef boost::transform_iterator<decltype(instance_getter)*,
|
typedef boost::transform_iterator<decltype(instance_getter)*,
|
||||||
typename snapshot::iterator> iterator;
|
typename super::iterator> iterator;
|
||||||
iterator begin() { return iterator(snapshot::begin(), instance_getter); }
|
iterator begin() { return iterator(super::begin(), instance_getter); }
|
||||||
iterator end() { return iterator(snapshot::end(), instance_getter); }
|
iterator end() { return iterator(super::end(), instance_getter); }
|
||||||
|
|
||||||
void deleteAll()
|
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();
|
delete it->second.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
using instance_snapshot = instance_snapshot_of<T>;
|
||||||
|
|
||||||
// iterate over this for each key
|
// iterate over this for each key
|
||||||
class key_snapshot: public snapshot
|
template <typename SUBCLASS>
|
||||||
|
class key_snapshot_of: public snapshot_of<SUBCLASS>
|
||||||
{
|
{
|
||||||
private:
|
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;
|
return pair.first;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
typedef boost::transform_iterator<decltype(key_getter)*,
|
typedef boost::transform_iterator<decltype(key_getter)*,
|
||||||
typename snapshot::iterator> iterator;
|
typename super::iterator> iterator;
|
||||||
iterator begin() { return iterator(snapshot::begin(), key_getter); }
|
iterator begin() { return iterator(super::begin(), key_getter); }
|
||||||
iterator end() { return iterator(snapshot::end(), key_getter); }
|
iterator end() { return iterator(super::end(), key_getter); }
|
||||||
};
|
};
|
||||||
|
using key_snapshot = key_snapshot_of<T>;
|
||||||
|
|
||||||
static ptr_t getInstance(const KEY& k)
|
static ptr_t getInstance(const KEY& k)
|
||||||
{
|
{
|
||||||
|
|
@ -368,22 +379,25 @@ public:
|
||||||
return LockStatic()->mSet.size();
|
return LockStatic()->mSet.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// snapshot of std::shared_ptr<T> pointers
|
// snapshot of std::shared_ptr<SUBCLASS> pointers
|
||||||
class snapshot
|
template <typename SUBCLASS>
|
||||||
|
class snapshot_of
|
||||||
{
|
{
|
||||||
// It's very important that what we store in this snapshot are
|
// It's very important that what we store in this snapshot are
|
||||||
// weak_ptrs, NOT shared_ptrs. That's how we discover whether any
|
// weak_ptrs, NOT shared_ptrs. That's how we discover whether any
|
||||||
// instance has been deleted during the lifespan of a snapshot.
|
// instance has been deleted during the lifespan of a snapshot.
|
||||||
typedef std::vector<weak_t> VectorType;
|
typedef std::vector<weak_t> VectorType;
|
||||||
// Dereferencing our iterator produces a std::shared_ptr for each
|
// Dereferencing the iterator we publish produces a
|
||||||
// instance that still exists. Since we store weak_ptrs, that involves
|
// std::shared_ptr<SUBCLASS> for each instance that still exists.
|
||||||
// two chained transformations:
|
// Since we store weak_ptrs, that involves two chained
|
||||||
|
// transformations:
|
||||||
// - a transform_iterator to lock the weak_ptr and return a shared_ptr
|
// - 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 that has become invalid
|
||||||
typedef std::shared_ptr<T> strong_ptr;
|
// 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)
|
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)
|
static bool dead_skipper(const strong_ptr& ptr)
|
||||||
{
|
{
|
||||||
|
|
@ -391,7 +405,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
snapshot():
|
snapshot_of():
|
||||||
// populate our vector with a snapshot of (locked!) InstanceSet
|
// populate our vector with a snapshot of (locked!) InstanceSet
|
||||||
// note, this assigns stored shared_ptrs to weak_ptrs for snapshot
|
// note, this assigns stored shared_ptrs to weak_ptrs for snapshot
|
||||||
mData(mLock->mSet.begin(), mLock->mSet.end())
|
mData(mLock->mSet.begin(), mLock->mSet.end())
|
||||||
|
|
@ -437,22 +451,33 @@ public:
|
||||||
#endif // LL_WINDOWS
|
#endif // LL_WINDOWS
|
||||||
VectorType mData;
|
VectorType mData;
|
||||||
};
|
};
|
||||||
|
using snapshot = snapshot_of<T>;
|
||||||
|
|
||||||
// iterate over this for references to each instance
|
// 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;
|
private:
|
||||||
iterator begin() { return iterator(snapshot::begin()); }
|
using super = snapshot_of<SUBCLASS>;
|
||||||
iterator end() { return iterator(snapshot::end()); }
|
|
||||||
|
public:
|
||||||
|
typedef boost::indirect_iterator<typename super::iterator> iterator;
|
||||||
|
iterator begin() { return iterator(super::begin()); }
|
||||||
|
iterator end() { return iterator(super::end()); }
|
||||||
|
|
||||||
void deleteAll()
|
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();
|
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:
|
protected:
|
||||||
LLInstanceTracker()
|
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 <sys/types.h>
|
||||||
# include <mach/task.h>
|
# include <mach/task.h>
|
||||||
# include <mach/mach_init.h>
|
# include <mach/mach_init.h>
|
||||||
|
#include <mach/mach_host.h>
|
||||||
#elif LL_LINUX
|
#elif LL_LINUX
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -109,6 +110,50 @@ void LLMemory::updateMemoryInfo()
|
||||||
{
|
{
|
||||||
sAvailPhysicalMemInKB = U32Kilobytes(0);
|
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
|
#else
|
||||||
//not valid for other systems for now.
|
//not valid for other systems for now.
|
||||||
sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS());
|
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
|
#if MUTEX_DEBUG
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
@ -61,7 +62,7 @@ protected:
|
||||||
mutable LLThread::id_t mLockingThread;
|
mutable LLThread::id_t mLockingThread;
|
||||||
|
|
||||||
#if MUTEX_DEBUG
|
#if MUTEX_DEBUG
|
||||||
std::map<LLThread::id_t, BOOL> mIsLocked;
|
std::unordered_map<LLThread::id_t, BOOL> mIsLocked;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -340,4 +340,28 @@ private:
|
||||||
bool mStayUnique;
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,12 @@ extern thread_local bool gProfilerEnabled;
|
||||||
#define TRACY_ONLY_IPV4 1
|
#define TRACY_ONLY_IPV4 1
|
||||||
#include "Tracy.hpp"
|
#include "Tracy.hpp"
|
||||||
|
|
||||||
// Mutually exclusive with detailed memory tracing
|
// Enable OpenGL profiling
|
||||||
#define LL_PROFILER_ENABLE_TRACY_OPENGL 0
|
#define LL_PROFILER_ENABLE_TRACY_OPENGL 0
|
||||||
|
|
||||||
|
// Enable RenderDoc labeling
|
||||||
|
#define LL_PROFILER_ENABLE_RENDER_DOC 0
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY
|
#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_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_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_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
|
#endif
|
||||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER
|
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER
|
||||||
#define LL_PROFILER_FRAME_END
|
#define LL_PROFILER_FRAME_END
|
||||||
#define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
|
#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_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(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_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)
|
#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_ERR(name) (void)(name); // Not supported
|
||||||
#define LL_PROFILE_ZONE_INFO(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_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
|
#endif
|
||||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
|
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
|
||||||
#define LL_PROFILER_FRAME_END FrameMark
|
#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_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_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_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
|
#endif
|
||||||
#else
|
#else
|
||||||
#define LL_PROFILER_FRAME_END
|
#define LL_PROFILER_FRAME_END
|
||||||
#define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
|
#define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name)
|
||||||
#endif // LL_PROFILER
|
#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"
|
#include "llprofilercategories.h"
|
||||||
|
|
||||||
#endif // LL_PROFILER_H
|
#endif // LL_PROFILER_H
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
#define LL_PROFILER_CATEGORY_ENABLE_LOGGING 1
|
#define LL_PROFILER_CATEGORY_ENABLE_LOGGING 1
|
||||||
#define LL_PROFILER_CATEGORY_ENABLE_MATERIAL 1
|
#define LL_PROFILER_CATEGORY_ENABLE_MATERIAL 1
|
||||||
#define LL_PROFILER_CATEGORY_ENABLE_MEDIA 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_NETWORK 1
|
||||||
#define LL_PROFILER_CATEGORY_ENABLE_OCTREE 1
|
#define LL_PROFILER_CATEGORY_ENABLE_OCTREE 1
|
||||||
#define LL_PROFILER_CATEGORY_ENABLE_PIPELINE 1
|
#define LL_PROFILER_CATEGORY_ENABLE_PIPELINE 1
|
||||||
|
|
|
||||||
|
|
@ -26,20 +26,26 @@
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
#include "llqueuedthread.h"
|
#include "llqueuedthread.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include "llstl.h"
|
#include "llstl.h"
|
||||||
#include "lltimer.h" // ms_sleep()
|
#include "lltimer.h" // ms_sleep()
|
||||||
#include "lltracethreadrecorder.h"
|
#include "llmutex.h"
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
// MAIN THREAD
|
// MAIN THREAD
|
||||||
LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) :
|
LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) :
|
||||||
LLThread(name),
|
LLThread(name),
|
||||||
mThreaded(threaded),
|
mIdleThread(TRUE),
|
||||||
mIdleThread(TRUE),
|
mNextHandle(0),
|
||||||
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 (mThreaded)
|
||||||
{
|
{
|
||||||
if(should_pause)
|
if(should_pause)
|
||||||
|
|
@ -69,6 +75,11 @@ void LLQueuedThread::shutdown()
|
||||||
unpause(); // MAIN THREAD
|
unpause(); // MAIN THREAD
|
||||||
if (mThreaded)
|
if (mThreaded)
|
||||||
{
|
{
|
||||||
|
if (mRequestQueue.size() == 0)
|
||||||
|
{
|
||||||
|
mRequestQueue.close();
|
||||||
|
}
|
||||||
|
|
||||||
S32 timeout = 100;
|
S32 timeout = 100;
|
||||||
for ( ; timeout>0; timeout--)
|
for ( ; timeout>0; timeout--)
|
||||||
{
|
{
|
||||||
|
|
@ -104,6 +115,8 @@ void LLQueuedThread::shutdown()
|
||||||
{
|
{
|
||||||
LL_WARNS() << "~LLQueuedThread() called with active requests: " << active_count << LL_ENDL;
|
LL_WARNS() << "~LLQueuedThread() called with active requests: " << active_count << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mRequestQueue.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
@ -112,6 +125,7 @@ void LLQueuedThread::shutdown()
|
||||||
// virtual
|
// virtual
|
||||||
size_t LLQueuedThread::update(F32 max_time_ms)
|
size_t LLQueuedThread::update(F32 max_time_ms)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
if (!mStarted)
|
if (!mStarted)
|
||||||
{
|
{
|
||||||
if (!mThreaded)
|
if (!mThreaded)
|
||||||
|
|
@ -125,29 +139,34 @@ size_t LLQueuedThread::update(F32 max_time_ms)
|
||||||
|
|
||||||
size_t LLQueuedThread::updateQueue(F32 max_time_ms)
|
size_t LLQueuedThread::updateQueue(F32 max_time_ms)
|
||||||
{
|
{
|
||||||
F64 max_time = (F64)max_time_ms * .001;
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
LLTimer timer;
|
|
||||||
size_t pending = 1;
|
|
||||||
|
|
||||||
// Frame Update
|
// Frame Update
|
||||||
if (mThreaded)
|
if (mThreaded)
|
||||||
{
|
{
|
||||||
pending = getPending();
|
// schedule a call to threadedUpdate for every call to updateQueue
|
||||||
if(pending > 0)
|
if (!isQuitting())
|
||||||
|
{
|
||||||
|
mRequestQueue.post([=]()
|
||||||
|
{
|
||||||
|
LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qt - update");
|
||||||
|
mIdleThread = FALSE;
|
||||||
|
threadedUpdate();
|
||||||
|
mIdleThread = TRUE;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getPending() > 0)
|
||||||
{
|
{
|
||||||
unpause();
|
unpause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (pending > 0)
|
mRequestQueue.runFor(std::chrono::microseconds((int) (max_time_ms*1000.f)));
|
||||||
{
|
threadedUpdate();
|
||||||
pending = processNextRequest();
|
|
||||||
if (max_time && timer.getElapsedTimeF64() > max_time)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return pending;
|
return getPending();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLQueuedThread::incQueue()
|
void LLQueuedThread::incQueue()
|
||||||
|
|
@ -166,11 +185,7 @@ void LLQueuedThread::incQueue()
|
||||||
// May be called from any thread
|
// May be called from any thread
|
||||||
size_t LLQueuedThread::getPending()
|
size_t LLQueuedThread::getPending()
|
||||||
{
|
{
|
||||||
size_t res;
|
return mRequestQueue.size();
|
||||||
lockData();
|
|
||||||
res = mRequestQueue.size();
|
|
||||||
unlockData();
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MAIN thread
|
// MAIN thread
|
||||||
|
|
@ -195,35 +210,28 @@ void LLQueuedThread::waitOnPending()
|
||||||
// MAIN thread
|
// MAIN thread
|
||||||
void LLQueuedThread::printQueueStats()
|
void LLQueuedThread::printQueueStats()
|
||||||
{
|
{
|
||||||
lockData();
|
U32 size = mRequestQueue.size();
|
||||||
if (!mRequestQueue.empty())
|
if (size > 0)
|
||||||
{
|
{
|
||||||
QueuedRequest *req = *mRequestQueue.begin();
|
LL_INFOS() << llformat("Pending Requests:%d ", mRequestQueue.size()) << LL_ENDL;
|
||||||
LL_INFOS() << llformat("Pending Requests:%d Current status:%d", mRequestQueue.size(), req->getStatus()) << LL_ENDL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LL_INFOS() << "Queued Thread Idle" << LL_ENDL;
|
LL_INFOS() << "Queued Thread Idle" << LL_ENDL;
|
||||||
}
|
}
|
||||||
unlockData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MAIN thread
|
// MAIN thread
|
||||||
LLQueuedThread::handle_t LLQueuedThread::generateHandle()
|
LLQueuedThread::handle_t LLQueuedThread::generateHandle()
|
||||||
{
|
{
|
||||||
lockData();
|
U32 res = ++mNextHandle;
|
||||||
while ((mNextHandle == nullHandle()) || (mRequestHash.find(mNextHandle)))
|
|
||||||
{
|
|
||||||
mNextHandle++;
|
|
||||||
}
|
|
||||||
const LLQueuedThread::handle_t res = mNextHandle++;
|
|
||||||
unlockData();
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MAIN thread
|
// MAIN thread
|
||||||
bool LLQueuedThread::addRequest(QueuedRequest* req)
|
bool LLQueuedThread::addRequest(QueuedRequest* req)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
if (mStatus == QUITTING)
|
if (mStatus == QUITTING)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -231,14 +239,14 @@ bool LLQueuedThread::addRequest(QueuedRequest* req)
|
||||||
|
|
||||||
lockData();
|
lockData();
|
||||||
req->setStatus(STATUS_QUEUED);
|
req->setStatus(STATUS_QUEUED);
|
||||||
mRequestQueue.insert(req);
|
mRequestHash.insert(req);
|
||||||
mRequestHash.insert(req);
|
|
||||||
#if _DEBUG
|
#if _DEBUG
|
||||||
// LL_INFOS() << llformat("LLQueuedThread::Added req [%08d]",handle) << LL_ENDL;
|
// LL_INFOS() << llformat("LLQueuedThread::Added req [%08d]",handle) << LL_ENDL;
|
||||||
#endif
|
#endif
|
||||||
unlockData();
|
unlockData();
|
||||||
|
|
||||||
incQueue();
|
llassert(!mDataLock->isSelfLocked());
|
||||||
|
mRequestQueue.post([this, req]() { processRequest(req); });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -246,6 +254,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req)
|
||||||
// MAIN thread
|
// MAIN thread
|
||||||
bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_complete)
|
bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_complete)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
llassert (handle != nullHandle());
|
llassert (handle != nullHandle());
|
||||||
bool res = false;
|
bool res = false;
|
||||||
bool waspaused = isPaused();
|
bool waspaused = isPaused();
|
||||||
|
|
@ -312,6 +321,7 @@ LLQueuedThread::status_t LLQueuedThread::getRequestStatus(handle_t handle)
|
||||||
|
|
||||||
void LLQueuedThread::abortRequest(handle_t handle, bool autocomplete)
|
void LLQueuedThread::abortRequest(handle_t handle, bool autocomplete)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||||
lockData();
|
lockData();
|
||||||
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
||||||
if (req)
|
if (req)
|
||||||
|
|
@ -333,30 +343,9 @@ void LLQueuedThread::setFlags(handle_t handle, U32 flags)
|
||||||
unlockData();
|
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)
|
bool LLQueuedThread::completeRequest(handle_t handle)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
bool res = false;
|
bool res = false;
|
||||||
lockData();
|
lockData();
|
||||||
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
||||||
|
|
@ -399,88 +388,120 @@ bool LLQueuedThread::check()
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// Runs on its OWN thread
|
// 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
|
// Get next request from pool
|
||||||
lockData();
|
lockData();
|
||||||
|
|
||||||
while(1)
|
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
|
||||||
{
|
{
|
||||||
req = NULL;
|
LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qtpr - abort");
|
||||||
if (mRequestQueue.empty())
|
req->setStatus(STATUS_ABORTED);
|
||||||
|
req->finishRequest(false);
|
||||||
|
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||||
{
|
{
|
||||||
break;
|
mRequestHash.erase(req);
|
||||||
}
|
req->deleteRequest();
|
||||||
req = *mRequestQueue.begin();
|
|
||||||
mRequestQueue.erase(mRequestQueue.begin());
|
|
||||||
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
|
|
||||||
{
|
|
||||||
req->setStatus(STATUS_ABORTED);
|
|
||||||
req->finishRequest(false);
|
|
||||||
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
|
||||||
{
|
|
||||||
mRequestHash.erase(req);
|
|
||||||
req->deleteRequest();
|
|
||||||
// check();
|
// check();
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
llassert_always(req->getStatus() == STATUS_QUEUED);
|
unlockData();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
U32 start_priority = 0 ;
|
else
|
||||||
if (req)
|
{
|
||||||
{
|
llassert_always(req->getStatus() == STATUS_QUEUED);
|
||||||
req->setStatus(STATUS_INPROGRESS);
|
|
||||||
start_priority = req->getPriority();
|
|
||||||
}
|
|
||||||
unlockData();
|
|
||||||
|
|
||||||
// This is the only place we will call req->setStatus() after
|
if (req)
|
||||||
// it has initially been seet to STATUS_QUEUED, so it is
|
{
|
||||||
// safe to access req.
|
req->setStatus(STATUS_INPROGRESS);
|
||||||
if (req)
|
}
|
||||||
{
|
unlockData();
|
||||||
// process request
|
|
||||||
bool complete = req->processRequest();
|
|
||||||
|
|
||||||
if (complete)
|
// This is the only place we will call req->setStatus() after
|
||||||
{
|
// it has initially been seet to STATUS_QUEUED, so it is
|
||||||
lockData();
|
// safe to access req.
|
||||||
req->setStatus(STATUS_COMPLETE);
|
if (req)
|
||||||
req->finishRequest(true);
|
{
|
||||||
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
// process request
|
||||||
{
|
bool complete = req->processRequest();
|
||||||
mRequestHash.erase(req);
|
|
||||||
req->deleteRequest();
|
|
||||||
// check();
|
|
||||||
}
|
|
||||||
unlockData();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lockData();
|
|
||||||
req->setStatus(STATUS_QUEUED);
|
|
||||||
mRequestQueue.insert(req);
|
|
||||||
unlockData();
|
|
||||||
if (mThreaded && start_priority < PRIORITY_NORMAL)
|
|
||||||
{
|
|
||||||
ms_sleep(1); // sleep the thread a little
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LLTrace::get_thread_recorder()->pushToParent();
|
if (complete)
|
||||||
}
|
{
|
||||||
|
LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qtpr - complete");
|
||||||
|
lockData();
|
||||||
|
req->setStatus(STATUS_COMPLETE);
|
||||||
|
req->finishRequest(true);
|
||||||
|
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||||
|
{
|
||||||
|
mRequestHash.erase(req);
|
||||||
|
req->deleteRequest();
|
||||||
|
// 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);
|
||||||
|
|
||||||
return getPending();
|
unlockData();
|
||||||
|
|
||||||
|
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,
|
||||||
|
[=]()
|
||||||
|
{
|
||||||
|
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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mIdleThread = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
bool LLQueuedThread::runCondition()
|
bool LLQueuedThread::runCondition()
|
||||||
{
|
{
|
||||||
// mRunCondition must be locked here
|
// mRunCondition must be locked here
|
||||||
if (mRequestQueue.empty() && mIdleThread)
|
if (mRequestQueue.size() == 0 && mIdleThread)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -494,18 +515,13 @@ void LLQueuedThread::run()
|
||||||
startThread();
|
startThread();
|
||||||
mStarted = TRUE;
|
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.
|
// this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state.
|
||||||
checkPause();
|
checkPause();
|
||||||
|
|
||||||
if (isQuitting())
|
|
||||||
{
|
|
||||||
LLTrace::get_thread_recorder()->pushToParent();
|
|
||||||
endThread();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mIdleThread = FALSE;
|
mIdleThread = FALSE;
|
||||||
|
|
||||||
threadedUpdate();
|
threadedUpdate();
|
||||||
|
|
@ -514,12 +530,18 @@ void LLQueuedThread::run()
|
||||||
|
|
||||||
if (pending_work == 0)
|
if (pending_work == 0)
|
||||||
{
|
{
|
||||||
|
//LL_PROFILE_ZONE_NAMED("LLQueuedThread - sleep");
|
||||||
mIdleThread = TRUE;
|
mIdleThread = TRUE;
|
||||||
ms_sleep(1);
|
//ms_sleep(1);
|
||||||
}
|
}
|
||||||
//LLThread::yield(); // thread should yield after each request
|
//LLThread::yield(); // thread should yield after each request
|
||||||
}
|
}*/
|
||||||
|
mRequestQueue.runUntilClose();
|
||||||
|
|
||||||
|
endThread();
|
||||||
LL_INFOS() << "LLQueuedThread " << mName << " EXITING." << LL_ENDL;
|
LL_INFOS() << "LLQueuedThread " << mName << " EXITING." << LL_ENDL;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// 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),
|
LLSimpleHashEntry<LLQueuedThread::handle_t>(handle),
|
||||||
mStatus(STATUS_UNKNOWN),
|
mStatus(STATUS_UNKNOWN),
|
||||||
mPriority(priority),
|
|
||||||
mFlags(flags)
|
mFlags(flags)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
#include "llthread.h"
|
#include "llthread.h"
|
||||||
#include "llsimplehash.h"
|
#include "llsimplehash.h"
|
||||||
|
#include "workqueue.h"
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// Note: ~LLQueuedThread is O(N) N=# of queued threads, assumed to be small
|
// 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:
|
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 {
|
enum status_t {
|
||||||
STATUS_EXPIRED = -1,
|
STATUS_EXPIRED = -1,
|
||||||
STATUS_UNKNOWN = 0,
|
STATUS_UNKNOWN = 0,
|
||||||
|
|
@ -82,27 +74,16 @@ public:
|
||||||
virtual ~QueuedRequest(); // use deleteRequest()
|
virtual ~QueuedRequest(); // use deleteRequest()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QueuedRequest(handle_t handle, U32 priority, U32 flags = 0);
|
QueuedRequest(handle_t handle, U32 flags = 0);
|
||||||
|
|
||||||
status_t getStatus()
|
status_t getStatus()
|
||||||
{
|
{
|
||||||
return mStatus;
|
return mStatus;
|
||||||
}
|
}
|
||||||
U32 getPriority() const
|
|
||||||
{
|
|
||||||
return mPriority;
|
|
||||||
}
|
|
||||||
U32 getFlags() const
|
U32 getFlags() const
|
||||||
{
|
{
|
||||||
return mFlags;
|
return mFlags;
|
||||||
}
|
}
|
||||||
bool higherPriority(const QueuedRequest& second) const
|
|
||||||
{
|
|
||||||
if ( mPriority == second.mPriority)
|
|
||||||
return mHashKey < second.mHashKey;
|
|
||||||
else
|
|
||||||
return mPriority > second.mPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
status_t setStatus(status_t newstatus)
|
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 finishRequest(bool completed); // Always called from thread after request has completed or aborted
|
||||||
virtual void deleteRequest(); // Only method to delete a request
|
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:
|
protected:
|
||||||
LLAtomicBase<status_t> mStatus;
|
LLAtomicBase<status_t> mStatus;
|
||||||
U32 mPriority;
|
|
||||||
U32 mFlags;
|
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:
|
public:
|
||||||
|
|
@ -167,7 +131,7 @@ private:
|
||||||
protected:
|
protected:
|
||||||
handle_t generateHandle();
|
handle_t generateHandle();
|
||||||
bool addRequest(QueuedRequest* req);
|
bool addRequest(QueuedRequest* req);
|
||||||
size_t processNextRequest(void);
|
void processRequest(QueuedRequest* req);
|
||||||
void incQueue();
|
void incQueue();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -186,7 +150,6 @@ public:
|
||||||
status_t getRequestStatus(handle_t handle);
|
status_t getRequestStatus(handle_t handle);
|
||||||
void abortRequest(handle_t handle, bool autocomplete);
|
void abortRequest(handle_t handle, bool autocomplete);
|
||||||
void setFlags(handle_t handle, U32 flags);
|
void setFlags(handle_t handle, U32 flags);
|
||||||
void setPriority(handle_t handle, U32 priority);
|
|
||||||
bool completeRequest(handle_t handle);
|
bool completeRequest(handle_t handle);
|
||||||
// This is public for support classes like LLWorkerThread,
|
// This is public for support classes like LLWorkerThread,
|
||||||
// but generally the methods above should be used.
|
// 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()
|
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
|
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;
|
//typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
|
||||||
request_queue_t mRequestQueue;
|
//request_queue_t mRequestQueue;
|
||||||
|
LL::WorkQueue mRequestQueue;
|
||||||
|
LL::WorkQueue::weak_t mMainQueue;
|
||||||
|
|
||||||
enum { REQUEST_HASH_SIZE = 512 }; // must be power of 2
|
enum { REQUEST_HASH_SIZE = 512 }; // must be power of 2
|
||||||
typedef LLSimpleHash<handle_t, REQUEST_HASH_SIZE> request_hash_t;
|
typedef LLSimpleHash<handle_t, REQUEST_HASH_SIZE> request_hash_t;
|
||||||
|
|
|
||||||
|
|
@ -475,6 +475,7 @@ LLSDNotationParser::~LLSDNotationParser()
|
||||||
// virtual
|
// virtual
|
||||||
S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
|
S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||||
// map: { string:object, string:object }
|
// map: { string:object, string:object }
|
||||||
// array: [ object, object, object ]
|
// array: [ object, object, object ]
|
||||||
// undef: !
|
// 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
|
S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||||
// map: { string:object, string:object }
|
// map: { string:object, string:object }
|
||||||
map = LLSD::emptyMap();
|
map = LLSD::emptyMap();
|
||||||
S32 parse_count = 0;
|
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
|
S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||||
// array: [ object, object, object ]
|
// array: [ object, object, object ]
|
||||||
array = LLSD::emptyArray();
|
array = LLSD::emptyArray();
|
||||||
S32 parse_count = 0;
|
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
|
bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||||
std::string value;
|
std::string value;
|
||||||
auto count = deserialize_string(istr, value, mMaxBytesLeft);
|
auto count = deserialize_string(istr, value, mMaxBytesLeft);
|
||||||
if(PARSE_FAILURE == count) return false;
|
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
|
bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||||
// binary: b##"ff3120ab1"
|
// binary: b##"ff3120ab1"
|
||||||
// or: b(len)"..."
|
// or: b(len)"..."
|
||||||
|
|
||||||
|
|
@ -945,6 +950,7 @@ LLSDBinaryParser::~LLSDBinaryParser()
|
||||||
// virtual
|
// virtual
|
||||||
S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
|
S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||||
/**
|
/**
|
||||||
* Undefined: '!'<br>
|
* Undefined: '!'<br>
|
||||||
* Boolean: '1' for true '0' for false<br>
|
* Boolean: '1' for true '0' for false<br>
|
||||||
|
|
|
||||||
|
|
@ -923,6 +923,8 @@ void LLSDXMLParser::parsePart(const char *buf, llssize len)
|
||||||
// virtual
|
// virtual
|
||||||
S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data, S32 max_depth) const
|
S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data, S32 max_depth) const
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||||
|
|
||||||
#ifdef XML_PARSER_PERFORMANCE_TESTS
|
#ifdef XML_PARSER_PERFORMANCE_TESTS
|
||||||
XML_Timer timer( &parseTime );
|
XML_Timer timer( &parseTime );
|
||||||
#endif // XML_PARSER_PERFORMANCE_TESTS
|
#endif // XML_PARSER_PERFORMANCE_TESTS
|
||||||
|
|
|
||||||
|
|
@ -771,20 +771,28 @@ static U32Kilobytes LLMemoryAdjustKBResult(U32Kilobytes inKB)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LL_DARWIN
|
||||||
|
// static
|
||||||
|
U32Kilobytes LLMemoryInfo::getHardwareMemSize()
|
||||||
|
{
|
||||||
|
// This might work on Linux as well. Someone check...
|
||||||
|
uint64_t phys = 0;
|
||||||
|
int mib[2] = { CTL_HW, HW_MEMSIZE };
|
||||||
|
|
||||||
|
size_t len = sizeof(phys);
|
||||||
|
sysctl(mib, 2, &phys, &len, NULL, 0);
|
||||||
|
|
||||||
|
return U64Bytes(phys);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const
|
U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const
|
||||||
{
|
{
|
||||||
#if LL_WINDOWS
|
#if LL_WINDOWS
|
||||||
return LLMemoryAdjustKBResult(U32Kilobytes(mStatsMap["Total Physical KB"].asInteger()));
|
return LLMemoryAdjustKBResult(U32Kilobytes(mStatsMap["Total Physical KB"].asInteger()));
|
||||||
|
|
||||||
#elif LL_DARWIN
|
#elif LL_DARWIN
|
||||||
// This might work on Linux as well. Someone check...
|
return getHardwareMemSize();
|
||||||
uint64_t phys = 0;
|
|
||||||
int mib[2] = { CTL_HW, HW_MEMSIZE };
|
|
||||||
|
|
||||||
size_t len = sizeof(phys);
|
|
||||||
sysctl(mib, 2, &phys, &len, NULL, 0);
|
|
||||||
|
|
||||||
return U64Bytes(phys);
|
|
||||||
|
|
||||||
#elif LL_LINUX
|
#elif LL_LINUX
|
||||||
U64 phys = 0;
|
U64 phys = 0;
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,9 @@ public:
|
||||||
void stream(std::ostream& s) const; ///< output text info to s
|
void stream(std::ostream& s) const; ///< output text info to s
|
||||||
|
|
||||||
U32Kilobytes getPhysicalMemoryKB() const;
|
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.
|
//get the available memory infomation in KiloBytes.
|
||||||
static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb);
|
static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb);
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
|
|
||||||
#ifdef LL_WINDOWS
|
#ifdef LL_WINDOWS
|
||||||
|
|
||||||
const DWORD MS_VC_EXCEPTION=0x406D1388;
|
const DWORD MS_VC_EXCEPTION=0x406D1388;
|
||||||
|
|
||||||
#pragma pack(push,8)
|
#pragma pack(push,8)
|
||||||
|
|
@ -133,6 +134,15 @@ void LLThread::threadRun()
|
||||||
{
|
{
|
||||||
#ifdef LL_WINDOWS
|
#ifdef LL_WINDOWS
|
||||||
set_thread_name(-1, mName.c_str());
|
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
|
#endif
|
||||||
|
|
||||||
LL_PROFILER_SET_THREAD_NAME( mName.c_str() );
|
LL_PROFILER_SET_THREAD_NAME( mName.c_str() );
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,9 @@
|
||||||
|
|
||||||
#include "u64.h"
|
#include "u64.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#if LL_WINDOWS
|
#if LL_WINDOWS
|
||||||
# include "llwin32headerslean.h"
|
# include "llwin32headerslean.h"
|
||||||
#elif LL_LINUX || LL_DARWIN
|
#elif LL_LINUX || LL_DARWIN
|
||||||
|
|
@ -62,9 +65,18 @@ LLTimer* LLTimer::sTimer = NULL;
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
#if LL_WINDOWS
|
#if LL_WINDOWS
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
void ms_sleep(U32 ms)
|
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)
|
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));
|
ms_sleep((U32)(us / 1000));
|
||||||
return 0;
|
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
|
#elif LL_LINUX || LL_DARWIN
|
||||||
static void _sleep_loop(struct timespec& thiswait)
|
static void _sleep_loop(struct timespec& thiswait)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -73,6 +73,7 @@ void LLWorkerThread::clearDeleteList()
|
||||||
{
|
{
|
||||||
worker->mRequestHandle = LLWorkerThread::nullHandle();
|
worker->mRequestHandle = LLWorkerThread::nullHandle();
|
||||||
worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK);
|
worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK);
|
||||||
|
worker->clearFlags(LLWorkerClass::WCF_WORKING);
|
||||||
delete worker;
|
delete worker;
|
||||||
}
|
}
|
||||||
mDeleteList.clear() ;
|
mDeleteList.clear() ;
|
||||||
|
|
@ -97,6 +98,7 @@ size_t LLWorkerThread::update(F32 max_time_ms)
|
||||||
{
|
{
|
||||||
if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED))
|
if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED))
|
||||||
{
|
{
|
||||||
|
worker->setFlags(LLWorkerClass::WCF_DELETE_REQUESTED);
|
||||||
delete_list.push_back(worker);
|
delete_list.push_back(worker);
|
||||||
mDeleteList.erase(curiter);
|
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();
|
handle_t handle = generateHandle();
|
||||||
|
|
||||||
WorkRequest* req = new WorkRequest(handle, priority, workerclass, param);
|
WorkRequest* req = new WorkRequest(handle, workerclass, param);
|
||||||
|
|
||||||
bool res = addRequest(req);
|
bool res = addRequest(req);
|
||||||
if (!res)
|
if (!res)
|
||||||
|
|
@ -157,8 +159,8 @@ void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass)
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// Runs on its OWN thread
|
// Runs on its OWN thread
|
||||||
|
|
||||||
LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param) :
|
LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param) :
|
||||||
LLQueuedThread::QueuedRequest(handle, priority),
|
LLQueuedThread::QueuedRequest(handle),
|
||||||
mWorkerClass(workerclass),
|
mWorkerClass(workerclass),
|
||||||
mParam(param)
|
mParam(param)
|
||||||
{
|
{
|
||||||
|
|
@ -177,6 +179,7 @@ void LLWorkerThread::WorkRequest::deleteRequest()
|
||||||
// virtual
|
// virtual
|
||||||
bool LLWorkerThread::WorkRequest::processRequest()
|
bool LLWorkerThread::WorkRequest::processRequest()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
LLWorkerClass* workerclass = getWorkerClass();
|
LLWorkerClass* workerclass = getWorkerClass();
|
||||||
workerclass->setWorking(true);
|
workerclass->setWorking(true);
|
||||||
bool complete = workerclass->doWork(getParam());
|
bool complete = workerclass->doWork(getParam());
|
||||||
|
|
@ -187,6 +190,7 @@ bool LLWorkerThread::WorkRequest::processRequest()
|
||||||
// virtual
|
// virtual
|
||||||
void LLWorkerThread::WorkRequest::finishRequest(bool completed)
|
void LLWorkerThread::WorkRequest::finishRequest(bool completed)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
LLWorkerClass* workerclass = getWorkerClass();
|
LLWorkerClass* workerclass = getWorkerClass();
|
||||||
workerclass->finishWork(getParam(), completed);
|
workerclass->finishWork(getParam(), completed);
|
||||||
U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED);
|
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),
|
: mWorkerThread(workerthread),
|
||||||
mWorkerClassName(name),
|
mWorkerClassName(name),
|
||||||
mRequestHandle(LLWorkerThread::nullHandle()),
|
mRequestHandle(LLWorkerThread::nullHandle()),
|
||||||
mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
|
|
||||||
mMutex(),
|
mMutex(),
|
||||||
mWorkFlags(0)
|
mWorkFlags(0)
|
||||||
{
|
{
|
||||||
|
|
@ -289,7 +292,7 @@ bool LLWorkerClass::yield()
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
// calls startWork, adds doWork() to queue
|
// calls startWork, adds doWork() to queue
|
||||||
void LLWorkerClass::addWork(S32 param, U32 priority)
|
void LLWorkerClass::addWork(S32 param)
|
||||||
{
|
{
|
||||||
mMutex.lock();
|
mMutex.lock();
|
||||||
llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK)));
|
llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK)));
|
||||||
|
|
@ -303,7 +306,7 @@ void LLWorkerClass::addWork(S32 param, U32 priority)
|
||||||
startWork(param);
|
startWork(param);
|
||||||
clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED);
|
clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED);
|
||||||
setFlags(WCF_HAVE_WORK);
|
setFlags(WCF_HAVE_WORK);
|
||||||
mRequestHandle = mWorkerThread->addWorkRequest(this, param, priority);
|
mRequestHandle = mWorkerThread->addWorkRequest(this, param);
|
||||||
mMutex.unlock();
|
mMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,7 +321,6 @@ void LLWorkerClass::abortWork(bool autocomplete)
|
||||||
if (mRequestHandle != LLWorkerThread::nullHandle())
|
if (mRequestHandle != LLWorkerThread::nullHandle())
|
||||||
{
|
{
|
||||||
mWorkerThread->abortRequest(mRequestHandle, autocomplete);
|
mWorkerThread->abortRequest(mRequestHandle, autocomplete);
|
||||||
mWorkerThread->setPriority(mRequestHandle, LLQueuedThread::PRIORITY_IMMEDIATE);
|
|
||||||
setFlags(WCF_ABORT_REQUESTED);
|
setFlags(WCF_ABORT_REQUESTED);
|
||||||
}
|
}
|
||||||
mMutex.unlock();
|
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()
|
virtual ~WorkRequest(); // use deleteRequest()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param);
|
WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param);
|
||||||
|
|
||||||
S32 getParam()
|
S32 getParam()
|
||||||
{
|
{
|
||||||
|
|
@ -90,7 +90,7 @@ public:
|
||||||
|
|
||||||
/*virtual*/ size_t update(F32 max_time_ms);
|
/*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
|
S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug
|
||||||
|
|
||||||
|
|
@ -151,10 +151,6 @@ public:
|
||||||
bool isWorking() { return getFlags(WCF_WORKING); }
|
bool isWorking() { return getFlags(WCF_WORKING); }
|
||||||
bool wasAborted() { return getFlags(WCF_ABORT_REQUESTED); }
|
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; }
|
const std::string& getName() const { return mWorkerClassName; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -169,7 +165,7 @@ protected:
|
||||||
void setWorkerThread(LLWorkerThread* workerthread);
|
void setWorkerThread(LLWorkerThread* workerthread);
|
||||||
|
|
||||||
// addWork(): calls startWork, adds doWork() to queue
|
// 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
|
// abortWork(): requests that work be aborted
|
||||||
void abortWork(bool autocomplete);
|
void abortWork(bool autocomplete);
|
||||||
|
|
@ -193,7 +189,6 @@ protected:
|
||||||
LLWorkerThread* mWorkerThread;
|
LLWorkerThread* mWorkerThread;
|
||||||
std::string mWorkerClassName;
|
std::string mWorkerClassName;
|
||||||
handle_t mRequestHandle;
|
handle_t mRequestHandle;
|
||||||
U32 mRequestPriority; // last priority set
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LLMutex mMutex;
|
LLMutex mMutex;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace tut
|
||||||
{
|
{
|
||||||
struct workqueue_data
|
struct workqueue_data
|
||||||
{
|
{
|
||||||
WorkQueue queue{"queue"};
|
WorkSchedule queue{"queue"};
|
||||||
};
|
};
|
||||||
typedef test_group<workqueue_data> workqueue_group;
|
typedef test_group<workqueue_data> workqueue_group;
|
||||||
typedef workqueue_group::object object;
|
typedef workqueue_group::object object;
|
||||||
|
|
@ -49,8 +49,8 @@ namespace tut
|
||||||
{
|
{
|
||||||
set_test_name("name");
|
set_test_name("name");
|
||||||
ensure_equals("didn't capture name", queue.getKey(), "queue");
|
ensure_equals("didn't capture name", queue.getKey(), "queue");
|
||||||
ensure("not findable", WorkQueue::getInstance("queue") == queue.getWeak().lock());
|
ensure("not findable", WorkSchedule::getInstance("queue") == queue.getWeak().lock());
|
||||||
WorkQueue q2;
|
WorkSchedule q2;
|
||||||
ensure("has no name", LLStringUtil::startsWith(q2.getKey(), "WorkQueue"));
|
ensure("has no name", LLStringUtil::startsWith(q2.getKey(), "WorkQueue"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,16 +73,16 @@ namespace tut
|
||||||
{
|
{
|
||||||
set_test_name("postEvery");
|
set_test_name("postEvery");
|
||||||
// record of runs
|
// 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
|
// 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
|
// 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
|
// should call any of LLCond's wait methods: you don't want to stall
|
||||||
// either the worker thread or the originating thread (conventionally
|
// either the worker thread or the originating thread (conventionally
|
||||||
// main). Use LLCond or a subclass even if all you want to do is
|
// main). Use LLCond or a subclass even if all you want to do is
|
||||||
// signal the work item that it can quit; consider LLOneShotCond.
|
// signal the work item that it can quit; consider LLOneShotCond.
|
||||||
LLCond<Shared> data;
|
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
|
// 2s seems like a long time to wait, since it directly impacts the
|
||||||
// duration of this test program. Unfortunately GitHub's Mac runners
|
// duration of this test program. Unfortunately GitHub's Mac runners
|
||||||
// are pretty wimpy, and we're getting spurious "too late" errors just
|
// are pretty wimpy, and we're getting spurious "too late" errors just
|
||||||
|
|
@ -97,7 +97,7 @@ namespace tut
|
||||||
data.update_one(
|
data.update_one(
|
||||||
[](Shared& data)
|
[](Shared& data)
|
||||||
{
|
{
|
||||||
data.push_back(WorkQueue::TimePoint::clock::now());
|
data.push_back(WorkSchedule::TimePoint::clock::now());
|
||||||
});
|
});
|
||||||
// by the 3rd call, return false to stop
|
// by the 3rd call, return false to stop
|
||||||
return (++count < 3);
|
return (++count < 3);
|
||||||
|
|
@ -106,7 +106,7 @@ namespace tut
|
||||||
// postEvery() running, so run until we have exhausted the iterations
|
// postEvery() running, so run until we have exhausted the iterations
|
||||||
// or we time out waiting
|
// or we time out waiting
|
||||||
for (auto finish = start + 10*interval;
|
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; )
|
data.get([](const Shared& data){ return data.size(); }) < 3; )
|
||||||
{
|
{
|
||||||
queue.runPending();
|
queue.runPending();
|
||||||
|
|
@ -143,8 +143,8 @@ namespace tut
|
||||||
void object::test<4>()
|
void object::test<4>()
|
||||||
{
|
{
|
||||||
set_test_name("postTo");
|
set_test_name("postTo");
|
||||||
WorkQueue main("main");
|
WorkSchedule main("main");
|
||||||
auto qptr = WorkQueue::getInstance("queue");
|
auto qptr = WorkSchedule::getInstance("queue");
|
||||||
int result = 0;
|
int result = 0;
|
||||||
main.postTo(
|
main.postTo(
|
||||||
qptr,
|
qptr,
|
||||||
|
|
@ -175,8 +175,8 @@ namespace tut
|
||||||
void object::test<5>()
|
void object::test<5>()
|
||||||
{
|
{
|
||||||
set_test_name("postTo with void return");
|
set_test_name("postTo with void return");
|
||||||
WorkQueue main("main");
|
WorkSchedule main("main");
|
||||||
auto qptr = WorkQueue::getInstance("queue");
|
auto qptr = WorkSchedule::getInstance("queue");
|
||||||
std::string observe;
|
std::string observe;
|
||||||
main.postTo(
|
main.postTo(
|
||||||
qptr,
|
qptr,
|
||||||
|
|
@ -198,7 +198,7 @@ namespace tut
|
||||||
std::string stored;
|
std::string stored;
|
||||||
// Try to call waitForResult() on this thread's main coroutine. It
|
// Try to call waitForResult() on this thread's main coroutine. It
|
||||||
// should throw because the main coroutine must service the queue.
|
// 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(
|
[this, &stored](){ stored = queue.waitForResult(
|
||||||
[](){ return "should throw"; }); }) };
|
[](){ return "should throw"; }); }) };
|
||||||
ensure("lambda should not have run", stored.empty());
|
ensure("lambda should not have run", stored.empty());
|
||||||
|
|
|
||||||
|
|
@ -17,18 +17,58 @@
|
||||||
// std headers
|
// std headers
|
||||||
// external library headers
|
// external library headers
|
||||||
// other Linden headers
|
// other Linden headers
|
||||||
|
#include "commoncontrol.h"
|
||||||
#include "llerror.h"
|
#include "llerror.h"
|
||||||
#include "llevents.h"
|
#include "llevents.h"
|
||||||
|
#include "llsd.h"
|
||||||
#include "stringize.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),
|
super(name),
|
||||||
mQueue(name, capacity),
|
|
||||||
mName("ThreadPool:" + name),
|
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)
|
for (size_t i = 0; i < mThreadCount; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -56,17 +96,17 @@ void LL::ThreadPool::start()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LL::ThreadPool::~ThreadPool()
|
LL::ThreadPoolBase::~ThreadPoolBase()
|
||||||
{
|
{
|
||||||
close();
|
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;
|
LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL;
|
||||||
mQueue.close();
|
mQueue->close();
|
||||||
for (auto& pair: mThreads)
|
for (auto& pair: mThreads)
|
||||||
{
|
{
|
||||||
LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
|
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;
|
LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL;
|
||||||
run();
|
run();
|
||||||
LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL;
|
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)
|
#if ! defined(LL_THREADPOOL_H)
|
||||||
#define LL_THREADPOOL_H
|
#define LL_THREADPOOL_H
|
||||||
|
|
||||||
|
#include "threadpool_fwd.h"
|
||||||
#include "workqueue.h"
|
#include "workqueue.h"
|
||||||
|
#include <memory> // std::unique_ptr
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <utility> // std::pair
|
#include <utility> // std::pair
|
||||||
|
|
@ -22,17 +24,24 @@
|
||||||
namespace LL
|
namespace LL
|
||||||
{
|
{
|
||||||
|
|
||||||
class ThreadPool: public LLInstanceTracker<ThreadPool, std::string>
|
class ThreadPoolBase: public LLInstanceTracker<ThreadPoolBase, std::string>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
using super = LLInstanceTracker<ThreadPool, std::string>;
|
using super = LLInstanceTracker<ThreadPoolBase, std::string>;
|
||||||
|
|
||||||
public:
|
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.
|
* 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);
|
ThreadPoolBase(const std::string& name, size_t threads,
|
||||||
virtual ~ThreadPool();
|
WorkQueueBase* queue);
|
||||||
|
virtual ~ThreadPoolBase();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch the ThreadPool. Until this call, a constructed ThreadPool
|
* Launch the ThreadPool. Until this call, a constructed ThreadPool
|
||||||
|
|
@ -50,8 +59,6 @@ namespace LL
|
||||||
|
|
||||||
std::string getName() const { return mName; }
|
std::string getName() const { return mName; }
|
||||||
size_t getWidth() const { return mThreads.size(); }
|
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()
|
* Override run() if you need special processing. The default run()
|
||||||
|
|
@ -59,15 +66,72 @@ namespace LL
|
||||||
*/
|
*/
|
||||||
virtual void run();
|
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:
|
private:
|
||||||
void run(const std::string& name);
|
void run(const std::string& name);
|
||||||
|
|
||||||
WorkQueue mQueue;
|
|
||||||
std::string mName;
|
std::string mName;
|
||||||
size_t mThreadCount;
|
size_t mThreadCount;
|
||||||
std::vector<std::pair<std::string, std::thread>> mThreads;
|
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
|
} // namespace LL
|
||||||
|
|
||||||
#endif /* ! defined(LL_THREADPOOL_H) */
|
#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 Mutex = LLCoros::Mutex;
|
||||||
using Lock = LLCoros::LockType;
|
using Lock = LLCoros::LockType;
|
||||||
|
|
||||||
LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity):
|
/*****************************************************************************
|
||||||
super(makeName(name)),
|
* WorkQueueBase
|
||||||
mQueue(capacity)
|
*****************************************************************************/
|
||||||
|
LL::WorkQueueBase::WorkQueueBase(const std::string& name):
|
||||||
|
super(makeName(name))
|
||||||
{
|
{
|
||||||
// TODO: register for "LLApp" events so we can implicitly close() on
|
// TODO: register for "LLApp" events so we can implicitly close() on
|
||||||
// viewer shutdown.
|
// 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()
|
void LL::WorkQueue::close()
|
||||||
{
|
{
|
||||||
mQueue.close();
|
mQueue.close();
|
||||||
|
|
@ -54,105 +161,85 @@ bool LL::WorkQueue::done()
|
||||||
return mQueue.done();
|
return mQueue.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LL::WorkQueue::runUntilClose()
|
bool LL::WorkQueue::post(const Work& callable)
|
||||||
{
|
{
|
||||||
try
|
return mQueue.pushIfOpen(callable);
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
|
||||||
callWork(mQueue.pop());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const Queue::Closed&)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LL::WorkQueue::runPending()
|
bool LL::WorkQueue::tryPost(const Work& callable)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
return mQueue.tryPush(callable);
|
||||||
for (Work work; mQueue.tryPop(work); )
|
|
||||||
{
|
|
||||||
callWork(work);
|
|
||||||
}
|
|
||||||
return ! mQueue.done();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LL::WorkQueue::runOne()
|
LL::WorkQueue::Work LL::WorkQueue::pop_()
|
||||||
{
|
{
|
||||||
Work work;
|
return mQueue.pop();
|
||||||
if (mQueue.tryPop(work))
|
|
||||||
{
|
|
||||||
callWork(work);
|
|
||||||
}
|
|
||||||
return ! mQueue.done();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LL::WorkQueue::runUntil(const TimePoint& until)
|
bool LL::WorkQueue::tryPop_(Work& work)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
return mQueue.tryPop(work);
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
mQueue.close();
|
||||||
// there's only one data field per item, as for us.
|
|
||||||
callWork(std::get<0>(work));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LL::WorkQueue::callWork(const Work& work)
|
size_t LL::WorkSchedule::size()
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
return mQueue.size();
|
||||||
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::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
|
return mQueue.done();
|
||||||
// string. See also LLCoros::logname().
|
}
|
||||||
if (LLCoros::getName().empty())
|
|
||||||
{
|
bool LL::WorkSchedule::post(const Work& callable)
|
||||||
LLTHROW(Error("Do not call " + method + " from a thread's default coroutine"));
|
{
|
||||||
}
|
// 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 "llcoros.h"
|
||||||
#include "llexception.h"
|
#include "llexception.h"
|
||||||
#include "llinstancetracker.h"
|
#include "llinstancetracker.h"
|
||||||
|
#include "llinstancetrackersubclass.h"
|
||||||
#include "threadsafeschedule.h"
|
#include "threadsafeschedule.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <exception> // std::current_exception
|
#include <exception> // std::current_exception
|
||||||
|
|
@ -23,27 +24,23 @@
|
||||||
|
|
||||||
namespace LL
|
namespace LL
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* WorkQueueBase: API for WorkQueue and WorkSchedule
|
||||||
|
*****************************************************************************/
|
||||||
/**
|
/**
|
||||||
* A typical WorkQueue has a string name that can be used to find it.
|
* 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:
|
private:
|
||||||
using super = LLInstanceTracker<WorkQueue, std::string>;
|
using super = LLInstanceTracker<WorkQueueBase, std::string>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Work = std::function<void()>;
|
using Work = std::function<void()>;
|
||||||
|
using Closed = LLThreadSafeQueueInterrupt;
|
||||||
private:
|
// for runFor()
|
||||||
using Queue = ThreadSafeSchedule<Work>;
|
using TimePoint = std::chrono::steady_clock::time_point;
|
||||||
// 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;
|
|
||||||
|
|
||||||
struct Error: public LLException
|
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.
|
* 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
|
* Since the point of WorkQueue is to pass work to some other worker
|
||||||
* thread(s) asynchronously, it's important that the WorkQueue continue
|
* thread(s) asynchronously, it's important that it continue to exist
|
||||||
* to exist until the worker thread(s) have drained it. To communicate
|
* until the worker thread(s) have drained it. To communicate that
|
||||||
* that it's time for them to quit, close() the queue.
|
* it's time for them to quit, close() the queue.
|
||||||
*/
|
*/
|
||||||
void close();
|
virtual void close() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WorkQueue supports multiple producers and multiple consumers. In
|
* 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
|
* * If you're the only consumer, noticing that size() > 0 is
|
||||||
* meaningful.
|
* meaningful.
|
||||||
*/
|
*/
|
||||||
size_t size();
|
virtual size_t size() = 0;
|
||||||
/// producer end: are we prevented from pushing any additional items?
|
/// 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?
|
/// consumer end: are we done, is the queue entirely drained?
|
||||||
bool done();
|
virtual bool done() = 0;
|
||||||
|
|
||||||
/*---------------------- fire and forget API -----------------------*/
|
/*---------------------- 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
|
* post work, unless the queue is closed before we can post
|
||||||
*/
|
*/
|
||||||
template <typename CALLABLE>
|
virtual bool post(const Work&) = 0;
|
||||||
bool postIfOpen(CALLABLE&& callable)
|
|
||||||
{
|
|
||||||
return postIfOpen(TimePoint::clock::now(), std::move(callable));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Post work to be run at a specified time to another WorkQueue, which
|
* post work, unless the queue is full
|
||||||
* may or may not still exist and be open. Return true if we were able
|
|
||||||
* to post.
|
|
||||||
*/
|
*/
|
||||||
template <typename CALLABLE>
|
virtual bool tryPost(const Work&) = 0;
|
||||||
static bool postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Post work to another WorkQueue, which may or may not still exist
|
* 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>
|
template <typename... ARGS>
|
||||||
static bool postMaybe(weak_t target, CALLABLE&& callable)
|
static bool postMaybe(weak_t target, ARGS&&... args);
|
||||||
{
|
|
||||||
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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*------------------------- handshake API --------------------------*/
|
/*------------------------- 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
|
* 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
|
* Returns true if able to post, false if the other WorkQueue is
|
||||||
* inaccessible.
|
* inaccessible.
|
||||||
*/
|
*/
|
||||||
template <typename CALLABLE, typename FOLLOWUP>
|
template <typename CALLABLE, typename FOLLOWUP, typename... ARGS>
|
||||||
bool postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback)
|
bool postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback,
|
||||||
{
|
ARGS&&... args);
|
||||||
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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Post work to another WorkQueue, blocking the calling coroutine
|
* 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
|
* In general, we assume that each thread's default coroutine is busy
|
||||||
* servicing its WorkQueue or whatever. To try to prevent mistakes, we
|
* servicing its WorkQueue or whatever. To try to prevent mistakes, we
|
||||||
* forbid calling waitForResult() from a thread's default coroutine.
|
* forbid calling waitForResult() from a thread's default coroutine.
|
||||||
*/
|
*/
|
||||||
template <typename CALLABLE>
|
template <typename CALLABLE, typename... ARGS>
|
||||||
auto waitForResult(CALLABLE&& callable)
|
auto waitForResult(CALLABLE&& callable, ARGS&&... args);
|
||||||
{
|
|
||||||
return waitForResult(TimePoint::clock::now(), std::move(callable));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------- worker API ---------------------------*/
|
/*--------------------------- worker API ---------------------------*/
|
||||||
|
|
||||||
|
|
@ -270,7 +172,7 @@ namespace LL
|
||||||
*/
|
*/
|
||||||
bool runUntil(const TimePoint& until);
|
bool runUntil(const TimePoint& until);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
template <typename CALLABLE, typename FOLLOWUP>
|
template <typename CALLABLE, typename FOLLOWUP>
|
||||||
static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback);
|
static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback);
|
||||||
/// general case: arbitrary C++ return type
|
/// general case: arbitrary C++ return type
|
||||||
|
|
@ -290,13 +192,170 @@ namespace LL
|
||||||
static void checkCoroutine(const std::string& method);
|
static void checkCoroutine(const std::string& method);
|
||||||
static void error(const std::string& msg);
|
static void error(const std::string& msg);
|
||||||
static std::string makeName(const std::string& name);
|
static std::string makeName(const std::string& name);
|
||||||
void callWork(const Queue::DataTuple& work);
|
|
||||||
void callWork(const Work& 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;
|
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
|
* CALLABLE that returns bool, a TimePoint and an interval at which to
|
||||||
* relaunch it. As long as the callable continues returning true, BackJack
|
* relaunch it. As long as the callable continues returning true, BackJack
|
||||||
* keeps resubmitting it to the target WorkQueue.
|
* 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
|
// class method gets its own 'this' pointer -- which we need to resubmit
|
||||||
// the whole BackJack callable.
|
// the whole BackJack callable.
|
||||||
template <typename Rep, typename Period, typename CALLABLE>
|
template <typename Rep, typename Period, typename CALLABLE>
|
||||||
class WorkQueue::BackJack
|
class WorkSchedule::BackJack
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// bind the desired data
|
// bind the desired data
|
||||||
|
|
@ -319,9 +378,10 @@ namespace LL
|
||||||
mCallable(std::move(callable))
|
mCallable(std::move(callable))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// Call by target WorkQueue -- note that although WE require a
|
// This operator() method, called by target WorkSchedule, is what
|
||||||
// callable returning bool, WorkQueue wants a void callable. We
|
// makes this object a Work item. Although WE require a callable
|
||||||
// consume the bool.
|
// returning bool, WorkSchedule wants a void callable. We consume the
|
||||||
|
// bool.
|
||||||
void operator()()
|
void operator()()
|
||||||
{
|
{
|
||||||
// If mCallable() throws an exception, don't catch it here: if it
|
// 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.
|
// register our intent to fire at exact mIntervals.
|
||||||
mStart += mInterval;
|
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
|
// Assume it still exists, rather than checking the result of
|
||||||
// lock().
|
// lock().
|
||||||
// Resubmit the whole *this callable: that's why we're a class
|
// 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
|
// move-only callable; but naturally this statement must be
|
||||||
// the last time we reference this instance, which may become
|
// the last time we reference this instance, which may become
|
||||||
// moved-from.
|
// moved-from.
|
||||||
try
|
auto target{ std::dynamic_pointer_cast<WorkSchedule>(mTarget.lock()) };
|
||||||
{
|
// Discard bool return: once this queue is closed, oh well,
|
||||||
mTarget.lock()->post(mStart, std::move(*this));
|
// just stop
|
||||||
}
|
target->post(std::move(*this), mStart);
|
||||||
catch (const Closed&)
|
|
||||||
{
|
|
||||||
// Once this queue is closed, oh well, just stop
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,8 +420,8 @@ namespace LL
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Rep, typename Period, typename CALLABLE>
|
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)
|
CALLABLE&& callable)
|
||||||
{
|
{
|
||||||
if (interval.count() <= 0)
|
if (interval.count() <= 0)
|
||||||
{
|
{
|
||||||
|
|
@ -381,14 +437,14 @@ namespace LL
|
||||||
// Instantiate and post a suitable BackJack, binding a weak_ptr to
|
// Instantiate and post a suitable BackJack, binding a weak_ptr to
|
||||||
// self, the current time, the desired interval and the desired
|
// self, the current time, the desired interval and the desired
|
||||||
// callable.
|
// callable.
|
||||||
post(
|
return post(
|
||||||
BackJack<Rep, Period, CALLABLE>(
|
BackJack<Rep, Period, CALLABLE>(
|
||||||
getWeak(), TimePoint::clock::now(), interval, std::move(callable)));
|
getWeak(), TimePoint::clock::now(), interval, std::move(callable)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// general case: arbitrary C++ return type
|
/// general case: arbitrary C++ return type
|
||||||
template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
|
template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
|
||||||
struct WorkQueue::MakeReplyLambda
|
struct WorkQueueBase::MakeReplyLambda
|
||||||
{
|
{
|
||||||
auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
|
auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
|
||||||
{
|
{
|
||||||
|
|
@ -409,7 +465,7 @@ namespace LL
|
||||||
|
|
||||||
/// specialize for CALLABLE returning void
|
/// specialize for CALLABLE returning void
|
||||||
template <typename CALLABLE, typename FOLLOWUP>
|
template <typename CALLABLE, typename FOLLOWUP>
|
||||||
struct WorkQueue::MakeReplyLambda<CALLABLE, FOLLOWUP, void>
|
struct WorkQueueBase::MakeReplyLambda<CALLABLE, FOLLOWUP, void>
|
||||||
{
|
{
|
||||||
auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
|
auto operator()(CALLABLE&& callable, FOLLOWUP&& callback)
|
||||||
{
|
{
|
||||||
|
|
@ -421,16 +477,16 @@ namespace LL
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CALLABLE, typename FOLLOWUP>
|
template <typename CALLABLE, typename FOLLOWUP>
|
||||||
auto WorkQueue::makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback)
|
auto WorkQueueBase::makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback)
|
||||||
{
|
{
|
||||||
return MakeReplyLambda<CALLABLE, FOLLOWUP,
|
return MakeReplyLambda<CALLABLE, FOLLOWUP,
|
||||||
decltype(std::forward<CALLABLE>(callable)())>()
|
decltype(std::forward<CALLABLE>(callable)())>()
|
||||||
(std::move(callable), std::move(callback));
|
(std::move(callable), std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename CALLABLE, typename FOLLOWUP>
|
template <typename CALLABLE, typename FOLLOWUP, typename... ARGS>
|
||||||
bool WorkQueue::postTo(weak_t target,
|
bool WorkQueueBase::postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback,
|
||||||
const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback)
|
ARGS&&... args)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED;
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
// We're being asked to post to the WorkQueue at target.
|
// 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
|
// Here we believe target WorkQueue still exists. Post to it a
|
||||||
// lambda that packages our callable, our callback and a weak_ptr
|
// lambda that packages our callable, our callback and a weak_ptr
|
||||||
// to this originating WorkQueue.
|
// to this originating WorkQueue.
|
||||||
tptr->post(
|
return tptr->post(
|
||||||
time,
|
|
||||||
[reply = super::getWeak(),
|
[reply = super::getWeak(),
|
||||||
callable = std::move(callable),
|
callable = std::move(callable),
|
||||||
callback = std::move(callback)]
|
callback = std::move(callback)]
|
||||||
()
|
() mutable
|
||||||
mutable {
|
{
|
||||||
// Use postMaybe() below in case this originating WorkQueue
|
// Use postMaybe() below in case this originating WorkQueue
|
||||||
// has been closed or destroyed. Remember, the outer lambda is
|
// has been closed or destroyed. Remember, the outer lambda is
|
||||||
// now running on a thread servicing the target WorkQueue, and
|
// now running on a thread servicing the target WorkQueue, and
|
||||||
|
|
@ -472,44 +527,34 @@ namespace LL
|
||||||
// originating WorkQueue. Once there, rethrow it.
|
// originating WorkQueue. Once there, rethrow it.
|
||||||
[exc = std::current_exception()](){ std::rethrow_exception(exc); });
|
[exc = std::current_exception()](){ std::rethrow_exception(exc); });
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
// if caller passed a TimePoint, pass it along to post()
|
||||||
// looks like we were able to post()
|
std::forward<ARGS>(args)...);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename CALLABLE>
|
template <typename... ARGS>
|
||||||
bool WorkQueue::postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable)
|
bool WorkQueueBase::postMaybe(weak_t target, ARGS&&... args)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED;
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
// target is a weak_ptr: have to lock it to check it
|
// target is a weak_ptr: have to lock it to check it
|
||||||
auto tptr = target.lock();
|
auto tptr = target.lock();
|
||||||
if (tptr)
|
if (tptr)
|
||||||
{
|
{
|
||||||
try
|
return tptr->post(std::forward<ARGS>(args)...);
|
||||||
{
|
|
||||||
tptr->post(time, std::forward<CALLABLE>(callable));
|
|
||||||
// we were able to post()
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// general case: arbitrary C++ return type
|
/// general case: arbitrary C++ return type
|
||||||
template <typename CALLABLE, typename RETURNTYPE>
|
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;
|
LLCoros::Promise<RETURNTYPE> promise;
|
||||||
self->post(
|
bool posted = self->post(
|
||||||
time,
|
|
||||||
// We dare to bind a reference to Promise because it's
|
// We dare to bind a reference to Promise because it's
|
||||||
// specifically designed for cross-thread communication.
|
// specifically designed for cross-thread communication.
|
||||||
[&promise, callable = std::move(callable)]()
|
[&promise, callable = std::move(callable)]()
|
||||||
|
|
@ -523,7 +568,13 @@ namespace LL
|
||||||
{
|
{
|
||||||
promise.set_exception(std::current_exception());
|
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) };
|
auto future{ LLCoros::getFuture(promise) };
|
||||||
// now, on the calling thread, wait for that result
|
// now, on the calling thread, wait for that result
|
||||||
LLCoros::TempStatus st("waiting for WorkQueue::waitForResult()");
|
LLCoros::TempStatus st("waiting for WorkQueue::waitForResult()");
|
||||||
|
|
@ -533,13 +584,13 @@ namespace LL
|
||||||
|
|
||||||
/// specialize for CALLABLE returning void
|
/// specialize for CALLABLE returning void
|
||||||
template <typename CALLABLE>
|
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;
|
LLCoros::Promise<void> promise;
|
||||||
self->post(
|
bool posted = self->post(
|
||||||
time,
|
|
||||||
// &promise is designed for cross-thread access
|
// &promise is designed for cross-thread access
|
||||||
[&promise, callable = std::move(callable)]()
|
[&promise, callable = std::move(callable)]()
|
||||||
mutable {
|
mutable {
|
||||||
|
|
@ -552,7 +603,13 @@ namespace LL
|
||||||
{
|
{
|
||||||
promise.set_exception(std::current_exception());
|
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) };
|
auto future{ LLCoros::getFuture(promise) };
|
||||||
// block until set_value()
|
// block until set_value()
|
||||||
LLCoros::TempStatus st("waiting for void WorkQueue::waitForResult()");
|
LLCoros::TempStatus st("waiting for void WorkQueue::waitForResult()");
|
||||||
|
|
@ -560,13 +617,13 @@ namespace LL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CALLABLE>
|
template <typename CALLABLE, typename... ARGS>
|
||||||
auto WorkQueue::waitForResult(const TimePoint& time, CALLABLE&& callable)
|
auto WorkQueueBase::waitForResult(CALLABLE&& callable, ARGS&&... args)
|
||||||
{
|
{
|
||||||
checkCoroutine("waitForResult()");
|
checkCoroutine("waitForResult()");
|
||||||
// derive callable's return type so we can specialize for void
|
// derive callable's return type so we can specialize for void
|
||||||
return WaitForResult<CALLABLE, decltype(std::forward<CALLABLE>(callable)())>()
|
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
|
} // namespace LL
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ void HttpLibcurl::shutdown()
|
||||||
|
|
||||||
void HttpLibcurl::start(int policy_count)
|
void HttpLibcurl::start(int policy_count)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
llassert_always(policy_count <= HTTP_POLICY_CLASS_LIMIT);
|
llassert_always(policy_count <= HTTP_POLICY_CLASS_LIMIT);
|
||||||
llassert_always(! mMultiHandles); // One-time call only
|
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.
|
// sleep otherwise ask for a normal polling interval.
|
||||||
HttpService::ELoopSpeed HttpLibcurl::processTransport()
|
HttpService::ELoopSpeed HttpLibcurl::processTransport()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpService::ELoopSpeed ret(HttpService::REQUEST_SLEEP);
|
HttpService::ELoopSpeed ret(HttpService::REQUEST_SLEEP);
|
||||||
|
|
||||||
// Give libcurl some cycles to do I/O & callbacks
|
// Give libcurl some cycles to do I/O & callbacks
|
||||||
|
|
@ -168,6 +170,7 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport()
|
||||||
CURLMcode status(CURLM_CALL_MULTI_PERFORM);
|
CURLMcode status(CURLM_CALL_MULTI_PERFORM);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("httppt - curl_multi_perform");
|
||||||
running = 0;
|
running = 0;
|
||||||
status = curl_multi_perform(mMultiHandles[policy_class], &running);
|
status = curl_multi_perform(mMultiHandles[policy_class], &running);
|
||||||
}
|
}
|
||||||
|
|
@ -176,31 +179,34 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport()
|
||||||
// Run completion on anything done
|
// Run completion on anything done
|
||||||
CURLMsg * msg(NULL);
|
CURLMsg * msg(NULL);
|
||||||
int msgs_in_queue(0);
|
int msgs_in_queue(0);
|
||||||
while ((msg = curl_multi_info_read(mMultiHandles[policy_class], &msgs_in_queue)))
|
{
|
||||||
{
|
LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("httppt - curl_multi_info_read");
|
||||||
if (CURLMSG_DONE == msg->msg)
|
while ((msg = curl_multi_info_read(mMultiHandles[policy_class], &msgs_in_queue)))
|
||||||
{
|
{
|
||||||
CURL * handle(msg->easy_handle);
|
if (CURLMSG_DONE == msg->msg)
|
||||||
CURLcode result(msg->data.result);
|
{
|
||||||
|
CURL* handle(msg->easy_handle);
|
||||||
|
CURLcode result(msg->data.result);
|
||||||
|
|
||||||
completeRequest(mMultiHandles[policy_class], handle, result);
|
completeRequest(mMultiHandles[policy_class], handle, result);
|
||||||
handle = NULL; // No longer valid on return
|
handle = NULL; // No longer valid on return
|
||||||
ret = HttpService::NORMAL; // If anything completes, we may have a free slot.
|
ret = HttpService::NORMAL; // If anything completes, we may have a free slot.
|
||||||
// Turning around quickly reduces connection gap by 7-10mS.
|
// Turning around quickly reduces connection gap by 7-10mS.
|
||||||
}
|
}
|
||||||
else if (CURLMSG_NONE == msg->msg)
|
else if (CURLMSG_NONE == msg->msg)
|
||||||
{
|
{
|
||||||
// Ignore this... it shouldn't mean anything.
|
// Ignore this... it shouldn't mean anything.
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LL_WARNS_ONCE(LOG_CORE) << "Unexpected message from libcurl. Msg code: "
|
LL_WARNS_ONCE(LOG_CORE) << "Unexpected message from libcurl. Msg code: "
|
||||||
<< msg->msg
|
<< msg->msg
|
||||||
<< LL_ENDL;
|
<< LL_ENDL;
|
||||||
}
|
}
|
||||||
msgs_in_queue = 0;
|
msgs_in_queue = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! mActiveOps.empty())
|
if (! mActiveOps.empty())
|
||||||
|
|
@ -214,6 +220,7 @@ HttpService::ELoopSpeed HttpLibcurl::processTransport()
|
||||||
// Caller has provided us with a ref count on op.
|
// Caller has provided us with a ref count on op.
|
||||||
void HttpLibcurl::addOp(const HttpOpRequest::ptr_t &op)
|
void HttpLibcurl::addOp(const HttpOpRequest::ptr_t &op)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
llassert_always(op->mReqPolicy < mPolicyCount);
|
llassert_always(op->mReqPolicy < mPolicyCount);
|
||||||
llassert_always(mMultiHandles[op->mReqPolicy] != NULL);
|
llassert_always(mMultiHandles[op->mReqPolicy] != NULL);
|
||||||
|
|
||||||
|
|
@ -257,6 +264,7 @@ void HttpLibcurl::addOp(const HttpOpRequest::ptr_t &op)
|
||||||
// method to kill the request.
|
// method to kill the request.
|
||||||
bool HttpLibcurl::cancel(HttpHandle handle)
|
bool HttpLibcurl::cancel(HttpHandle handle)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpOpRequest::ptr_t op = HttpOpRequest::fromHandle<HttpOpRequest>(handle);
|
HttpOpRequest::ptr_t op = HttpOpRequest::fromHandle<HttpOpRequest>(handle);
|
||||||
active_set_t::iterator it(mActiveOps.find(op));
|
active_set_t::iterator it(mActiveOps.find(op));
|
||||||
if (mActiveOps.end() == it)
|
if (mActiveOps.end() == it)
|
||||||
|
|
@ -282,6 +290,7 @@ bool HttpLibcurl::cancel(HttpHandle handle)
|
||||||
// op to the reply queue with refcount intact.
|
// op to the reply queue with refcount intact.
|
||||||
void HttpLibcurl::cancelRequest(const HttpOpRequest::ptr_t &op)
|
void HttpLibcurl::cancelRequest(const HttpOpRequest::ptr_t &op)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
// Deactivate request
|
// Deactivate request
|
||||||
op->mCurlActive = false;
|
op->mCurlActive = false;
|
||||||
|
|
||||||
|
|
@ -308,6 +317,7 @@ void HttpLibcurl::cancelRequest(const HttpOpRequest::ptr_t &op)
|
||||||
// Keep them synchronized as necessary.
|
// Keep them synchronized as necessary.
|
||||||
bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status)
|
bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpHandle ophandle(NULL);
|
HttpHandle ophandle(NULL);
|
||||||
|
|
||||||
CURLcode ccode(CURLE_OK);
|
CURLcode ccode(CURLE_OK);
|
||||||
|
|
@ -445,6 +455,7 @@ int HttpLibcurl::getActiveCountInClass(int policy_class) const
|
||||||
|
|
||||||
void HttpLibcurl::policyUpdated(int policy_class)
|
void HttpLibcurl::policyUpdated(int policy_class)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
if (policy_class < 0 || policy_class >= mPolicyCount || ! mMultiHandles)
|
if (policy_class < 0 || policy_class >= mPolicyCount || ! mMultiHandles)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,6 @@ HttpOperation::HttpOperation():
|
||||||
mReplyQueue(),
|
mReplyQueue(),
|
||||||
mUserHandler(),
|
mUserHandler(),
|
||||||
mReqPolicy(HttpRequest::DEFAULT_POLICY_ID),
|
mReqPolicy(HttpRequest::DEFAULT_POLICY_ID),
|
||||||
mReqPriority(0U),
|
|
||||||
mTracing(HTTP_TRACE_OFF),
|
mTracing(HTTP_TRACE_OFF),
|
||||||
mMyHandle(LLCORE_HTTP_HANDLE_INVALID)
|
mMyHandle(LLCORE_HTTP_HANDLE_INVALID)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,6 @@ protected:
|
||||||
public:
|
public:
|
||||||
// Request Data
|
// Request Data
|
||||||
HttpRequest::policy_t mReqPolicy;
|
HttpRequest::policy_t mReqPolicy;
|
||||||
HttpRequest::priority_t mReqPriority;
|
|
||||||
|
|
||||||
// Reply Data
|
// Reply Data
|
||||||
HttpStatus mStatus;
|
HttpStatus mStatus;
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,7 @@ HttpOpRequest::~HttpOpRequest()
|
||||||
|
|
||||||
void HttpOpRequest::stageFromRequest(HttpService * service)
|
void HttpOpRequest::stageFromRequest(HttpService * service)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast<HttpOpRequest>(shared_from_this()));
|
HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast<HttpOpRequest>(shared_from_this()));
|
||||||
service->getPolicy().addOp(self); // transfers refcount
|
service->getPolicy().addOp(self); // transfers refcount
|
||||||
}
|
}
|
||||||
|
|
@ -207,6 +208,7 @@ void HttpOpRequest::stageFromRequest(HttpService * service)
|
||||||
|
|
||||||
void HttpOpRequest::stageFromReady(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()));
|
HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast<HttpOpRequest>(shared_from_this()));
|
||||||
service->getTransport().addOp(self); // transfers refcount
|
service->getTransport().addOp(self); // transfers refcount
|
||||||
}
|
}
|
||||||
|
|
@ -214,6 +216,7 @@ void HttpOpRequest::stageFromReady(HttpService * service)
|
||||||
|
|
||||||
void HttpOpRequest::stageFromActive(HttpService * service)
|
void HttpOpRequest::stageFromActive(HttpService * service)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
if (mReplyLength)
|
if (mReplyLength)
|
||||||
{
|
{
|
||||||
// If non-zero, we received and processed a Content-Range
|
// If non-zero, we received and processed a Content-Range
|
||||||
|
|
@ -250,6 +253,7 @@ void HttpOpRequest::stageFromActive(HttpService * service)
|
||||||
|
|
||||||
void HttpOpRequest::visitNotifier(HttpRequest * request)
|
void HttpOpRequest::visitNotifier(HttpRequest * request)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
if (mUserHandler)
|
if (mUserHandler)
|
||||||
{
|
{
|
||||||
HttpResponse * response = new HttpResponse();
|
HttpResponse * response = new HttpResponse();
|
||||||
|
|
@ -292,6 +296,7 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
|
||||||
|
|
||||||
HttpStatus HttpOpRequest::cancel()
|
HttpStatus HttpOpRequest::cancel()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
mStatus = HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED);
|
mStatus = HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED);
|
||||||
|
|
||||||
addAsReply();
|
addAsReply();
|
||||||
|
|
@ -301,12 +306,12 @@ HttpStatus HttpOpRequest::cancel()
|
||||||
|
|
||||||
|
|
||||||
HttpStatus HttpOpRequest::setupGet(HttpRequest::policy_t policy_id,
|
HttpStatus HttpOpRequest::setupGet(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers)
|
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;
|
mReqMethod = HOR_GET;
|
||||||
|
|
||||||
return HttpStatus();
|
return HttpStatus();
|
||||||
|
|
@ -314,14 +319,14 @@ HttpStatus HttpOpRequest::setupGet(HttpRequest::policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
HttpStatus HttpOpRequest::setupGetByteRange(HttpRequest::policy_t policy_id,
|
HttpStatus HttpOpRequest::setupGetByteRange(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
size_t offset,
|
size_t offset,
|
||||||
size_t len,
|
size_t len,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers)
|
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;
|
mReqMethod = HOR_GET;
|
||||||
mReqOffset = offset;
|
mReqOffset = offset;
|
||||||
mReqLength = len;
|
mReqLength = len;
|
||||||
|
|
@ -335,13 +340,13 @@ HttpStatus HttpOpRequest::setupGetByteRange(HttpRequest::policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
HttpStatus HttpOpRequest::setupPost(HttpRequest::policy_t policy_id,
|
HttpStatus HttpOpRequest::setupPost(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers)
|
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;
|
mReqMethod = HOR_POST;
|
||||||
|
|
||||||
return HttpStatus();
|
return HttpStatus();
|
||||||
|
|
@ -349,13 +354,13 @@ HttpStatus HttpOpRequest::setupPost(HttpRequest::policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,
|
HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers)
|
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;
|
mReqMethod = HOR_PUT;
|
||||||
|
|
||||||
return HttpStatus();
|
return HttpStatus();
|
||||||
|
|
@ -363,12 +368,12 @@ HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
HttpStatus HttpOpRequest::setupDelete(HttpRequest::policy_t policy_id,
|
HttpStatus HttpOpRequest::setupDelete(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers)
|
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;
|
mReqMethod = HOR_DELETE;
|
||||||
|
|
||||||
return HttpStatus();
|
return HttpStatus();
|
||||||
|
|
@ -376,13 +381,13 @@ HttpStatus HttpOpRequest::setupDelete(HttpRequest::policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
HttpStatus HttpOpRequest::setupPatch(HttpRequest::policy_t policy_id,
|
HttpStatus HttpOpRequest::setupPatch(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers)
|
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;
|
mReqMethod = HOR_PATCH;
|
||||||
|
|
||||||
return HttpStatus();
|
return HttpStatus();
|
||||||
|
|
@ -390,12 +395,12 @@ HttpStatus HttpOpRequest::setupPatch(HttpRequest::policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
HttpStatus HttpOpRequest::setupCopy(HttpRequest::policy_t policy_id,
|
HttpStatus HttpOpRequest::setupCopy(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t &headers)
|
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;
|
mReqMethod = HOR_COPY;
|
||||||
|
|
||||||
return HttpStatus();
|
return HttpStatus();
|
||||||
|
|
@ -403,12 +408,12 @@ HttpStatus HttpOpRequest::setupCopy(HttpRequest::policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
HttpStatus HttpOpRequest::setupMove(HttpRequest::policy_t policy_id,
|
HttpStatus HttpOpRequest::setupMove(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t &headers)
|
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;
|
mReqMethod = HOR_MOVE;
|
||||||
|
|
||||||
return HttpStatus();
|
return HttpStatus();
|
||||||
|
|
@ -416,15 +421,14 @@ HttpStatus HttpOpRequest::setupMove(HttpRequest::policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
|
void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers)
|
const HttpHeaders::ptr_t & headers)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
mProcFlags = 0U;
|
mProcFlags = 0U;
|
||||||
mReqPolicy = policy_id;
|
mReqPolicy = policy_id;
|
||||||
mReqPriority = priority;
|
|
||||||
mReqURL = url;
|
mReqURL = url;
|
||||||
if (body)
|
if (body)
|
||||||
{
|
{
|
||||||
|
|
@ -465,6 +469,7 @@ void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
|
||||||
// *TODO: Move this to _httplibcurl where it belongs.
|
// *TODO: Move this to _httplibcurl where it belongs.
|
||||||
HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
|
HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
// Scrub transport and result data for retried op case
|
// Scrub transport and result data for retried op case
|
||||||
mCurlActive = false;
|
mCurlActive = false;
|
||||||
mCurlHandle = NULL;
|
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)
|
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));
|
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
||||||
|
|
||||||
if (! op->mReplyBody)
|
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)
|
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));
|
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
||||||
|
|
||||||
if (! op->mReqBody)
|
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)
|
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));
|
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
||||||
|
|
||||||
if (!op->mReqBody)
|
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)
|
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 char status_line[] = "HTTP/";
|
||||||
static const size_t status_line_len = sizeof(status_line) - 1;
|
static const size_t status_line_len = sizeof(status_line) - 1;
|
||||||
static const char con_ran_line[] = "content-range";
|
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)
|
CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userdata)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
||||||
|
|
||||||
if (op->mCallbackSSLVerify)
|
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)
|
int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(param));
|
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(param));
|
||||||
|
|
||||||
if (op->mCallbackSSLVerify)
|
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)
|
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));
|
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
|
||||||
|
|
||||||
std::string safe_line;
|
std::string safe_line;
|
||||||
|
|
|
||||||
|
|
@ -105,13 +105,11 @@ public:
|
||||||
/// Threading: called by application thread
|
/// Threading: called by application thread
|
||||||
///
|
///
|
||||||
HttpStatus setupGet(HttpRequest::policy_t policy_id,
|
HttpStatus setupGet(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers);
|
const HttpHeaders::ptr_t & headers);
|
||||||
|
|
||||||
HttpStatus setupGetByteRange(HttpRequest::policy_t policy_id,
|
HttpStatus setupGetByteRange(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
size_t offset,
|
size_t offset,
|
||||||
size_t len,
|
size_t len,
|
||||||
|
|
@ -119,40 +117,34 @@ public:
|
||||||
const HttpHeaders::ptr_t & headers);
|
const HttpHeaders::ptr_t & headers);
|
||||||
|
|
||||||
HttpStatus setupPost(HttpRequest::policy_t policy_id,
|
HttpStatus setupPost(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers);
|
const HttpHeaders::ptr_t & headers);
|
||||||
|
|
||||||
HttpStatus setupPut(HttpRequest::policy_t policy_id,
|
HttpStatus setupPut(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers);
|
const HttpHeaders::ptr_t & headers);
|
||||||
|
|
||||||
HttpStatus setupDelete(HttpRequest::policy_t policy_id,
|
HttpStatus setupDelete(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers);
|
const HttpHeaders::ptr_t & headers);
|
||||||
|
|
||||||
HttpStatus setupPatch(HttpRequest::policy_t policy_id,
|
HttpStatus setupPatch(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers);
|
const HttpHeaders::ptr_t & headers);
|
||||||
|
|
||||||
HttpStatus setupCopy(HttpRequest::policy_t policy_id,
|
HttpStatus setupCopy(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers);
|
const HttpHeaders::ptr_t & headers);
|
||||||
|
|
||||||
HttpStatus setupMove(HttpRequest::policy_t policy_id,
|
HttpStatus setupMove(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers);
|
const HttpHeaders::ptr_t & headers);
|
||||||
|
|
@ -172,7 +164,6 @@ protected:
|
||||||
// Threading: called by application thread
|
// Threading: called by application thread
|
||||||
//
|
//
|
||||||
void setupCommon(HttpRequest::policy_t policy_id,
|
void setupCommon(HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
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
|
// Free functions
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if 0 // DEPRECATED
|
||||||
#include "_httpopsetpriority.h"
|
#include "_httpopsetpriority.h"
|
||||||
|
|
||||||
#include "httpresponse.h"
|
#include "httpresponse.h"
|
||||||
|
|
@ -61,3 +62,5 @@ void HttpOpSetPriority::stageFromRequest(HttpService * service)
|
||||||
|
|
||||||
|
|
||||||
} // end namespace LLCore
|
} // end namespace LLCore
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#ifndef _LLCORE_HTTP_SETPRIORITY_H_
|
#ifndef _LLCORE_HTTP_SETPRIORITY_H_
|
||||||
#define _LLCORE_HTTP_SETPRIORITY_H_
|
#define _LLCORE_HTTP_SETPRIORITY_H_
|
||||||
|
|
||||||
|
#if 0 // DEPRECATED
|
||||||
#include "httpcommon.h"
|
#include "httpcommon.h"
|
||||||
#include "httprequest.h"
|
#include "httprequest.h"
|
||||||
#include "_httpoperation.h"
|
#include "_httpoperation.h"
|
||||||
|
|
@ -49,7 +49,7 @@ namespace LLCore
|
||||||
class HttpOpSetPriority : public HttpOperation
|
class HttpOpSetPriority : public HttpOperation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HttpOpSetPriority(HttpHandle handle, HttpRequest::priority_t priority);
|
HttpOpSetPriority(HttpHandle handle);
|
||||||
|
|
||||||
virtual ~HttpOpSetPriority();
|
virtual ~HttpOpSetPriority();
|
||||||
|
|
||||||
|
|
@ -63,10 +63,10 @@ public:
|
||||||
protected:
|
protected:
|
||||||
// Request Data
|
// Request Data
|
||||||
HttpHandle mHandle;
|
HttpHandle mHandle;
|
||||||
HttpRequest::priority_t mPriority;
|
|
||||||
}; // end class HttpOpSetPriority
|
}; // end class HttpOpSetPriority
|
||||||
|
|
||||||
} // end namespace LLCore
|
} // end namespace LLCore
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // _LLCORE_HTTP_SETPRIORITY_H_
|
#endif // _LLCORE_HTTP_SETPRIORITY_H_
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -330,37 +330,6 @@ HttpService::ELoopSpeed HttpPolicy::processReadyQueue()
|
||||||
return result;
|
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)
|
bool HttpPolicy::cancel(HttpHandle handle)
|
||||||
{
|
{
|
||||||
for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
|
for (int policy_class(0); policy_class < mClasses.size(); ++policy_class)
|
||||||
|
|
|
||||||
|
|
@ -110,12 +110,6 @@ public:
|
||||||
/// Threading: called by worker thread
|
/// Threading: called by worker thread
|
||||||
void retryOp(const opReqPtr_t &);
|
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.
|
/// Attempt to cancel a previous request.
|
||||||
/// Shadows HttpService's method as well
|
/// Shadows HttpService's method as well
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ HttpService::HttpService()
|
||||||
|
|
||||||
HttpService::~HttpService()
|
HttpService::~HttpService()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
mExitRequested = 1U;
|
mExitRequested = 1U;
|
||||||
if (RUNNING == sState)
|
if (RUNNING == sState)
|
||||||
{
|
{
|
||||||
|
|
@ -131,6 +132,7 @@ HttpService::~HttpService()
|
||||||
|
|
||||||
void HttpService::init(HttpRequestQueue * queue)
|
void HttpService::init(HttpRequestQueue * queue)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
llassert_always(! sInstance);
|
llassert_always(! sInstance);
|
||||||
llassert_always(NOT_INITIALIZED == sState);
|
llassert_always(NOT_INITIALIZED == sState);
|
||||||
sInstance = new HttpService();
|
sInstance = new HttpService();
|
||||||
|
|
@ -145,6 +147,7 @@ void HttpService::init(HttpRequestQueue * queue)
|
||||||
|
|
||||||
void HttpService::term()
|
void HttpService::term()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
if (sInstance)
|
if (sInstance)
|
||||||
{
|
{
|
||||||
if (RUNNING == sState && sInstance->mThread)
|
if (RUNNING == sState && sInstance->mThread)
|
||||||
|
|
@ -196,6 +199,7 @@ bool HttpService::isStopped()
|
||||||
/// Threading: callable by consumer thread *once*.
|
/// Threading: callable by consumer thread *once*.
|
||||||
void HttpService::startThread()
|
void HttpService::startThread()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
llassert_always(! mThread || STOPPED == sState);
|
llassert_always(! mThread || STOPPED == sState);
|
||||||
llassert_always(INITIALIZED == sState || 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
|
/// Try to find the given request handle on any of the request
|
||||||
/// queues and cancel the operation.
|
/// queues and cancel the operation.
|
||||||
///
|
///
|
||||||
|
|
@ -244,6 +232,7 @@ bool HttpService::changePriority(HttpHandle handle, HttpRequest::priority_t prio
|
||||||
/// Threading: callable by worker thread.
|
/// Threading: callable by worker thread.
|
||||||
bool HttpService::cancel(HttpHandle handle)
|
bool HttpService::cancel(HttpHandle handle)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
bool canceled(false);
|
bool canceled(false);
|
||||||
|
|
||||||
// Request can't be on request queue so skip that.
|
// Request can't be on request queue so skip that.
|
||||||
|
|
@ -264,6 +253,7 @@ bool HttpService::cancel(HttpHandle handle)
|
||||||
/// Threading: callable by worker thread.
|
/// Threading: callable by worker thread.
|
||||||
void HttpService::shutdown()
|
void HttpService::shutdown()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
// Disallow future enqueue of requests
|
// Disallow future enqueue of requests
|
||||||
mRequestQueue->stopQueue();
|
mRequestQueue->stopQueue();
|
||||||
|
|
||||||
|
|
@ -293,6 +283,8 @@ void HttpService::shutdown()
|
||||||
// requested to stop.
|
// requested to stop.
|
||||||
void HttpService::threadRun(LLCoreInt::HttpThread * thread)
|
void HttpService::threadRun(LLCoreInt::HttpThread * thread)
|
||||||
{
|
{
|
||||||
|
LL_PROFILER_SET_THREAD_NAME("HttpService");
|
||||||
|
|
||||||
boost::this_thread::disable_interruption di;
|
boost::this_thread::disable_interruption di;
|
||||||
|
|
||||||
LLThread::registerThreadID();
|
LLThread::registerThreadID();
|
||||||
|
|
@ -300,6 +292,7 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread)
|
||||||
ELoopSpeed loop(REQUEST_SLEEP);
|
ELoopSpeed loop(REQUEST_SLEEP);
|
||||||
while (! mExitRequested)
|
while (! mExitRequested)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
loop = processRequestQueue(loop);
|
loop = processRequestQueue(loop);
|
||||||
|
|
@ -344,6 +337,7 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread)
|
||||||
|
|
||||||
HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop)
|
HttpService::ELoopSpeed HttpService::processRequestQueue(ELoopSpeed loop)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpRequestQueue::OpContainer ops;
|
HttpRequestQueue::OpContainer ops;
|
||||||
const bool wait_for_req(REQUEST_SLEEP == loop);
|
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,
|
HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||||
long * ret_value)
|
long * ret_value)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
||||||
|| opt >= HttpRequest::PO_LAST // ditto
|
|| opt >= HttpRequest::PO_LAST // ditto
|
||||||
|| (! sOptionDesc[opt].mIsLong) // datatype is long
|
|| (! 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,
|
HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||||
std::string * ret_value)
|
std::string * ret_value)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||||
|
|
||||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
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,
|
HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||||
HttpRequest::policyCallback_t * ret_value)
|
HttpRequest::policyCallback_t * ret_value)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||||
|
|
||||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
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,
|
HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||||
long value, long * ret_value)
|
long value, long * ret_value)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||||
|
|
||||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
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,
|
HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||||
const std::string & value, std::string * ret_value)
|
const std::string & value, std::string * ret_value)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||||
|
|
||||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
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,
|
HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
|
||||||
HttpRequest::policyCallback_t value, HttpRequest::policyCallback_t * ret_value)
|
HttpRequest::policyCallback_t value, HttpRequest::policyCallback_t * ret_value)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
|
||||||
|
|
||||||
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
|
||||||
|
|
|
||||||
|
|
@ -146,15 +146,6 @@ public:
|
||||||
/// Threading: callable by worker thread.
|
/// Threading: callable by worker thread.
|
||||||
void shutdown();
|
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
|
/// Try to find the given request handle on any of the request
|
||||||
/// queues and cancel the operation.
|
/// queues and cancel the operation.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -469,11 +469,11 @@ bool WorkingSet::reload(LLCore::HttpRequest * hr, LLCore::HttpOptions::ptr_t & o
|
||||||
LLCore::HttpHandle handle;
|
LLCore::HttpHandle handle;
|
||||||
if (offset || length)
|
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
|
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)
|
if (! handle)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@
|
||||||
#include "_httppolicy.h"
|
#include "_httppolicy.h"
|
||||||
#include "_httpoperation.h"
|
#include "_httpoperation.h"
|
||||||
#include "_httpoprequest.h"
|
#include "_httpoprequest.h"
|
||||||
#include "_httpopsetpriority.h"
|
|
||||||
#include "_httpopcancel.h"
|
#include "_httpopcancel.h"
|
||||||
#include "_httpopsetget.h"
|
#include "_httpopsetget.h"
|
||||||
|
|
||||||
|
|
@ -183,16 +182,16 @@ HttpStatus HttpRequest::getStatus() const
|
||||||
|
|
||||||
|
|
||||||
HttpHandle HttpRequest::requestGet(policy_t policy_id,
|
HttpHandle HttpRequest::requestGet(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers,
|
const HttpHeaders::ptr_t & headers,
|
||||||
HttpHandler::ptr_t user_handler)
|
HttpHandler::ptr_t user_handler)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpStatus status;
|
HttpStatus status;
|
||||||
|
|
||||||
HttpOpRequest::ptr_t op(new HttpOpRequest());
|
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;
|
mLastReqStatus = status;
|
||||||
return LLCORE_HTTP_HANDLE_INVALID;
|
return LLCORE_HTTP_HANDLE_INVALID;
|
||||||
|
|
@ -210,7 +209,6 @@ HttpHandle HttpRequest::requestGet(policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
|
HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
size_t offset,
|
size_t offset,
|
||||||
size_t len,
|
size_t len,
|
||||||
|
|
@ -218,10 +216,11 @@ HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
|
||||||
const HttpHeaders::ptr_t & headers,
|
const HttpHeaders::ptr_t & headers,
|
||||||
HttpHandler::ptr_t user_handler)
|
HttpHandler::ptr_t user_handler)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
|
||||||
HttpStatus status;
|
HttpStatus status;
|
||||||
|
|
||||||
HttpOpRequest::ptr_t op(new HttpOpRequest());
|
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;
|
mLastReqStatus = status;
|
||||||
return LLCORE_HTTP_HANDLE_INVALID;
|
return LLCORE_HTTP_HANDLE_INVALID;
|
||||||
|
|
@ -239,7 +238,6 @@ HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
HttpHandle HttpRequest::requestPost(policy_t policy_id,
|
HttpHandle HttpRequest::requestPost(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
|
|
@ -249,7 +247,7 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id,
|
||||||
HttpStatus status;
|
HttpStatus status;
|
||||||
|
|
||||||
HttpOpRequest::ptr_t op(new HttpOpRequest());
|
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;
|
mLastReqStatus = status;
|
||||||
return LLCORE_HTTP_HANDLE_INVALID;
|
return LLCORE_HTTP_HANDLE_INVALID;
|
||||||
|
|
@ -267,7 +265,6 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id,
|
||||||
|
|
||||||
|
|
||||||
HttpHandle HttpRequest::requestPut(policy_t policy_id,
|
HttpHandle HttpRequest::requestPut(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
|
|
@ -277,7 +274,7 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,
|
||||||
HttpStatus status;
|
HttpStatus status;
|
||||||
|
|
||||||
HttpOpRequest::ptr_t op (new HttpOpRequest());
|
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;
|
mLastReqStatus = status;
|
||||||
return LLCORE_HTTP_HANDLE_INVALID;
|
return LLCORE_HTTP_HANDLE_INVALID;
|
||||||
|
|
@ -294,7 +291,6 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpHandle HttpRequest::requestDelete(policy_t policy_id,
|
HttpHandle HttpRequest::requestDelete(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers,
|
const HttpHeaders::ptr_t & headers,
|
||||||
|
|
@ -303,7 +299,7 @@ HttpHandle HttpRequest::requestDelete(policy_t policy_id,
|
||||||
HttpStatus status;
|
HttpStatus status;
|
||||||
|
|
||||||
HttpOpRequest::ptr_t op(new HttpOpRequest());
|
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;
|
mLastReqStatus = status;
|
||||||
return LLCORE_HTTP_HANDLE_INVALID;
|
return LLCORE_HTTP_HANDLE_INVALID;
|
||||||
|
|
@ -320,7 +316,6 @@ HttpHandle HttpRequest::requestDelete(policy_t policy_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpHandle HttpRequest::requestPatch(policy_t policy_id,
|
HttpHandle HttpRequest::requestPatch(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
|
|
@ -330,7 +325,7 @@ HttpHandle HttpRequest::requestPatch(policy_t policy_id,
|
||||||
HttpStatus status;
|
HttpStatus status;
|
||||||
|
|
||||||
HttpOpRequest::ptr_t op (new HttpOpRequest());
|
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;
|
mLastReqStatus = status;
|
||||||
return LLCORE_HTTP_HANDLE_INVALID;
|
return LLCORE_HTTP_HANDLE_INVALID;
|
||||||
|
|
@ -347,7 +342,6 @@ HttpHandle HttpRequest::requestPatch(policy_t policy_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpHandle HttpRequest::requestCopy(policy_t policy_id,
|
HttpHandle HttpRequest::requestCopy(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers,
|
const HttpHeaders::ptr_t & headers,
|
||||||
|
|
@ -356,7 +350,7 @@ HttpHandle HttpRequest::requestCopy(policy_t policy_id,
|
||||||
HttpStatus status;
|
HttpStatus status;
|
||||||
|
|
||||||
HttpOpRequest::ptr_t op(new HttpOpRequest());
|
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;
|
mLastReqStatus = status;
|
||||||
return LLCORE_HTTP_HANDLE_INVALID;
|
return LLCORE_HTTP_HANDLE_INVALID;
|
||||||
|
|
@ -374,7 +368,6 @@ HttpHandle HttpRequest::requestCopy(policy_t policy_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpHandle HttpRequest::requestMove(policy_t policy_id,
|
HttpHandle HttpRequest::requestMove(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers,
|
const HttpHeaders::ptr_t & headers,
|
||||||
|
|
@ -383,7 +376,7 @@ HttpHandle HttpRequest::requestMove(policy_t policy_id,
|
||||||
HttpStatus status;
|
HttpStatus status;
|
||||||
|
|
||||||
HttpOpRequest::ptr_t op (new HttpOpRequest());
|
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;
|
mLastReqStatus = status;
|
||||||
return LLCORE_HTTP_HANDLE_INVALID;
|
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
|
// Utility Methods
|
||||||
// ====================================
|
// ====================================
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,6 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef unsigned int policy_t;
|
typedef unsigned int policy_t;
|
||||||
typedef unsigned int priority_t;
|
|
||||||
|
|
||||||
typedef boost::shared_ptr<HttpRequest> ptr_t;
|
typedef boost::shared_ptr<HttpRequest> ptr_t;
|
||||||
typedef boost::weak_ptr<HttpRequest> wptr_t;
|
typedef boost::weak_ptr<HttpRequest> wptr_t;
|
||||||
|
|
@ -316,8 +315,6 @@ public:
|
||||||
///
|
///
|
||||||
/// @param policy_id Default or user-defined policy class under
|
/// @param policy_id Default or user-defined policy class under
|
||||||
/// which this request is to be serviced.
|
/// 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
|
/// @param url URL with any encoded query parameters to
|
||||||
/// be accessed.
|
/// be accessed.
|
||||||
/// @param options Optional instance of an HttpOptions object
|
/// @param options Optional instance of an HttpOptions object
|
||||||
|
|
@ -346,7 +343,6 @@ public:
|
||||||
/// case, @see getStatus() will return more info.
|
/// case, @see getStatus() will return more info.
|
||||||
///
|
///
|
||||||
HttpHandle requestGet(policy_t policy_id,
|
HttpHandle requestGet(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers,
|
const HttpHeaders::ptr_t & headers,
|
||||||
|
|
@ -377,7 +373,6 @@ public:
|
||||||
/// - Referer:
|
/// - Referer:
|
||||||
///
|
///
|
||||||
/// @param policy_id @see requestGet()
|
/// @param policy_id @see requestGet()
|
||||||
/// @param priority "
|
|
||||||
/// @param url "
|
/// @param url "
|
||||||
/// @param offset Offset of first byte into resource to be returned.
|
/// @param offset Offset of first byte into resource to be returned.
|
||||||
/// @param len Count of bytes to be returned
|
/// @param len Count of bytes to be returned
|
||||||
|
|
@ -387,7 +382,6 @@ public:
|
||||||
/// @return "
|
/// @return "
|
||||||
///
|
///
|
||||||
HttpHandle requestGetByteRange(policy_t policy_id,
|
HttpHandle requestGetByteRange(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
size_t offset,
|
size_t offset,
|
||||||
size_t len,
|
size_t len,
|
||||||
|
|
@ -418,7 +412,6 @@ public:
|
||||||
/// - Expect:
|
/// - Expect:
|
||||||
///
|
///
|
||||||
/// @param policy_id @see requestGet()
|
/// @param policy_id @see requestGet()
|
||||||
/// @param priority "
|
|
||||||
/// @param url "
|
/// @param url "
|
||||||
/// @param body Byte stream to be sent as the body. No
|
/// @param body Byte stream to be sent as the body. No
|
||||||
/// further encoding or escaping will be done
|
/// further encoding or escaping will be done
|
||||||
|
|
@ -429,7 +422,6 @@ public:
|
||||||
/// @return "
|
/// @return "
|
||||||
///
|
///
|
||||||
HttpHandle requestPost(policy_t policy_id,
|
HttpHandle requestPost(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
|
|
@ -459,7 +451,6 @@ public:
|
||||||
/// - Content-Type:
|
/// - Content-Type:
|
||||||
///
|
///
|
||||||
/// @param policy_id @see requestGet()
|
/// @param policy_id @see requestGet()
|
||||||
/// @param priority "
|
|
||||||
/// @param url "
|
/// @param url "
|
||||||
/// @param body Byte stream to be sent as the body. No
|
/// @param body Byte stream to be sent as the body. No
|
||||||
/// further encoding or escaping will be done
|
/// further encoding or escaping will be done
|
||||||
|
|
@ -470,7 +461,6 @@ public:
|
||||||
/// @return "
|
/// @return "
|
||||||
///
|
///
|
||||||
HttpHandle requestPut(policy_t policy_id,
|
HttpHandle requestPut(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
|
|
@ -483,7 +473,6 @@ public:
|
||||||
/// encoding and communicating the content types.
|
/// encoding and communicating the content types.
|
||||||
///
|
///
|
||||||
/// @param policy_id @see requestGet()
|
/// @param policy_id @see requestGet()
|
||||||
/// @param priority "
|
|
||||||
/// @param url "
|
/// @param url "
|
||||||
/// @param options @see requestGet()K(optional)
|
/// @param options @see requestGet()K(optional)
|
||||||
/// @param headers "
|
/// @param headers "
|
||||||
|
|
@ -491,7 +480,6 @@ public:
|
||||||
/// @return "
|
/// @return "
|
||||||
///
|
///
|
||||||
HttpHandle requestDelete(policy_t policy_id,
|
HttpHandle requestDelete(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers,
|
const HttpHeaders::ptr_t & headers,
|
||||||
|
|
@ -502,7 +490,6 @@ public:
|
||||||
/// encoding and communicating the content types.
|
/// encoding and communicating the content types.
|
||||||
///
|
///
|
||||||
/// @param policy_id @see requestGet()
|
/// @param policy_id @see requestGet()
|
||||||
/// @param priority "
|
|
||||||
/// @param url "
|
/// @param url "
|
||||||
/// @param body Byte stream to be sent as the body. No
|
/// @param body Byte stream to be sent as the body. No
|
||||||
/// further encoding or escaping will be done
|
/// further encoding or escaping will be done
|
||||||
|
|
@ -513,7 +500,6 @@ public:
|
||||||
/// @return "
|
/// @return "
|
||||||
///
|
///
|
||||||
HttpHandle requestPatch(policy_t policy_id,
|
HttpHandle requestPatch(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
BufferArray * body,
|
BufferArray * body,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
|
|
@ -525,7 +511,6 @@ public:
|
||||||
/// encoding and communicating the content types.
|
/// encoding and communicating the content types.
|
||||||
///
|
///
|
||||||
/// @param policy_id @see requestGet()
|
/// @param policy_id @see requestGet()
|
||||||
/// @param priority "
|
|
||||||
/// @param url "
|
/// @param url "
|
||||||
/// @param options @see requestGet()K(optional)
|
/// @param options @see requestGet()K(optional)
|
||||||
/// @param headers "
|
/// @param headers "
|
||||||
|
|
@ -533,7 +518,6 @@ public:
|
||||||
/// @return "
|
/// @return "
|
||||||
///
|
///
|
||||||
HttpHandle requestCopy(policy_t policy_id,
|
HttpHandle requestCopy(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers,
|
const HttpHeaders::ptr_t & headers,
|
||||||
|
|
@ -544,7 +528,6 @@ public:
|
||||||
/// encoding and communicating the content types.
|
/// encoding and communicating the content types.
|
||||||
///
|
///
|
||||||
/// @param policy_id @see requestGet()
|
/// @param policy_id @see requestGet()
|
||||||
/// @param priority "
|
|
||||||
/// @param url "
|
/// @param url "
|
||||||
/// @param options @see requestGet()K(optional)
|
/// @param options @see requestGet()K(optional)
|
||||||
/// @param headers "
|
/// @param headers "
|
||||||
|
|
@ -552,7 +535,6 @@ public:
|
||||||
/// @return "
|
/// @return "
|
||||||
///
|
///
|
||||||
HttpHandle requestMove(policy_t policy_id,
|
HttpHandle requestMove(policy_t policy_id,
|
||||||
priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const HttpOptions::ptr_t & options,
|
const HttpOptions::ptr_t & options,
|
||||||
const HttpHeaders::ptr_t & headers,
|
const HttpHeaders::ptr_t & headers,
|
||||||
|
|
@ -593,18 +575,6 @@ public:
|
||||||
|
|
||||||
HttpHandle requestCancel(HttpHandle request, HttpHandler::ptr_t);
|
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
|
/// @name UtilityMethods
|
||||||
|
|
|
||||||
|
|
@ -614,7 +614,6 @@ void HttpRequestTestObjectType::test<7>()
|
||||||
// Issue a GET that can't connect
|
// Issue a GET that can't connect
|
||||||
mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT);
|
mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT);
|
||||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
"http://127.0.0.1:2/nothing/here",
|
"http://127.0.0.1:2/nothing/here",
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
@ -716,7 +715,6 @@ void HttpRequestTestObjectType::test<8>()
|
||||||
// Issue a GET that *can* connect
|
// Issue a GET that *can* connect
|
||||||
mStatus = HttpStatus(200);
|
mStatus = HttpStatus(200);
|
||||||
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base,
|
url_base,
|
||||||
HttpOptions::ptr_t(),
|
HttpOptions::ptr_t(),
|
||||||
HttpHeaders::ptr_t(),
|
HttpHeaders::ptr_t(),
|
||||||
|
|
@ -812,7 +810,6 @@ void HttpRequestTestObjectType::test<9>()
|
||||||
// Issue a GET that *can* connect
|
// Issue a GET that *can* connect
|
||||||
mStatus = HttpStatus(200);
|
mStatus = HttpStatus(200);
|
||||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base,
|
url_base,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
@ -913,7 +910,6 @@ void HttpRequestTestObjectType::test<10>()
|
||||||
body->append(body_text, strlen(body_text));
|
body->append(body_text, strlen(body_text));
|
||||||
mStatus = HttpStatus(200);
|
mStatus = HttpStatus(200);
|
||||||
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base,
|
url_base,
|
||||||
body,
|
body,
|
||||||
HttpOptions::ptr_t(),
|
HttpOptions::ptr_t(),
|
||||||
|
|
@ -1020,7 +1016,6 @@ void HttpRequestTestObjectType::test<11>()
|
||||||
body->append(body_text, strlen(body_text));
|
body->append(body_text, strlen(body_text));
|
||||||
mStatus = HttpStatus(200);
|
mStatus = HttpStatus(200);
|
||||||
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base,
|
url_base,
|
||||||
body,
|
body,
|
||||||
HttpOptions::ptr_t(),
|
HttpOptions::ptr_t(),
|
||||||
|
|
@ -1127,7 +1122,6 @@ void HttpRequestTestObjectType::test<12>()
|
||||||
// Issue a GET that *can* connect
|
// Issue a GET that *can* connect
|
||||||
mStatus = HttpStatus(200);
|
mStatus = HttpStatus(200);
|
||||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base,
|
url_base,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
@ -1240,7 +1234,6 @@ void HttpRequestTestObjectType::test<13>()
|
||||||
regex_container_t::value_type(boost::regex("X-LL-Special", boost::regex::icase),
|
regex_container_t::value_type(boost::regex("X-LL-Special", boost::regex::icase),
|
||||||
boost::regex(".*", boost::regex::icase)));
|
boost::regex(".*", boost::regex::icase)));
|
||||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base,
|
url_base,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
@ -1346,7 +1339,6 @@ void HttpRequestTestObjectType::test<14>()
|
||||||
// Issue a GET that sleeps
|
// Issue a GET that sleeps
|
||||||
mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT);
|
mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT);
|
||||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base,
|
url_base,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
@ -1454,7 +1446,6 @@ void HttpRequestTestObjectType::test<15>()
|
||||||
mStatus = HttpStatus(200);
|
mStatus = HttpStatus(200);
|
||||||
handler.mCheckContentType = "application/llsd+xml";
|
handler.mCheckContentType = "application/llsd+xml";
|
||||||
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base,
|
url_base,
|
||||||
HttpOptions::ptr_t(),
|
HttpOptions::ptr_t(),
|
||||||
HttpHeaders::ptr_t(),
|
HttpHeaders::ptr_t(),
|
||||||
|
|
@ -1609,7 +1600,6 @@ void HttpRequestTestObjectType::test<16>()
|
||||||
boost::regex("X-Reflect-content-encoding", boost::regex::icase),
|
boost::regex("X-Reflect-content-encoding", boost::regex::icase),
|
||||||
boost::regex(".*", boost::regex::icase)));
|
boost::regex(".*", boost::regex::icase)));
|
||||||
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base + "reflect/",
|
url_base + "reflect/",
|
||||||
options,
|
options,
|
||||||
HttpHeaders::ptr_t(),
|
HttpHeaders::ptr_t(),
|
||||||
|
|
@ -1684,7 +1674,6 @@ void HttpRequestTestObjectType::test<16>()
|
||||||
boost::regex("X-Reflect-content-encoding", boost::regex::icase),
|
boost::regex("X-Reflect-content-encoding", boost::regex::icase),
|
||||||
boost::regex(".*", boost::regex::icase)));
|
boost::regex(".*", boost::regex::icase)));
|
||||||
handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base + "reflect/",
|
url_base + "reflect/",
|
||||||
0,
|
0,
|
||||||
47,
|
47,
|
||||||
|
|
@ -1863,7 +1852,6 @@ void HttpRequestTestObjectType::test<17>()
|
||||||
boost::regex("X-Reflect-transfer_encoding", boost::regex::icase),
|
boost::regex("X-Reflect-transfer_encoding", boost::regex::icase),
|
||||||
boost::regex(".*chunked.*", boost::regex::icase)));
|
boost::regex(".*chunked.*", boost::regex::icase)));
|
||||||
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base + "reflect/",
|
url_base + "reflect/",
|
||||||
ba,
|
ba,
|
||||||
options,
|
options,
|
||||||
|
|
@ -2049,7 +2037,6 @@ void HttpRequestTestObjectType::test<18>()
|
||||||
boost::regex(".*", boost::regex::icase)));
|
boost::regex(".*", boost::regex::icase)));
|
||||||
|
|
||||||
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base + "reflect/",
|
url_base + "reflect/",
|
||||||
ba,
|
ba,
|
||||||
options,
|
options,
|
||||||
|
|
@ -2249,7 +2236,6 @@ void HttpRequestTestObjectType::test<19>()
|
||||||
boost::regex("X-Reflect-content-encoding", boost::regex::icase),
|
boost::regex("X-Reflect-content-encoding", boost::regex::icase),
|
||||||
boost::regex(".*", boost::regex::icase)));
|
boost::regex(".*", boost::regex::icase)));
|
||||||
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base + "reflect/",
|
url_base + "reflect/",
|
||||||
options,
|
options,
|
||||||
headers,
|
headers,
|
||||||
|
|
@ -2457,7 +2443,6 @@ void HttpRequestTestObjectType::test<20>()
|
||||||
boost::regex(".*", boost::regex::icase)));
|
boost::regex(".*", boost::regex::icase)));
|
||||||
|
|
||||||
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base + "reflect/",
|
url_base + "reflect/",
|
||||||
ba,
|
ba,
|
||||||
options,
|
options,
|
||||||
|
|
@ -2666,7 +2651,6 @@ void HttpRequestTestObjectType::test<21>()
|
||||||
boost::regex("X-Reflect-content-type", boost::regex::icase),
|
boost::regex("X-Reflect-content-type", boost::regex::icase),
|
||||||
boost::regex("text/html", boost::regex::icase)));
|
boost::regex("text/html", boost::regex::icase)));
|
||||||
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base + "reflect/",
|
url_base + "reflect/",
|
||||||
ba,
|
ba,
|
||||||
options,
|
options,
|
||||||
|
|
@ -2797,7 +2781,6 @@ void HttpRequestTestObjectType::test<22>()
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
sprintf(buffer, "/bug2295/%d/", i);
|
sprintf(buffer, "/bug2295/%d/", i);
|
||||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base + buffer,
|
url_base + buffer,
|
||||||
0,
|
0,
|
||||||
25,
|
25,
|
||||||
|
|
@ -2829,7 +2812,6 @@ void HttpRequestTestObjectType::test<22>()
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
sprintf(buffer, "/bug2295/00000012/%d/", i);
|
sprintf(buffer, "/bug2295/00000012/%d/", i);
|
||||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base + buffer,
|
url_base + buffer,
|
||||||
0,
|
0,
|
||||||
25,
|
25,
|
||||||
|
|
@ -2861,7 +2843,6 @@ void HttpRequestTestObjectType::test<22>()
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
sprintf(buffer, "/bug2295/inv_cont_range/%d/", i);
|
sprintf(buffer, "/bug2295/inv_cont_range/%d/", i);
|
||||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url_base + buffer,
|
url_base + buffer,
|
||||||
0,
|
0,
|
||||||
25,
|
25,
|
||||||
|
|
@ -2984,7 +2965,6 @@ void HttpRequestTestObjectType::test<23>()
|
||||||
std::ostringstream url;
|
std::ostringstream url;
|
||||||
url << url_base << i << "/";
|
url << url_base << i << "/";
|
||||||
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
|
||||||
0U,
|
|
||||||
url.str(),
|
url.str(),
|
||||||
0,
|
0,
|
||||||
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));
|
updateApplication(llformat("%s, try %d...", msg.c_str(), i+1));
|
||||||
|
|
||||||
LL_INFOS("CRASHREPORT") << "POST crash data to " << host << LL_ENDL;
|
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));
|
host, data, httpOpts, LLCore::HttpHeaders::ptr_t(), LLCore::HttpHandler::ptr_t(new LLCrashLoggerHandler));
|
||||||
|
|
||||||
if (handle == LLCORE_HTTP_HANDLE_INVALID)
|
if (handle == LLCORE_HTTP_HANDLE_INVALID)
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,7 @@ const std::string LLDiskCache::assetTypeToString(LLAssetType::EType at)
|
||||||
{ LLAssetType::AT_PERSON, "PERSON" },
|
{ LLAssetType::AT_PERSON, "PERSON" },
|
||||||
{ LLAssetType::AT_MESH, "MESH" },
|
{ LLAssetType::AT_MESH, "MESH" },
|
||||||
{ LLAssetType::AT_SETTINGS, "SETTINGS" },
|
{ LLAssetType::AT_SETTINGS, "SETTINGS" },
|
||||||
|
{ LLAssetType::AT_MATERIAL, "MATERIAL" },
|
||||||
{ LLAssetType::AT_UNKNOWN, "UNKNOWN" }
|
{ LLAssetType::AT_UNKNOWN, "UNKNOWN" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,7 @@ void LLLFSThread::initClass(bool local_is_threaded)
|
||||||
//static
|
//static
|
||||||
S32 LLLFSThread::updateClass(U32 ms_elapsed)
|
S32 LLLFSThread::updateClass(U32 ms_elapsed)
|
||||||
{
|
{
|
||||||
sLocal->update((F32)ms_elapsed);
|
return sLocal->update((F32)ms_elapsed);
|
||||||
return sLocal->getPending();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
|
|
@ -58,6 +57,7 @@ void LLLFSThread::cleanupClass()
|
||||||
{
|
{
|
||||||
sLocal->update(0);
|
sLocal->update(0);
|
||||||
}
|
}
|
||||||
|
sLocal->shutdown();
|
||||||
delete sLocal;
|
delete sLocal;
|
||||||
sLocal = NULL;
|
sLocal = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -65,8 +65,7 @@ void LLLFSThread::cleanupClass()
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
LLLFSThread::LLLFSThread(bool threaded) :
|
LLLFSThread::LLLFSThread(bool threaded) :
|
||||||
LLQueuedThread("LFS", threaded),
|
LLQueuedThread("LFS", threaded)
|
||||||
mPriorityCounter(PRIORITY_LOWBITS)
|
|
||||||
{
|
{
|
||||||
if(!mLocalAPRFilePoolp)
|
if(!mLocalAPRFilePoolp)
|
||||||
{
|
{
|
||||||
|
|
@ -84,14 +83,12 @@ LLLFSThread::~LLLFSThread()
|
||||||
|
|
||||||
LLLFSThread::handle_t LLLFSThread::read(const std::string& filename, /* Flawfinder: ignore */
|
LLLFSThread::handle_t LLLFSThread::read(const std::string& filename, /* Flawfinder: ignore */
|
||||||
U8* buffer, S32 offset, S32 numbytes,
|
U8* buffer, S32 offset, S32 numbytes,
|
||||||
Responder* responder, U32 priority)
|
Responder* responder)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
handle_t handle = generateHandle();
|
handle_t handle = generateHandle();
|
||||||
|
|
||||||
if (priority == 0) priority = PRIORITY_NORMAL | priorityCounter();
|
Request* req = new Request(this, handle,
|
||||||
else if (priority < PRIORITY_LOW) priority |= PRIORITY_LOW; // All reads are at least PRIORITY_LOW
|
|
||||||
|
|
||||||
Request* req = new Request(this, handle, priority,
|
|
||||||
FILE_READ, filename,
|
FILE_READ, filename,
|
||||||
buffer, offset, numbytes,
|
buffer, offset, numbytes,
|
||||||
responder);
|
responder);
|
||||||
|
|
@ -107,13 +104,12 @@ LLLFSThread::handle_t LLLFSThread::read(const std::string& filename, /* Flawfind
|
||||||
|
|
||||||
LLLFSThread::handle_t LLLFSThread::write(const std::string& filename,
|
LLLFSThread::handle_t LLLFSThread::write(const std::string& filename,
|
||||||
U8* buffer, S32 offset, S32 numbytes,
|
U8* buffer, S32 offset, S32 numbytes,
|
||||||
Responder* responder, U32 priority)
|
Responder* responder)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
handle_t handle = generateHandle();
|
handle_t handle = generateHandle();
|
||||||
|
|
||||||
if (priority == 0) priority = PRIORITY_LOW | priorityCounter();
|
Request* req = new Request(this, handle,
|
||||||
|
|
||||||
Request* req = new Request(this, handle, priority,
|
|
||||||
FILE_WRITE, filename,
|
FILE_WRITE, filename,
|
||||||
buffer, offset, numbytes,
|
buffer, offset, numbytes,
|
||||||
responder);
|
responder);
|
||||||
|
|
@ -130,11 +126,11 @@ LLLFSThread::handle_t LLLFSThread::write(const std::string& filename,
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
LLLFSThread::Request::Request(LLLFSThread* thread,
|
LLLFSThread::Request::Request(LLLFSThread* thread,
|
||||||
handle_t handle, U32 priority,
|
handle_t handle,
|
||||||
operation_t op, const std::string& filename,
|
operation_t op, const std::string& filename,
|
||||||
U8* buffer, S32 offset, S32 numbytes,
|
U8* buffer, S32 offset, S32 numbytes,
|
||||||
Responder* responder) :
|
Responder* responder) :
|
||||||
QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE),
|
QueuedRequest(handle, FLAG_AUTO_COMPLETE),
|
||||||
mThread(thread),
|
mThread(thread),
|
||||||
mOperation(op),
|
mOperation(op),
|
||||||
mFileName(filename),
|
mFileName(filename),
|
||||||
|
|
@ -157,6 +153,7 @@ LLLFSThread::Request::~Request()
|
||||||
// virtual, called from own thread
|
// virtual, called from own thread
|
||||||
void LLLFSThread::Request::finishRequest(bool completed)
|
void LLLFSThread::Request::finishRequest(bool completed)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
if (mResponder.notNull())
|
if (mResponder.notNull())
|
||||||
{
|
{
|
||||||
mResponder->completed(completed ? mBytesRead : 0);
|
mResponder->completed(completed ? mBytesRead : 0);
|
||||||
|
|
@ -166,6 +163,7 @@ void LLLFSThread::Request::finishRequest(bool completed)
|
||||||
|
|
||||||
void LLLFSThread::Request::deleteRequest()
|
void LLLFSThread::Request::deleteRequest()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
if (getStatus() == STATUS_QUEUED)
|
if (getStatus() == STATUS_QUEUED)
|
||||||
{
|
{
|
||||||
LL_ERRS() << "Attempt to delete a queued LLLFSThread::Request!" << LL_ENDL;
|
LL_ERRS() << "Attempt to delete a queued LLLFSThread::Request!" << LL_ENDL;
|
||||||
|
|
@ -180,6 +178,7 @@ void LLLFSThread::Request::deleteRequest()
|
||||||
|
|
||||||
bool LLLFSThread::Request::processRequest()
|
bool LLLFSThread::Request::processRequest()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
bool complete = false;
|
bool complete = false;
|
||||||
if (mOperation == FILE_READ)
|
if (mOperation == FILE_READ)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Request(LLLFSThread* thread,
|
Request(LLLFSThread* thread,
|
||||||
handle_t handle, U32 priority,
|
handle_t handle,
|
||||||
operation_t op, const std::string& filename,
|
operation_t op, const std::string& filename,
|
||||||
U8* buffer, S32 offset, S32 numbytes,
|
U8* buffer, S32 offset, S32 numbytes,
|
||||||
Responder* responder);
|
Responder* responder);
|
||||||
|
|
@ -120,23 +120,16 @@ public:
|
||||||
// Return a Request handle
|
// Return a Request handle
|
||||||
handle_t read(const std::string& filename, /* Flawfinder: ignore */
|
handle_t read(const std::string& filename, /* Flawfinder: ignore */
|
||||||
U8* buffer, S32 offset, S32 numbytes,
|
U8* buffer, S32 offset, S32 numbytes,
|
||||||
Responder* responder, U32 pri=0);
|
Responder* responder);
|
||||||
handle_t write(const std::string& filename,
|
handle_t write(const std::string& filename,
|
||||||
U8* buffer, S32 offset, S32 numbytes,
|
U8* buffer, S32 offset, S32 numbytes,
|
||||||
Responder* responder, U32 pri=0);
|
Responder* responder);
|
||||||
|
|
||||||
// Misc
|
|
||||||
U32 priorityCounter() { return mPriorityCounter-- & PRIORITY_LOWBITS; } // Use to order IO operations
|
|
||||||
|
|
||||||
// static initializers
|
// static initializers
|
||||||
static void initClass(bool local_is_threaded = TRUE); // Setup sLocal
|
static void initClass(bool local_is_threaded = TRUE); // Setup sLocal
|
||||||
static S32 updateClass(U32 ms_elapsed);
|
static S32 updateClass(U32 ms_elapsed);
|
||||||
static void cleanupClass(); // Delete sLocal
|
static void cleanupClass(); // Delete sLocal
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
U32 mPriorityCounter;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static LLLFSThread* sLocal; // Default local file thread
|
static LLLFSThread* sLocal; // Default local file thread
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -798,7 +798,6 @@ U8* LLImageBase::allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 si
|
||||||
// LLImageRaw
|
// LLImageRaw
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
S32 LLImageRaw::sGlobalRawMemory = 0;
|
|
||||||
S32 LLImageRaw::sRawImageCount = 0;
|
S32 LLImageRaw::sRawImageCount = 0;
|
||||||
|
|
||||||
LLImageRaw::LLImageRaw()
|
LLImageRaw::LLImageRaw()
|
||||||
|
|
@ -815,6 +814,15 @@ LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components)
|
||||||
++sRawImageCount;
|
++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)
|
LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components, bool no_copy)
|
||||||
: LLImageBase()
|
: LLImageBase()
|
||||||
{
|
{
|
||||||
|
|
@ -847,16 +855,13 @@ LLImageRaw::~LLImageRaw()
|
||||||
U8* LLImageRaw::allocateData(S32 size)
|
U8* LLImageRaw::allocateData(S32 size)
|
||||||
{
|
{
|
||||||
U8* res = LLImageBase::allocateData(size);
|
U8* res = LLImageBase::allocateData(size);
|
||||||
sGlobalRawMemory += getDataSize();
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
U8* LLImageRaw::reallocateData(S32 size)
|
U8* LLImageRaw::reallocateData(S32 size)
|
||||||
{
|
{
|
||||||
sGlobalRawMemory -= getDataSize();
|
|
||||||
U8* res = LLImageBase::reallocateData(size);
|
U8* res = LLImageBase::reallocateData(size);
|
||||||
sGlobalRawMemory += getDataSize();
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -869,7 +874,6 @@ void LLImageRaw::releaseData()
|
||||||
// virtual
|
// virtual
|
||||||
void LLImageRaw::deleteData()
|
void LLImageRaw::deleteData()
|
||||||
{
|
{
|
||||||
sGlobalRawMemory -= getDataSize();
|
|
||||||
LLImageBase::deleteData();
|
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)
|
void LLImageRaw::expandToPowerOfTwo(S32 max_dim, bool scale_image)
|
||||||
{
|
{
|
||||||
// Find new sizes
|
// Find new sizes
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
LLImageRaw();
|
LLImageRaw();
|
||||||
LLImageRaw(U16 width, U16 height, S8 components);
|
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);
|
LLImageRaw(U8 *data, U16 width, U16 height, S8 components, bool no_copy = false);
|
||||||
// Construct using createFromFile (used by tools)
|
// Construct using createFromFile (used by tools)
|
||||||
//LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
|
//LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
|
||||||
|
|
@ -208,6 +209,10 @@ public:
|
||||||
|
|
||||||
void verticalFlip();
|
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 biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
|
||||||
static S32 expandDimToPowerOfTwo(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);
|
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) ;
|
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static S32 sGlobalRawMemory;
|
|
||||||
static S32 sRawImageCount;
|
static S32 sRawImageCount;
|
||||||
|
|
||||||
private:
|
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)
|
bool LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||||
return decodeChannels(raw_imagep, decode_time, 0, 4);
|
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.
|
// 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 )
|
bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||||
LLTimer elapsed;
|
LLTimer elapsed;
|
||||||
|
|
||||||
bool res = true;
|
bool res = true;
|
||||||
|
|
|
||||||
|
|
@ -28,64 +28,93 @@
|
||||||
|
|
||||||
#include "llimageworker.h"
|
#include "llimageworker.h"
|
||||||
#include "llimagedxt.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
|
// MAIN THREAD
|
||||||
LLImageDecodeThread::LLImageDecodeThread(bool threaded)
|
LLImageDecodeThread::LLImageDecodeThread(bool /*threaded*/)
|
||||||
: LLQueuedThread("imagedecode", threaded)
|
|
||||||
{
|
{
|
||||||
mCreationMutex = new LLMutex();
|
mThreadPool.reset(new LL::ThreadPool("ImageDecode", 8));
|
||||||
|
mThreadPool->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
//virtual
|
//virtual
|
||||||
LLImageDecodeThread::~LLImageDecodeThread()
|
LLImageDecodeThread::~LLImageDecodeThread()
|
||||||
{
|
{}
|
||||||
delete mCreationMutex ;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MAIN THREAD
|
// MAIN THREAD
|
||||||
// virtual
|
// virtual
|
||||||
size_t LLImageDecodeThread::update(F32 max_time_ms)
|
size_t LLImageDecodeThread::update(F32 max_time_ms)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||||
LLMutexLock lock(mCreationMutex);
|
return getPending();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image,
|
size_t LLImageDecodeThread::getPending()
|
||||||
U32 priority, S32 discard, BOOL needs_aux, Responder* responder)
|
{
|
||||||
|
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;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||||
LLMutexLock lock(mCreationMutex);
|
|
||||||
handle_t handle = generateHandle();
|
// Instantiate the ImageRequest right in the lambda, why not?
|
||||||
mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
|
bool posted = mThreadPool->getQueue().post(
|
||||||
return handle;
|
[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
|
void LLImageDecodeThread::shutdown()
|
||||||
// Returns the size of the mutex guarded list as an indication of sanity
|
|
||||||
S32 LLImageDecodeThread::tut_size()
|
|
||||||
{
|
{
|
||||||
LLMutexLock lock(mCreationMutex);
|
mThreadPool->close();
|
||||||
S32 res = mCreationList.size();
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLImageDecodeThread::Responder::~Responder()
|
LLImageDecodeThread::Responder::~Responder()
|
||||||
|
|
@ -94,11 +123,10 @@ LLImageDecodeThread::Responder::~Responder()
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatted* image,
|
ImageRequest::ImageRequest(const LLPointer<LLImageFormatted>& image,
|
||||||
U32 priority, S32 discard, BOOL needs_aux,
|
S32 discard, BOOL needs_aux,
|
||||||
LLImageDecodeThread::Responder* responder)
|
const LLPointer<LLImageDecodeThread::Responder>& responder)
|
||||||
: LLQueuedThread::QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE),
|
: mFormattedImage(image),
|
||||||
mFormattedImage(image),
|
|
||||||
mDiscardLevel(discard),
|
mDiscardLevel(discard),
|
||||||
mNeedsAux(needs_aux),
|
mNeedsAux(needs_aux),
|
||||||
mDecodedRaw(FALSE),
|
mDecodedRaw(FALSE),
|
||||||
|
|
@ -107,7 +135,7 @@ LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatte
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
LLImageDecodeThread::ImageRequest::~ImageRequest()
|
ImageRequest::~ImageRequest()
|
||||||
{
|
{
|
||||||
mDecodedImageRaw = NULL;
|
mDecodedImageRaw = NULL;
|
||||||
mDecodedImageAux = NULL;
|
mDecodedImageAux = NULL;
|
||||||
|
|
@ -118,10 +146,10 @@ LLImageDecodeThread::ImageRequest::~ImageRequest()
|
||||||
|
|
||||||
|
|
||||||
// Returns true when done, whether or not decode was successful.
|
// Returns true when done, whether or not decode was successful.
|
||||||
bool LLImageDecodeThread::ImageRequest::processRequest()
|
bool ImageRequest::processRequest()
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
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;
|
bool done = true;
|
||||||
if (!mDecodedRaw && mFormattedImage.notNull())
|
if (!mDecodedRaw && mFormattedImage.notNull())
|
||||||
{
|
{
|
||||||
|
|
@ -145,7 +173,7 @@ bool LLImageDecodeThread::ImageRequest::processRequest()
|
||||||
mFormattedImage->getHeight(),
|
mFormattedImage->getHeight(),
|
||||||
mFormattedImage->getComponents());
|
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
|
// some decoders are removing data when task is complete and there were errors
|
||||||
mDecodedRaw = done && mDecodedImageRaw->getData();
|
mDecodedRaw = done && mDecodedImageRaw->getData();
|
||||||
}
|
}
|
||||||
|
|
@ -158,14 +186,14 @@ bool LLImageDecodeThread::ImageRequest::processRequest()
|
||||||
mFormattedImage->getHeight(),
|
mFormattedImage->getHeight(),
|
||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4); // 1ms
|
done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4);
|
||||||
mDecodedAux = done && mDecodedImageAux->getData();
|
mDecodedAux = done && mDecodedImageAux->getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
|
void ImageRequest::finishRequest(bool completed)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||||
if (mResponder.notNull())
|
if (mResponder.notNull())
|
||||||
|
|
@ -175,10 +203,3 @@ void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
|
||||||
}
|
}
|
||||||
// Will automatically be deleted
|
// 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 "llimage.h"
|
||||||
#include "llpointer.h"
|
#include "llpointer.h"
|
||||||
#include "llworkerthread.h"
|
#include "threadpool_fwd.h"
|
||||||
|
|
||||||
class LLImageDecodeThread : public LLQueuedThread
|
class LLImageDecodeThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class Responder : public LLThreadSafeRefCount
|
class Responder : public LLThreadSafeRefCount
|
||||||
|
|
@ -42,63 +42,24 @@ public:
|
||||||
virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) = 0;
|
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:
|
public:
|
||||||
LLImageDecodeThread(bool threaded = true);
|
LLImageDecodeThread(bool threaded = true);
|
||||||
virtual ~LLImageDecodeThread();
|
virtual ~LLImageDecodeThread();
|
||||||
|
|
||||||
handle_t decodeImage(LLImageFormatted* image,
|
// meant to resemble LLQueuedThread::handle_t
|
||||||
U32 priority, S32 discard, BOOL needs_aux,
|
typedef U32 handle_t;
|
||||||
Responder* responder);
|
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);
|
size_t update(F32 max_time_ms);
|
||||||
|
void shutdown();
|
||||||
// Used by unit tests to check the consistency of the thread instance
|
|
||||||
S32 tut_size();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct creation_info
|
// As of SL-17483, LLImageDecodeThread is no longer itself an
|
||||||
{
|
// LLQueuedThread - instead this is the API by which we submit work to the
|
||||||
handle_t handle;
|
// "ImageDecode" ThreadPool.
|
||||||
LLPointer<LLImageFormatted> image;
|
std::unique_ptr<LL::ThreadPool> mThreadPool;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#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
|
// Tut templating thingamagic: test group, object and test instance
|
||||||
typedef test_group<imagedecodethread_test> imagedecodethread_t;
|
typedef test_group<imagedecodethread_test> imagedecodethread_t;
|
||||||
typedef imagedecodethread_t::object imagedecodethread_object_t;
|
typedef imagedecodethread_t::object imagedecodethread_object_t;
|
||||||
tut::imagedecodethread_t tut_imagedecodethread("LLImageDecodeThread");
|
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
|
// Test functions
|
||||||
// Notes:
|
// Notes:
|
||||||
|
|
@ -172,64 +141,18 @@ namespace tut
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
// Test the LLImageDecodeThread interface
|
// 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<>
|
template<> template<>
|
||||||
void imagedecodethread_object_t::test<1>()
|
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
|
// Test a *threaded* instance of the class
|
||||||
mThread = new LLImageDecodeThread(true);
|
mThread = new LLImageDecodeThread(true);
|
||||||
ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL);
|
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
|
// Insert something in the queue
|
||||||
bool done = false;
|
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
|
// Verifies we get back a valid handle
|
||||||
ensure("LLImageDecodeThread: threaded decodeImage(), returned handle is null", decodeHandle != 0);
|
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...)
|
// 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 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
|
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
|
// Verifies that the responder has now been called
|
||||||
ensure("LLImageDecodeThread: threaded work unit not processed", done == true);
|
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)
|
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
|
// No specific implementation for this method in the OpenJpeg case
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ LLFolderDictionary::LLFolderDictionary()
|
||||||
addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new FolderEntry("version", FALSE, FALSE, FALSE));
|
addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new FolderEntry("version", FALSE, FALSE, FALSE));
|
||||||
|
|
||||||
addEntry(LLFolderType::FT_SETTINGS, new FolderEntry("settings", TRUE, FALSE, TRUE));
|
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));
|
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE, FALSE, FALSE));
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -93,9 +93,13 @@ public:
|
||||||
|
|
||||||
FT_SETTINGS = 56,
|
FT_SETTINGS = 56,
|
||||||
|
|
||||||
|
FT_MATERIAL = 57,
|
||||||
|
|
||||||
FT_COUNT,
|
FT_COUNT,
|
||||||
|
|
||||||
FT_NONE = -1
|
FT_NONE = -1
|
||||||
|
|
||||||
|
// When adding, see note at bottom of LLAssetType::Etype
|
||||||
};
|
};
|
||||||
|
|
||||||
static EType lookup(const std::string& type_name);
|
static EType lookup(const std::string& type_name);
|
||||||
|
|
|
||||||
|
|
@ -904,152 +904,173 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
|
||||||
mInventoryType = LLInventoryType::IT_NONE;
|
mInventoryType = LLInventoryType::IT_NONE;
|
||||||
mAssetUUID.setNull();
|
mAssetUUID.setNull();
|
||||||
}
|
}
|
||||||
std::string w;
|
|
||||||
|
|
||||||
w = INV_ITEM_ID_LABEL;
|
// TODO - figure out if this should be moved into the noclobber fields above
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
mUUID = sd[w];
|
|
||||||
}
|
|
||||||
w = INV_PARENT_ID_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
mParentUUID = sd[w];
|
|
||||||
}
|
|
||||||
mThumbnailUUID.setNull();
|
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];
|
if (i->first == INV_ITEM_ID_LABEL)
|
||||||
w = INV_ASSET_ID_LABEL;
|
|
||||||
if (thumbnail_map.has(w))
|
|
||||||
{
|
{
|
||||||
mThumbnailUUID = thumbnail_map[w];
|
mUUID = i->second;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
/* Example:
|
|
||||||
<key> asset_id </key>
|
if (i->first == INV_PARENT_ID_LABEL)
|
||||||
<uuid> acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 </uuid>
|
|
||||||
<key> perms </key>
|
|
||||||
<integer> 8 </integer>
|
|
||||||
<key>service</key>
|
|
||||||
<integer> 3 </integer>
|
|
||||||
<key>version</key>
|
|
||||||
<integer> 1 </key>
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
w = INV_THUMBNAIL_ID_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
{
|
||||||
mThumbnailUUID = sd[w].asUUID();
|
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];
|
||||||
|
}
|
||||||
|
/* Example:
|
||||||
|
<key> asset_id </key>
|
||||||
|
<uuid> acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 </uuid>
|
||||||
|
<key> perms </key>
|
||||||
|
<integer> 8 </integer>
|
||||||
|
<key>service</key>
|
||||||
|
<integer> 3 </integer>
|
||||||
|
<key>version</key>
|
||||||
|
<integer> 1 </key>
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_THUMBNAIL_ID_LABEL)
|
||||||
|
{
|
||||||
|
mThumbnailUUID = i->second.asUUID();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_PERMISSIONS_LABEL)
|
||||||
|
{
|
||||||
|
mPermissions = ll_permissions_from_sd(i->second);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// objects. It's possible this op would fail, but it
|
||||||
|
// should pick up the vast majority of the tasks.
|
||||||
|
BOOL has_perm_mask = FALSE;
|
||||||
|
U32 perm_mask = 0;
|
||||||
|
if (!mSaleInfo.fromLLSD(i->second, has_perm_mask, perm_mask))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (has_perm_mask)
|
||||||
|
{
|
||||||
|
if (perm_mask == PERM_NONE)
|
||||||
|
{
|
||||||
|
perm_mask = mPermissions.getMaskOwner();
|
||||||
|
}
|
||||||
|
// fair use fix.
|
||||||
|
if (!(perm_mask & PERM_COPY))
|
||||||
|
{
|
||||||
|
perm_mask |= PERM_TRANSFER;
|
||||||
|
}
|
||||||
|
mPermissions.setMaskNext(perm_mask);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_SHADOW_ID_LABEL)
|
||||||
|
{
|
||||||
|
mAssetUUID = i->second;
|
||||||
|
LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
|
||||||
|
cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_ASSET_ID_LABEL)
|
||||||
|
{
|
||||||
|
mAssetUUID = i->second;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_LINKED_ID_LABEL)
|
||||||
|
{
|
||||||
|
mAssetUUID = i->second;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_ASSET_TYPE_LABEL)
|
||||||
|
{
|
||||||
|
LLSD const &label = i->second;
|
||||||
|
if (label.isString())
|
||||||
|
{
|
||||||
|
mType = LLAssetType::lookup(label.asString().c_str());
|
||||||
|
}
|
||||||
|
else if (label.isInteger())
|
||||||
|
{
|
||||||
|
S8 type = (U8) label.asInteger();
|
||||||
|
mType = static_cast<LLAssetType::EType>(type);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_INVENTORY_TYPE_LABEL)
|
||||||
|
{
|
||||||
|
LLSD const &label = i->second;
|
||||||
|
if (label.isString())
|
||||||
|
{
|
||||||
|
mInventoryType = LLInventoryType::lookup(label.asString().c_str());
|
||||||
|
}
|
||||||
|
else if (label.isInteger())
|
||||||
|
{
|
||||||
|
S8 type = (U8) label.asInteger();
|
||||||
|
mInventoryType = static_cast<LLInventoryType::EType>(type);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_FLAGS_LABEL)
|
||||||
|
{
|
||||||
|
LLSD const &label = i->second;
|
||||||
|
if (label.isBinary())
|
||||||
|
{
|
||||||
|
mFlags = ll_U32_from_sd(label);
|
||||||
|
}
|
||||||
|
else if (label.isInteger())
|
||||||
|
{
|
||||||
|
mFlags = label.asInteger();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_NAME_LABEL)
|
||||||
|
{
|
||||||
|
mName = i->second.asString();
|
||||||
|
LLStringUtil::replaceNonstandardASCII(mName, ' ');
|
||||||
|
LLStringUtil::replaceChar(mName, '|', ' ');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_DESC_LABEL)
|
||||||
|
{
|
||||||
|
mDescription = i->second.asString();
|
||||||
|
LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->first == INV_CREATION_DATE_LABEL)
|
||||||
|
{
|
||||||
|
mCreationDate = i->second.asInteger();
|
||||||
|
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))
|
|
||||||
{
|
|
||||||
// Sale info used to contain next owner perm. It is now in
|
|
||||||
// the permissions. Thus, we read that out, and fix legacy
|
|
||||||
// objects. It's possible this op would fail, but it
|
|
||||||
// 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))
|
|
||||||
{
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (has_perm_mask)
|
|
||||||
{
|
|
||||||
if(perm_mask == PERM_NONE)
|
|
||||||
{
|
|
||||||
perm_mask = mPermissions.getMaskOwner();
|
|
||||||
}
|
|
||||||
// fair use fix.
|
|
||||||
if(!(perm_mask & PERM_COPY))
|
|
||||||
{
|
|
||||||
perm_mask |= PERM_TRANSFER;
|
|
||||||
}
|
|
||||||
mPermissions.setMaskNext(perm_mask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w = INV_SHADOW_ID_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
mAssetUUID = sd[w];
|
|
||||||
LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
|
|
||||||
cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
|
|
||||||
}
|
|
||||||
w = INV_ASSET_ID_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
mAssetUUID = sd[w];
|
|
||||||
}
|
|
||||||
w = INV_LINKED_ID_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
mAssetUUID = sd[w];
|
|
||||||
}
|
|
||||||
w = INV_ASSET_TYPE_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
if (sd[w].isString())
|
|
||||||
{
|
|
||||||
mType = LLAssetType::lookup(sd[w].asString().c_str());
|
|
||||||
}
|
|
||||||
else if (sd[w].isInteger())
|
|
||||||
{
|
|
||||||
S8 type = (U8)sd[w].asInteger();
|
|
||||||
mType = static_cast<LLAssetType::EType>(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w = INV_INVENTORY_TYPE_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
if (sd[w].isString())
|
|
||||||
{
|
|
||||||
mInventoryType = LLInventoryType::lookup(sd[w].asString().c_str());
|
|
||||||
}
|
|
||||||
else if (sd[w].isInteger())
|
|
||||||
{
|
|
||||||
S8 type = (U8)sd[w].asInteger();
|
|
||||||
mInventoryType = static_cast<LLInventoryType::EType>(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w = INV_FLAGS_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
if (sd[w].isBinary())
|
|
||||||
{
|
|
||||||
mFlags = ll_U32_from_sd(sd[w]);
|
|
||||||
}
|
|
||||||
else if(sd[w].isInteger())
|
|
||||||
{
|
|
||||||
mFlags = sd[w].asInteger();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w = INV_NAME_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
mName = sd[w].asString();
|
|
||||||
LLStringUtil::replaceNonstandardASCII(mName, ' ');
|
|
||||||
LLStringUtil::replaceChar(mName, '|', ' ');
|
|
||||||
}
|
|
||||||
w = INV_DESC_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
mDescription = sd[w].asString();
|
|
||||||
LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
|
|
||||||
}
|
|
||||||
w = INV_CREATION_DATE_LABEL;
|
|
||||||
if (sd.has(w))
|
|
||||||
{
|
|
||||||
mCreationDate = sd[w].asInteger();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to convert 1.0 simstate files to a useful inventory type
|
// Need to convert 1.0 simstate files to a useful inventory type
|
||||||
// and potentially deal with bad inventory tyes eg, a landmark
|
// and potentially deal with bad inventory tyes eg, a landmark
|
||||||
|
|
@ -1064,9 +1085,6 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
|
||||||
mPermissions.initMasks(mInventoryType);
|
mPermissions.initMasks(mInventoryType);
|
||||||
|
|
||||||
return true;
|
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_WIDGET, new InventoryEntry("widget", "widget", 1, LLAssetType::AT_WIDGET));
|
||||||
addEntry(LLInventoryType::IT_PERSON, new InventoryEntry("person", "person", 1, LLAssetType::AT_PERSON));
|
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_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, // 53 AT_RESERVED_4
|
||||||
LLInventoryType::IT_NONE, // 54 AT_RESERVED_5
|
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
|
// static
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,8 @@ public:
|
||||||
IT_WIDGET = 23,
|
IT_WIDGET = 23,
|
||||||
IT_PERSON = 24,
|
IT_PERSON = 24,
|
||||||
IT_SETTINGS = 25,
|
IT_SETTINGS = 25,
|
||||||
IT_COUNT = 26,
|
IT_MATERIAL = 26,
|
||||||
|
IT_COUNT = 27,
|
||||||
|
|
||||||
IT_UNKNOWN = 255,
|
IT_UNKNOWN = 255,
|
||||||
IT_NONE = -1
|
IT_NONE = -1
|
||||||
|
|
@ -118,6 +119,8 @@ public:
|
||||||
ICONNAME_SETTINGS_WATER,
|
ICONNAME_SETTINGS_WATER,
|
||||||
ICONNAME_SETTINGS_DAY,
|
ICONNAME_SETTINGS_DAY,
|
||||||
|
|
||||||
|
ICONNAME_MATERIAL,
|
||||||
|
|
||||||
ICONNAME_INVALID,
|
ICONNAME_INVALID,
|
||||||
ICONNAME_UNKNOWN,
|
ICONNAME_UNKNOWN,
|
||||||
ICONNAME_COUNT,
|
ICONNAME_COUNT,
|
||||||
|
|
|
||||||
|
|
@ -694,6 +694,7 @@ void LLSettingsBlender::update(const LLSettingsBase::BlendFactor& blendf)
|
||||||
F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_in)
|
F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_in)
|
||||||
{
|
{
|
||||||
LLSettingsBase::TrackPosition blendf = blendf_in;
|
LLSettingsBase::TrackPosition blendf = blendf_in;
|
||||||
|
llassert(!isnan(blendf));
|
||||||
if (blendf >= 1.0)
|
if (blendf >= 1.0)
|
||||||
{
|
{
|
||||||
triggerComplete();
|
triggerComplete();
|
||||||
|
|
|
||||||
|
|
@ -467,6 +467,7 @@ protected:
|
||||||
|
|
||||||
class LLSettingsBlenderTimeDelta : public LLSettingsBlender
|
class LLSettingsBlenderTimeDelta : public LLSettingsBlender
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
LOG_CLASS(LLSettingsBlenderTimeDelta);
|
LOG_CLASS(LLSettingsBlenderTimeDelta);
|
||||||
public:
|
public:
|
||||||
static const LLSettingsBase::BlendFactor MIN_BLEND_DELTA;
|
static const LLSettingsBase::BlendFactor MIN_BLEND_DELTA;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include "v3colorutil.h"
|
#include "v3colorutil.h"
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
namespace
|
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_DROPLET_RADIUS("droplet_radius");
|
||||||
const std::string LLSettingsSky::SETTING_SKY_ICE_LEVEL("ice_level");
|
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_SUN_ID("32bfbcea-24b1-fb9d-1ef9-48a28a63730f"); // dataserver
|
||||||
static const LLUUID DEFAULT_MOON_ID("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver
|
static const LLUUID DEFAULT_MOON_ID("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver
|
||||||
|
|
@ -402,6 +407,7 @@ LLSettingsSky::LLSettingsSky(const LLSD &data) :
|
||||||
mNextRainbowTextureId(),
|
mNextRainbowTextureId(),
|
||||||
mNextHaloTextureId()
|
mNextHaloTextureId()
|
||||||
{
|
{
|
||||||
|
mCanAutoAdjust = !data.has(SETTING_REFLECTION_PROBE_AMBIANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLSettingsSky::LLSettingsSky():
|
LLSettingsSky::LLSettingsSky():
|
||||||
|
|
@ -424,6 +430,8 @@ void LLSettingsSky::replaceSettings(LLSD settings)
|
||||||
mNextBloomTextureId.setNull();
|
mNextBloomTextureId.setNull();
|
||||||
mNextRainbowTextureId.setNull();
|
mNextRainbowTextureId.setNull();
|
||||||
mNextHaloTextureId.setNull();
|
mNextHaloTextureId.setNull();
|
||||||
|
|
||||||
|
mCanAutoAdjust = !settings.has(SETTING_REFLECTION_PROBE_AMBIANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
|
void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
|
||||||
|
|
@ -436,6 +444,7 @@ void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
|
||||||
mNextBloomTextureId = pother->mNextBloomTextureId;
|
mNextBloomTextureId = pother->mNextBloomTextureId;
|
||||||
mNextRainbowTextureId = pother->mNextRainbowTextureId;
|
mNextRainbowTextureId = pother->mNextRainbowTextureId;
|
||||||
mNextHaloTextureId = pother->mNextHaloTextureId;
|
mNextHaloTextureId = pother->mNextHaloTextureId;
|
||||||
|
mCanAutoAdjust = pother->mCanAutoAdjust;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf)
|
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,
|
validation.push_back(Validator(SETTING_SKY_ICE_LEVEL, false, LLSD::TypeReal,
|
||||||
boost::bind(&Validator::verifyFloatRange, _1, _2, llsd::array(0.0f, 1.0f))));
|
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_RAYLEIGH_CONFIG, true, LLSD::TypeArray, &validateRayleighLayers));
|
||||||
validation.push_back(Validator(SETTING_ABSORPTION_CONFIG, true, LLSD::TypeArray, &validateAbsorptionLayers));
|
validation.push_back(Validator(SETTING_ABSORPTION_CONFIG, true, LLSD::TypeArray, &validateAbsorptionLayers));
|
||||||
validation.push_back(Validator(SETTING_MIE_CONFIG, true, LLSD::TypeArray, &validateMieLayers));
|
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_DROPLET_RADIUS] = 800.0f;
|
||||||
dfltsetting[SETTING_SKY_ICE_LEVEL] = 0.0f;
|
dfltsetting[SETTING_SKY_ICE_LEVEL] = 0.0f;
|
||||||
|
|
||||||
|
dfltsetting[SETTING_REFLECTION_PROBE_AMBIANCE] = 0.0f;
|
||||||
|
|
||||||
dfltsetting[SETTING_RAYLEIGH_CONFIG] = rayleighConfigDefault();
|
dfltsetting[SETTING_RAYLEIGH_CONFIG] = rayleighConfigDefault();
|
||||||
dfltsetting[SETTING_MIE_CONFIG] = mieConfigDefault();
|
dfltsetting[SETTING_MIE_CONFIG] = mieConfigDefault();
|
||||||
dfltsetting[SETTING_ABSORPTION_CONFIG] = absorptionConfigDefault();
|
dfltsetting[SETTING_ABSORPTION_CONFIG] = absorptionConfigDefault();
|
||||||
|
|
@ -1130,6 +1144,12 @@ void LLSettingsSky::setSkyIceLevel(F32 ice_level)
|
||||||
setValue(SETTING_SKY_ICE_LEVEL, 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)
|
void LLSettingsSky::setAmbientColor(const LLColor3 &val)
|
||||||
{
|
{
|
||||||
mSettings[SETTING_LEGACY_HAZE][SETTING_AMBIENT] = val.getValue();
|
mSettings[SETTING_LEGACY_HAZE][SETTING_AMBIENT] = val.getValue();
|
||||||
|
|
@ -1418,6 +1438,34 @@ F32 LLSettingsSky::getSkyIceLevel() const
|
||||||
return mSettings[SETTING_SKY_ICE_LEVEL].asReal();
|
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
|
F32 LLSettingsSky::getSkyBottomRadius() const
|
||||||
{
|
{
|
||||||
return mSettings[SETTING_SKY_BOTTOM_RADIUS].asReal();
|
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_DROPLET_RADIUS;
|
||||||
static const std::string SETTING_SKY_ICE_LEVEL;
|
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 std::string SETTING_LEGACY_HAZE;
|
||||||
|
|
||||||
static const LLUUID DEFAULT_ASSET_ID;
|
static const LLUUID DEFAULT_ASSET_ID;
|
||||||
|
|
||||||
|
static F32 sAutoAdjustProbeAmbiance;
|
||||||
|
|
||||||
typedef PTR_NAMESPACE::shared_ptr<LLSettingsSky> ptr_t;
|
typedef PTR_NAMESPACE::shared_ptr<LLSettingsSky> ptr_t;
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
|
@ -131,6 +135,14 @@ public:
|
||||||
F32 getSkyDropletRadius() const;
|
F32 getSkyDropletRadius() const;
|
||||||
F32 getSkyIceLevel() 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
|
// Return first (only) profile layer represented in LLSD
|
||||||
LLSD getRayleighConfig() const;
|
LLSD getRayleighConfig() const;
|
||||||
LLSD getMieConfig() const;
|
LLSD getMieConfig() const;
|
||||||
|
|
@ -159,6 +171,8 @@ public:
|
||||||
void setSkyDropletRadius(F32 radius);
|
void setSkyDropletRadius(F32 radius);
|
||||||
void setSkyIceLevel(F32 ice_level);
|
void setSkyIceLevel(F32 ice_level);
|
||||||
|
|
||||||
|
void setReflectionProbeAmbiance(F32 ambiance);
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
LLColor3 getAmbientColor() const;
|
LLColor3 getAmbientColor() const;
|
||||||
void setAmbientColor(const LLColor3 &val);
|
void setAmbientColor(const LLColor3 &val);
|
||||||
|
|
@ -324,6 +338,10 @@ public:
|
||||||
F32 aniso_factor = 0.0f);
|
F32 aniso_factor = 0.0f);
|
||||||
|
|
||||||
virtual void updateSettings() SETTINGS_OVERRIDE;
|
virtual void updateSettings() SETTINGS_OVERRIDE;
|
||||||
|
|
||||||
|
// if true, this sky is a candidate for auto-adjustment
|
||||||
|
bool canAutoAdjust() const { return mCanAutoAdjust; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const std::string SETTING_LEGACY_EAST_ANGLE;
|
static const std::string SETTING_LEGACY_EAST_ANGLE;
|
||||||
static const std::string SETTING_LEGACY_ENABLE_CLOUD_SCROLL;
|
static const std::string SETTING_LEGACY_ENABLE_CLOUD_SCROLL;
|
||||||
|
|
@ -367,6 +385,9 @@ private:
|
||||||
mutable LLColor4 mTotalAmbient;
|
mutable LLColor4 mTotalAmbient;
|
||||||
mutable LLColor4 mHazeColor;
|
mutable LLColor4 mHazeColor;
|
||||||
|
|
||||||
|
// if true, this sky is a candidate for auto adjustment
|
||||||
|
bool mCanAutoAdjust = true;
|
||||||
|
|
||||||
typedef std::map<std::string, S32> mapNameToUniformId_t;
|
typedef std::map<std::string, S32> mapNameToUniformId_t;
|
||||||
|
|
||||||
static mapNameToUniformId_t sNameToUniformMapping;
|
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(0.0f, 0.0f, 0.0f, 1.0f),
|
||||||
llsd::array(1.0f, 1.0f, 1.0f, 1.0f))));
|
llsd::array(1.0f, 1.0f, 1.0f, 1.0f))));
|
||||||
validation.push_back(Validator(SETTING_FOG_DENSITY, true, LLSD::TypeReal,
|
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,
|
validation.push_back(Validator(SETTING_FOG_MOD, true, LLSD::TypeReal,
|
||||||
boost::bind(&Validator::verifyFloatRange, _1, _2, llsd::array(0.0f, 20.0f))));
|
boost::bind(&Validator::verifyFloatRange, _1, _2, llsd::array(0.0f, 20.0f))));
|
||||||
validation.push_back(Validator(SETTING_FRESNEL_OFFSET, true, LLSD::TypeReal,
|
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()
|
void LLImageJ2CKDU::cleanupCodeStream()
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||||
mInputp.reset();
|
mInputp.reset();
|
||||||
mDecodeState.reset();
|
mDecodeState.reset();
|
||||||
mCodeStreamp.reset();
|
mCodeStreamp.reset();
|
||||||
|
|
@ -426,6 +427,7 @@ bool LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int bloc
|
||||||
// decodeImpl() usage matters for production.
|
// 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)
|
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();
|
base.resetLastError();
|
||||||
|
|
||||||
// *FIX: kdu calls our callback function if there's an error, and then bombs.
|
// *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.
|
// 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)
|
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;
|
ECodeStreamMode mode = MODE_FAST;
|
||||||
|
|
||||||
LLTimer decode_timer;
|
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
|
multiple tiles. For this reason, `row_gap' is needed to identify the
|
||||||
separation between consecutive rows in the real buffer. */
|
separation between consecutive rows in the real buffer. */
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||||
S32 c;
|
S32 c;
|
||||||
// Now walk through the lines of the buffer, recovering them from the
|
// Now walk through the lines of the buffer, recovering them from the
|
||||||
// relevant tile-component processing engines.
|
// relevant tile-component processing engines.
|
||||||
|
|
@ -1339,18 +1343,27 @@ separation between consecutive rows in the real buffer. */
|
||||||
LLTimer decode_timer;
|
LLTimer decode_timer;
|
||||||
while (mDims.size.y--)
|
while (mDims.size.y--)
|
||||||
{
|
{
|
||||||
for (c = 0; c < mNumComponents; c++)
|
{
|
||||||
{
|
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("kduptc - pull");
|
||||||
mEngines[c].pull(mLines[c]);
|
for (c = 0; c < mNumComponents; c++)
|
||||||
}
|
{
|
||||||
|
mEngines[c].pull(mLines[c]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((mNumComponents >= 3) && mUseYCC)
|
if ((mNumComponents >= 3) && mUseYCC)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("kduptc - convert");
|
||||||
kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
|
kdu_convert_ycc_to_rgb(mLines[0],mLines[1],mLines[2]);
|
||||||
}
|
}
|
||||||
for (c = 0; c < mNumComponents; c++)
|
|
||||||
{
|
{
|
||||||
transfer_bytes(mBuf+c,mLines[c],mNumComponents,mBitDepths[c]);
|
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("kduptc - transfer");
|
||||||
}
|
for (c = 0; c < mNumComponents; c++)
|
||||||
|
{
|
||||||
|
transfer_bytes(mBuf + c, mLines[c], mNumComponents, mBitDepths[c]);
|
||||||
|
}
|
||||||
|
}
|
||||||
mBuf += mRowGap;
|
mBuf += mRowGap;
|
||||||
if (mDims.size.y % 10)
|
if (mDims.size.y % 10)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -311,104 +311,6 @@ int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 rad
|
||||||
return 0;
|
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.
|
// Return 1 if sphere is in frustum, 2 if fully in frustum, otherwise 0.
|
||||||
// NOTE: 'center' is in absolute frame.
|
// NOTE: 'center' is in absolute frame.
|
||||||
int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) const
|
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 ----------------
|
// ---------------- friends and operators ----------------
|
||||||
|
|
||||||
|
|
@ -536,18 +379,6 @@ std::ostream& operator<<(std::ostream &s, const LLCamera &C)
|
||||||
s << " Aspect = " << C.getAspect() << "\n";
|
s << " Aspect = " << C.getAspect() << "\n";
|
||||||
s << " NearPlane = " << C.mNearPlane << "\n";
|
s << " NearPlane = " << C.mNearPlane << "\n";
|
||||||
s << " FarPlane = " << C.mFarPlane << "\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 << "}";
|
s << "}";
|
||||||
return 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)
|
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
|
//calculate center and radius squared of frustum in world absolute coordinates
|
||||||
static LLVector3 const X_AXIS(1.f, 0.f, 0.f);
|
static LLVector3 const X_AXIS(1.f, 0.f, 0.f);
|
||||||
mFrustCenter = X_AXIS*mFarPlane*0.5f;
|
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);
|
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
|
// 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):
|
// (-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 DEFAULT_FAR_PLANE = 64.f; // far reaches across two horizontal, not diagonal, regions
|
||||||
|
|
||||||
const F32 MAX_ASPECT_RATIO = 50.0f;
|
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_PLANE = 100000.0f; //1000000.0f; // Max allowed. Not good Z precision though.
|
||||||
const F32 MAX_FAR_CLIP = 512.0f;
|
const F32 MAX_FAR_CLIP = 512.0f;
|
||||||
|
|
||||||
|
|
@ -131,14 +131,10 @@ private:
|
||||||
S32 mViewHeightInPixels; // for ViewHeightInPixels() only
|
S32 mViewHeightInPixels; // for ViewHeightInPixels() only
|
||||||
F32 mNearPlane;
|
F32 mNearPlane;
|
||||||
F32 mFarPlane;
|
F32 mFarPlane;
|
||||||
LL_ALIGN_16(LLPlane mLocalPlanes[PLANE_NUM]);
|
|
||||||
F32 mFixedDistance; // Always return this distance, unless < 0
|
F32 mFixedDistance; // Always return this distance, unless < 0
|
||||||
LLVector3 mFrustCenter; // center of frustum and radius squared for ultra-quick exclusion test
|
LLVector3 mFrustCenter; // center of frustum and radius squared for ultra-quick exclusion test
|
||||||
F32 mFrustRadiusSquared;
|
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
|
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)
|
LLVector3 mWorldPlanePos; // Position of World Planes (may be offset from camera)
|
||||||
|
|
@ -184,7 +180,6 @@ public:
|
||||||
return atan2f(mXAxis[VZ], xylen);
|
return atan2f(mXAxis[VZ], xylen);
|
||||||
}
|
}
|
||||||
|
|
||||||
const LLPlane& getWorldPlane(S32 index) const { return mWorldPlanes[index]; }
|
|
||||||
const LLVector3& getWorldPlanePos() const { return mWorldPlanePos; }
|
const LLVector3& getWorldPlanePos() const { return mWorldPlanePos; }
|
||||||
|
|
||||||
// Copy mView, mAspect, mNearPlane, and mFarPlane to buffer.
|
// Copy mView, mAspect, mNearPlane, and mFarPlane to buffer.
|
||||||
|
|
@ -200,7 +195,6 @@ public:
|
||||||
|
|
||||||
// Returns 1 if partly in, 2 if fully in.
|
// Returns 1 if partly in, 2 if fully in.
|
||||||
// NOTE: 'center' is in absolute frame.
|
// 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 sphereInFrustum(const LLVector3 ¢er, const F32 radius) const;
|
||||||
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
|
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
|
||||||
S32 sphereInFrustumFull(const LLVector3 ¢er, const F32 radius) const { return sphereInFrustum(center, radius); }
|
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;
|
F32 heightInPixels(const LLVector3 ¢er, F32 radius ) const;
|
||||||
|
|
||||||
// return the distance from pos to camera if visible (-distance if not visible)
|
// 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; }
|
void setFixedDistance(F32 distance) { mFixedDistance = distance; }
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream &s, const LLCamera &C);
|
friend std::ostream& operator<<(std::ostream &s, const LLCamera &C);
|
||||||
|
|
@ -227,7 +219,6 @@ protected:
|
||||||
void calculateFrustumPlanes();
|
void calculateFrustumPlanes();
|
||||||
void calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom);
|
void calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom);
|
||||||
void calculateFrustumPlanesFromWindow(F32 x1, F32 y1, F32 x2, F32 y2);
|
void calculateFrustumPlanesFromWindow(F32 x1, F32 y1, F32 x2, F32 y2);
|
||||||
void calculateWorldFrustumPlanes();
|
|
||||||
} LL_ALIGN_POSTFIX(16);
|
} LL_ALIGN_POSTFIX(16);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "llerror.h"
|
#include "llerror.h"
|
||||||
|
|
||||||
|
|
@ -52,6 +53,11 @@
|
||||||
#include "llmeshoptimizer.h"
|
#include "llmeshoptimizer.h"
|
||||||
#include "lltimer.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_BINORMALS 0
|
||||||
#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
|
#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
|
#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;
|
mDetail = detail;
|
||||||
mSculptLevel = -2;
|
mSculptLevel = -2;
|
||||||
mSurfaceArea = 1.f; //only calculated for sculpts, defaults to 1 for all other prims
|
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);
|
mLODScaleBias.setVec(1,1,1);
|
||||||
mHullPoints = NULL;
|
mHullPoints = NULL;
|
||||||
mHullIndices = NULL;
|
mHullIndices = NULL;
|
||||||
|
|
@ -2093,7 +2100,9 @@ void LLVolume::regen()
|
||||||
|
|
||||||
void LLVolume::genTangents(S32 face)
|
void LLVolume::genTangents(S32 face)
|
||||||
{
|
{
|
||||||
mVolumeFaces[face].createTangents();
|
// 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVolume::~LLVolume()
|
LLVolume::~LLVolume()
|
||||||
|
|
@ -2433,11 +2442,10 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
|
||||||
|
|
||||||
LLSD::Binary pos = mdl[i]["Position"];
|
LLSD::Binary pos = mdl[i]["Position"];
|
||||||
LLSD::Binary norm = mdl[i]["Normal"];
|
LLSD::Binary norm = mdl[i]["Normal"];
|
||||||
|
LLSD::Binary tangent = mdl[i]["Tangent"];
|
||||||
LLSD::Binary tc = mdl[i]["TexCoord0"];
|
LLSD::Binary tc = mdl[i]["TexCoord0"];
|
||||||
LLSD::Binary idx = mdl[i]["TriangleList"];
|
LLSD::Binary idx = mdl[i]["TriangleList"];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//copy out indices
|
//copy out indices
|
||||||
S32 num_indices = idx.size() / 2;
|
S32 num_indices = idx.size() / 2;
|
||||||
const S32 indices_to_discard = num_indices % 3;
|
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"]);
|
min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
|
||||||
max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
|
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;
|
LLVector4a pos_range;
|
||||||
pos_range.setSub(max_pos, min_pos);
|
pos_range.setSub(max_pos, min_pos);
|
||||||
LLVector2 tc_range2 = max_tc - min_tc;
|
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())
|
if (!tc.empty())
|
||||||
{
|
{
|
||||||
|
|
@ -2745,7 +2791,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cacheOptimize())
|
if (!cacheOptimize(true))
|
||||||
{
|
{
|
||||||
// Out of memory?
|
// Out of memory?
|
||||||
LL_WARNS() << "Failed to optimize!" << LL_ENDL;
|
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;
|
return mIsMeshAssetLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVolume::setMeshAssetLoaded(BOOL loaded)
|
void LLVolume::setMeshAssetLoaded(bool loaded)
|
||||||
{
|
{
|
||||||
mIsMeshAssetLoaded = 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
|
void LLVolume::copyFacesTo(std::vector<LLVolumeFace> &faces) const
|
||||||
|
|
@ -2786,11 +2850,11 @@ void LLVolume::copyVolumeFaces(const LLVolume* volume)
|
||||||
mSculptLevel = 0;
|
mSculptLevel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LLVolume::cacheOptimize()
|
bool LLVolume::cacheOptimize(bool gen_tangents)
|
||||||
{
|
{
|
||||||
for (S32 i = 0; i < mVolumeFaces.size(); ++i)
|
for (S32 i = 0; i < mVolumeFaces.size(); ++i)
|
||||||
{
|
{
|
||||||
if (!mVolumeFaces[i].cacheOptimize())
|
if (!mVolumeFaces[i].cacheOptimize(gen_tangents))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -3306,12 +3370,12 @@ BOOL LLVolume::isFlat(S32 face)
|
||||||
|
|
||||||
bool LLVolumeParams::isSculpt() const
|
bool LLVolumeParams::isSculpt() const
|
||||||
{
|
{
|
||||||
return mSculptID.notNull();
|
return (mSculptType & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LLVolumeParams::isMeshSculpt() const
|
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
|
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)
|
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
|
{ //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
|
//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};
|
F32 detail[] = {1.f, 1.5f, 2.5f, 4.f};
|
||||||
for (S32 i = 0; i < 4; i++)
|
for (S32 i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -4073,7 +4138,7 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
|
||||||
{
|
{
|
||||||
if (tangent_out != NULL) // if the caller wants tangents, we may need to generate them
|
if (tangent_out != NULL) // if the caller wants tangents, we may need to generate them
|
||||||
{
|
{
|
||||||
genTangents(i);
|
genTangents(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUnique())
|
if (isUnique())
|
||||||
|
|
@ -4861,6 +4926,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
||||||
}
|
}
|
||||||
|
|
||||||
mOptimized = src.mOptimized;
|
mOptimized = src.mOptimized;
|
||||||
|
mNormalizedScale = src.mNormalizedScale;
|
||||||
|
|
||||||
//delete
|
//delete
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -5383,256 +5449,218 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// data structures for tangent generation
|
||||||
|
|
||||||
bool LLVolumeFace::cacheOptimize()
|
struct MikktData
|
||||||
{ //optimize for vertex cache according to Forsyth method:
|
{
|
||||||
// http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html
|
LLVolumeFace* face;
|
||||||
|
std::vector<LLVector3> p;
|
||||||
|
std::vector<LLVector3> n;
|
||||||
|
std::vector<LLVector2> tc;
|
||||||
|
std::vector<LLVector4> w;
|
||||||
|
std::vector<LLVector4> t;
|
||||||
|
|
||||||
llassert(!mOptimized);
|
MikktData(LLVolumeFace* f)
|
||||||
mOptimized = TRUE;
|
: 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)
|
if (face->mWeights)
|
||||||
{ //nothing to do
|
{
|
||||||
return true;
|
w.resize(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
//mapping of vertices to triangles and indices
|
|
||||||
std::vector<LLVCacheVertexData> vertex_data;
|
|
||||||
|
|
||||||
//mapping of triangles do vertices
|
LLVector3 inv_scale(1.f / face->mNormalizedScale.mV[0], 1.f / face->mNormalizedScale.mV[1], 1.f / face->mNormalizedScale.mV[2]);
|
||||||
std::vector<LLVCacheTriangleData> triangle_data;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
triangle_data.resize(mNumIndices / 3);
|
|
||||||
vertex_data.resize(mNumVertices);
|
|
||||||
|
|
||||||
for (U32 i = 0; i < mNumIndices; i++)
|
for (int i = 0; i < face->mNumIndices; ++i)
|
||||||
{ //populate vertex data and triangle data arrays
|
{
|
||||||
U16 idx = mIndices[i];
|
U32 idx = face->mIndices[i];
|
||||||
U32 tri_idx = i / 3;
|
|
||||||
|
|
||||||
if (idx >= mNumVertices)
|
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 >= face->mNumVertices)
|
||||||
{
|
{
|
||||||
// invalid index
|
// invalid index
|
||||||
// replace with a valid index to avoid crashes
|
// replace with a valid index to avoid crashes
|
||||||
idx = mNumVertices - 1;
|
idx = face->mNumVertices - 1;
|
||||||
mIndices[i] = idx;
|
face->mIndices[i] = idx;
|
||||||
|
|
||||||
// Needs better logging
|
// Needs better logging
|
||||||
LL_DEBUGS_ONCE("LLVOLUME") << "Invalid index, substituting" << LL_ENDL;
|
LL_DEBUGS_ONCE("LLVOLUME") << "Invalid index, substituting" << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
|
if (face->mWeights)
|
||||||
vertex_data[idx].mIdx = idx;
|
{
|
||||||
triangle_data[tri_idx].mVertex[i % 3] = &(vertex_data[idx]);
|
w[i].set(face->mWeights[idx].getF32ptr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::bad_alloc&)
|
};
|
||||||
{
|
|
||||||
// resize or push_back failed
|
|
||||||
LL_WARNS("LLVOLUME") << "Resize for " << mNumVertices << " vertices failed" << LL_ENDL;
|
bool LLVolumeFace::cacheOptimize(bool gen_tangents)
|
||||||
return false;
|
{ //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);
|
||||||
|
}
|
||||||
|
|
||||||
|
allocateTangents(mNumVertices);
|
||||||
|
|
||||||
|
for (int i = 0; i < mNumIndices; ++i)
|
||||||
|
{
|
||||||
|
U32 src_idx = i;
|
||||||
|
U32 dst_idx = remap[i];
|
||||||
|
mIndices[i] = dst_idx;
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
mTangents[dst_idx].loadua(data.t[src_idx].mV);
|
||||||
|
|
||||||
|
if (mWeights)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// blew past the max vertex size limit, use legacy tangent generation which never adds verts
|
||||||
|
createTangents();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*F32 pre_acmr = 1.f;
|
// cache optimize index buffer
|
||||||
//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++)
|
// meshopt needs scratch space, do some pointer shuffling to avoid an extra index buffer copy
|
||||||
{
|
U16* src_indices = mIndices;
|
||||||
vertex_data[i].mCacheTag = -1;
|
mIndices = nullptr;
|
||||||
}
|
resizeIndices(mNumIndices);
|
||||||
|
|
||||||
pre_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
|
meshopt_optimizeVertexCache<U16>(mIndices, src_indices, mNumIndices, mNumVertices);
|
||||||
}*/
|
|
||||||
|
|
||||||
for (U32 i = 0; i < mNumVertices; i++)
|
ll_aligned_free_16(src_indices);
|
||||||
{ //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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (U32 i = 0; i < mNumIndices; ++i)
|
|
||||||
{
|
|
||||||
mIndices[i] = new_indices[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*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;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (U32 i = 0; i < mNumIndices; ++i)
|
|
||||||
{
|
|
||||||
test_cache.addVertex(&vertex_data[mIndices[i]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
ll_aligned_free<64>(pos);
|
|
||||||
LL_WARNS("LLVOLUME") << "Allocation of weights[" << sizeof(LLVector4a) * num_verts << "] failed" << LL_ENDL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LLVector4a* binorm = NULL;
|
|
||||||
if (mTangents)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//allocate mapping of old indices to new indices
|
|
||||||
std::vector<S32> new_idx;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
//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;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -6442,35 +6470,31 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe
|
||||||
|
|
||||||
void LLVolumeFace::createTangents()
|
void LLVolumeFace::createTangents()
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
|
||||||
|
|
||||||
if (!mTangents)
|
if (!mTangents)
|
||||||
{
|
{
|
||||||
allocateTangents(mNumVertices);
|
allocateTangents(mNumVertices);
|
||||||
|
|
||||||
//generate tangents
|
//generate tangents
|
||||||
//LLVector4a* pos = mPositions;
|
LLVector4a* ptr = (LLVector4a*)mTangents;
|
||||||
//LLVector2* tc = (LLVector2*) mTexCoords;
|
|
||||||
LLVector4a* binorm = (LLVector4a*) mTangents;
|
|
||||||
|
|
||||||
LLVector4a* end = mTangents+mNumVertices;
|
LLVector4a* end = mTangents + mNumVertices;
|
||||||
while (binorm < end)
|
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 normals
|
||||||
|
for (U32 i = 0; i < mNumVertices; i++)
|
||||||
|
{
|
||||||
|
//bump map/planar projection code requires normals to be normalized
|
||||||
|
mNormals[i].normalize3fast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//normalize tangents
|
|
||||||
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)
|
void LLVolumeFace::resizeVertices(S32 num_verts)
|
||||||
|
|
|
||||||
|
|
@ -908,7 +908,7 @@ public:
|
||||||
void remap();
|
void remap();
|
||||||
|
|
||||||
void optimize(F32 angle_cutoff = 2.f);
|
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 createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f));
|
||||||
void destroyOctree();
|
void destroyOctree();
|
||||||
|
|
@ -960,10 +960,6 @@ public:
|
||||||
// indexes for mPositions/mNormals/mTexCoords
|
// indexes for mPositions/mNormals/mTexCoords
|
||||||
U16* mIndices;
|
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;
|
std::vector<S32> mEdge;
|
||||||
|
|
||||||
//list of skin weights for rigged volumes
|
//list of skin weights for rigged volumes
|
||||||
|
|
@ -985,6 +981,11 @@ public:
|
||||||
//whether or not face has been cache optimized
|
//whether or not face has been cache optimized
|
||||||
BOOL mOptimized;
|
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:
|
private:
|
||||||
LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* mOctree;
|
LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* mOctree;
|
||||||
LLVolumeTriangle* mOctreeTriangles;
|
LLVolumeTriangle* mOctreeTriangles;
|
||||||
|
|
@ -1033,7 +1034,7 @@ public:
|
||||||
void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); }
|
void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); }
|
||||||
|
|
||||||
void regen();
|
void regen();
|
||||||
void genTangents(S32 face);
|
void genTangents(S32 face);
|
||||||
|
|
||||||
BOOL isConvex() const;
|
BOOL isConvex() const;
|
||||||
BOOL isCap(S32 face);
|
BOOL isCap(S32 face);
|
||||||
|
|
@ -1087,7 +1088,10 @@ public:
|
||||||
void copyVolumeFaces(const LLVolume* volume);
|
void copyVolumeFaces(const LLVolume* volume);
|
||||||
void copyFacesTo(std::vector<LLVolumeFace> &faces) const;
|
void copyFacesTo(std::vector<LLVolumeFace> &faces) const;
|
||||||
void copyFacesFrom(const std::vector<LLVolumeFace> &faces);
|
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:
|
private:
|
||||||
void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type);
|
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);
|
bool unpackVolumeFacesInternal(const LLSD& mdl);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void setMeshAssetLoaded(BOOL loaded);
|
virtual void setMeshAssetLoaded(bool loaded);
|
||||||
virtual BOOL isMeshAssetLoaded();
|
virtual bool isMeshAssetLoaded();
|
||||||
|
virtual void setMeshAssetUnavaliable(bool unavaliable);
|
||||||
|
virtual bool isMeshAssetUnavaliable();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BOOL mUnique;
|
BOOL mUnique;
|
||||||
F32 mDetail;
|
F32 mDetail;
|
||||||
S32 mSculptLevel;
|
S32 mSculptLevel;
|
||||||
F32 mSurfaceArea; //unscaled surface area
|
F32 mSurfaceArea; //unscaled surface area
|
||||||
BOOL mIsMeshAssetLoaded;
|
bool mIsMeshAssetLoaded;
|
||||||
|
bool mIsMeshAssetUnavaliable;
|
||||||
|
|
||||||
const LLVolumeParams mParams;
|
const LLVolumeParams mParams;
|
||||||
LLPath *mPathp;
|
LLPath *mPathp;
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ BOOL LLVolumeMgr::cleanup()
|
||||||
// Note however that LLVolumeLODGroup that contains the volume
|
// Note however that LLVolumeLODGroup that contains the volume
|
||||||
// also holds a LLPointer so the volume will only go away after
|
// also holds a LLPointer so the volume will only go away after
|
||||||
// anything holding the volume and the LODGroup are destroyed
|
// 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;
|
LLVolumeLODGroup* volgroupp;
|
||||||
if (mDataMutex)
|
if (mDataMutex)
|
||||||
|
|
@ -109,7 +109,7 @@ LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32
|
||||||
{
|
{
|
||||||
mDataMutex->unlock();
|
mDataMutex->unlock();
|
||||||
}
|
}
|
||||||
return volgroupp->refLOD(detail);
|
return volgroupp->refLOD(lod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
|
|
@ -287,18 +287,18 @@ bool LLVolumeLODGroup::cleanupRefs()
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVolume* LLVolumeLODGroup::refLOD(const S32 detail)
|
LLVolume* LLVolumeLODGroup::refLOD(const S32 lod)
|
||||||
{
|
{
|
||||||
llassert(detail >=0 && detail < NUM_LODS);
|
llassert(lod >=0 && lod < NUM_LODS);
|
||||||
mAccessCount[detail]++;
|
mAccessCount[lod]++;
|
||||||
|
|
||||||
mRefs++;
|
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]++;
|
mLODRefs[lod]++;
|
||||||
return mVolumeLODs[detail];
|
return mVolumeLODs[lod];
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
|
BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ class LLVector4;
|
||||||
#include "llerror.h"
|
#include "llerror.h"
|
||||||
#include "llmath.h"
|
#include "llmath.h"
|
||||||
#include "llsd.h"
|
#include "llsd.h"
|
||||||
|
#include "v3math.h" // needed for linearColor3v implemtation below
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
// LLColor3 = |r g b|
|
// LLColor3 = |r g b|
|
||||||
|
|
@ -88,6 +89,16 @@ public:
|
||||||
const LLColor3& set(const LLColor3 &vec); // Sets LLColor3 to vec
|
const LLColor3& set(const LLColor3 &vec); // Sets LLColor3 to vec
|
||||||
const LLColor3& set(const F32 *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 magVec() const; // deprecated
|
||||||
F32 magVecSquared() const; // deprecated
|
F32 magVecSquared() const; // deprecated
|
||||||
F32 normVec(); // deprecated
|
F32 normVec(); // deprecated
|
||||||
|
|
@ -484,13 +495,45 @@ inline const LLColor3 srgbColor3(const LLColor3 &a) {
|
||||||
return srgbColor;
|
return srgbColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const LLColor3 linearColor3(const LLColor3 &a) {
|
inline const LLColor3 linearColor3p(const F32* v) {
|
||||||
LLColor3 linearColor;
|
LLColor3 linearColor;
|
||||||
linearColor.mV[0] = sRGBtoLinear(a.mV[0]);
|
linearColor.mV[0] = sRGBtoLinear(v[0]);
|
||||||
linearColor.mV[1] = sRGBtoLinear(a.mV[1]);
|
linearColor.mV[1] = sRGBtoLinear(v[1]);
|
||||||
linearColor.mV[2] = sRGBtoLinear(a.mV[2]);
|
linearColor.mV[2] = sRGBtoLinear(v[2]);
|
||||||
|
|
||||||
return linearColor;
|
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
|
#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); // 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 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 F32 *vec); // Sets LLColor4 to vec
|
||||||
const LLColor4& set(const LLColor4U& color4u); // Sets LLColor4 to color4u, rescaled.
|
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);
|
const LLColor4& setAlpha(F32 a);
|
||||||
|
|
||||||
|
|
@ -334,6 +344,15 @@ inline const LLColor4& LLColor4::set(const F32 *vec)
|
||||||
return (*this);
|
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
|
// deprecated
|
||||||
inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z)
|
inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z)
|
||||||
{
|
{
|
||||||
|
|
@ -680,5 +699,25 @@ inline const LLColor4 linearColor4(const LLColor4 &a)
|
||||||
return linearColor;
|
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
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ set(llmessage_SOURCE_FILES
|
||||||
lldispatcher.cpp
|
lldispatcher.cpp
|
||||||
llexperiencecache.cpp
|
llexperiencecache.cpp
|
||||||
llfiltersd2xmlrpc.cpp
|
llfiltersd2xmlrpc.cpp
|
||||||
|
llgenericstreamingmessage.cpp
|
||||||
llhost.cpp
|
llhost.cpp
|
||||||
llhttpnode.cpp
|
llhttpnode.cpp
|
||||||
llhttpsdhandler.cpp
|
llhttpsdhandler.cpp
|
||||||
|
|
@ -114,6 +115,7 @@ set(llmessage_HEADER_FILES
|
||||||
llextendedstatus.h
|
llextendedstatus.h
|
||||||
llfiltersd2xmlrpc.h
|
llfiltersd2xmlrpc.h
|
||||||
llfollowcamparams.h
|
llfollowcamparams.h
|
||||||
|
llgenericstreamingmessage.h
|
||||||
llhost.h
|
llhost.h
|
||||||
llhttpnode.h
|
llhttpnode.h
|
||||||
llhttpnodeadapter.h
|
llhttpnodeadapter.h
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,6 @@ LLCore::HttpRequest::ptr_t sHttpRequest;
|
||||||
LLCore::HttpHeaders::ptr_t sHttpHeaders;
|
LLCore::HttpHeaders::ptr_t sHttpHeaders;
|
||||||
LLCore::HttpOptions::ptr_t sHttpOptions;
|
LLCore::HttpOptions::ptr_t sHttpOptions;
|
||||||
LLCore::HttpRequest::policy_t sHttpPolicy;
|
LLCore::HttpRequest::policy_t sHttpPolicy;
|
||||||
LLCore::HttpRequest::priority_t sHttpPriority;
|
|
||||||
|
|
||||||
/* Sample response:
|
/* Sample response:
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
|
@ -121,7 +120,6 @@ LLAvatarNameCache::LLAvatarNameCache()
|
||||||
sHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
|
sHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
|
||||||
sHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());
|
sHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());
|
||||||
sHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID;
|
sHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID;
|
||||||
sHttpPriority = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLAvatarNameCache::~LLAvatarNameCache()
|
LLAvatarNameCache::~LLAvatarNameCache()
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,6 @@ bool responseToLLSD(HttpResponse * response, bool log, LLSD & out_llsd)
|
||||||
|
|
||||||
HttpHandle requestPostWithLLSD(HttpRequest * request,
|
HttpHandle requestPostWithLLSD(HttpRequest * request,
|
||||||
HttpRequest::policy_t policy_id,
|
HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const LLSD & body,
|
const LLSD & body,
|
||||||
const HttpOptions::ptr_t &options,
|
const HttpOptions::ptr_t &options,
|
||||||
|
|
@ -145,7 +144,6 @@ HttpHandle requestPostWithLLSD(HttpRequest * request,
|
||||||
LLSDSerialize::toXML(body, bas);
|
LLSDSerialize::toXML(body, bas);
|
||||||
|
|
||||||
handle = request->requestPost(policy_id,
|
handle = request->requestPost(policy_id,
|
||||||
priority,
|
|
||||||
url,
|
url,
|
||||||
ba,
|
ba,
|
||||||
options,
|
options,
|
||||||
|
|
@ -158,7 +156,6 @@ HttpHandle requestPostWithLLSD(HttpRequest * request,
|
||||||
|
|
||||||
HttpHandle requestPutWithLLSD(HttpRequest * request,
|
HttpHandle requestPutWithLLSD(HttpRequest * request,
|
||||||
HttpRequest::policy_t policy_id,
|
HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const LLSD & body,
|
const LLSD & body,
|
||||||
const HttpOptions::ptr_t &options,
|
const HttpOptions::ptr_t &options,
|
||||||
|
|
@ -172,7 +169,6 @@ HttpHandle requestPutWithLLSD(HttpRequest * request,
|
||||||
LLSDSerialize::toXML(body, bas);
|
LLSDSerialize::toXML(body, bas);
|
||||||
|
|
||||||
handle = request->requestPut(policy_id,
|
handle = request->requestPut(policy_id,
|
||||||
priority,
|
|
||||||
url,
|
url,
|
||||||
ba,
|
ba,
|
||||||
options,
|
options,
|
||||||
|
|
@ -184,7 +180,6 @@ HttpHandle requestPutWithLLSD(HttpRequest * request,
|
||||||
|
|
||||||
HttpHandle requestPatchWithLLSD(HttpRequest * request,
|
HttpHandle requestPatchWithLLSD(HttpRequest * request,
|
||||||
HttpRequest::policy_t policy_id,
|
HttpRequest::policy_t policy_id,
|
||||||
HttpRequest::priority_t priority,
|
|
||||||
const std::string & url,
|
const std::string & url,
|
||||||
const LLSD & body,
|
const LLSD & body,
|
||||||
const HttpOptions::ptr_t &options,
|
const HttpOptions::ptr_t &options,
|
||||||
|
|
@ -198,7 +193,6 @@ HttpHandle requestPatchWithLLSD(HttpRequest * request,
|
||||||
LLSDSerialize::toXML(body, bas);
|
LLSDSerialize::toXML(body, bas);
|
||||||
|
|
||||||
handle = request->requestPatch(policy_id,
|
handle = request->requestPatch(policy_id,
|
||||||
priority,
|
|
||||||
url,
|
url,
|
||||||
ba,
|
ba,
|
||||||
options,
|
options,
|
||||||
|
|
@ -672,10 +666,9 @@ const std::string HttpCoroutineAdapter::HTTP_RESULTS_CONTENT("content");
|
||||||
const std::string HttpCoroutineAdapter::HTTP_RESULTS_RAW("raw");
|
const std::string HttpCoroutineAdapter::HTTP_RESULTS_RAW("raw");
|
||||||
|
|
||||||
HttpCoroutineAdapter::HttpCoroutineAdapter(const std::string &name,
|
HttpCoroutineAdapter::HttpCoroutineAdapter(const std::string &name,
|
||||||
LLCore::HttpRequest::policy_t policyId, LLCore::HttpRequest::priority_t priority) :
|
LLCore::HttpRequest::policy_t policyId) :
|
||||||
mAdapterName(name),
|
mAdapterName(name),
|
||||||
mPolicyId(policyId),
|
mPolicyId(policyId),
|
||||||
mPriority(priority),
|
|
||||||
mYieldingHandle(LLCORE_HTTP_HANDLE_INVALID),
|
mYieldingHandle(LLCORE_HTTP_HANDLE_INVALID),
|
||||||
mWeakRequest(),
|
mWeakRequest(),
|
||||||
mWeakHandler()
|
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
|
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||||
// pointer from the smart pointer is safe in this case.
|
// pointer from the smart pointer is safe in this case.
|
||||||
LLCore::HttpHandle hhandle = requestPostWithLLSD(request,
|
LLCore::HttpHandle hhandle = requestPostWithLLSD(request,
|
||||||
mPolicyId, mPriority, url, body, options, headers,
|
mPolicyId, url, body, options, headers,
|
||||||
handler);
|
handler);
|
||||||
|
|
||||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
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
|
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||||
// pointer from the smart pointer is safe in this case.
|
// 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);
|
options, headers, handler);
|
||||||
|
|
||||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
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
|
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||||
// pointer from the smart pointer is safe in this case.
|
// pointer from the smart pointer is safe in this case.
|
||||||
LLCore::HttpHandle hhandle = requestPutWithLLSD(request,
|
LLCore::HttpHandle hhandle = requestPutWithLLSD(request,
|
||||||
mPolicyId, mPriority, url, body, options, headers,
|
mPolicyId, url, body, options, headers,
|
||||||
handler);
|
handler);
|
||||||
|
|
||||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
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
|
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||||
// pointer from the smart pointer is safe in this case.
|
// 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);
|
url, rawbody.get(), options, headers, handler);
|
||||||
|
|
||||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
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
|
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||||
// pointer from the smart pointer is safe in this case.
|
// 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);
|
url, options, headers, handler);
|
||||||
|
|
||||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
||||||
|
|
@ -1018,7 +1011,7 @@ LLSD HttpCoroutineAdapter::deleteAndSuspend_(LLCore::HttpRequest::ptr_t &request
|
||||||
checkDefaultHeaders(headers);
|
checkDefaultHeaders(headers);
|
||||||
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||||
// pointer from the smart pointer is safe in this case.
|
// 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);
|
url, options, headers, handler);
|
||||||
|
|
||||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
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
|
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||||
// pointer from the smart pointer is safe in this case.
|
// pointer from the smart pointer is safe in this case.
|
||||||
LLCore::HttpHandle hhandle = requestPatchWithLLSD(request,
|
LLCore::HttpHandle hhandle = requestPatchWithLLSD(request,
|
||||||
mPolicyId, mPriority, url, body, options, headers,
|
mPolicyId, url, body, options, headers,
|
||||||
handler);
|
handler);
|
||||||
|
|
||||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
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
|
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||||
// pointer from the smart pointer is safe in this case.
|
// 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);
|
options, headers, handler);
|
||||||
|
|
||||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
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
|
// The HTTPCoroHandler does not self delete, so retrieval of a the contained
|
||||||
// pointer from the smart pointer is safe in this case.
|
// 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);
|
options, headers, handler);
|
||||||
|
|
||||||
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
|
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