Compare commits
339 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b03b4db7c7 | ||
|
|
859e2701f2 | ||
|
|
7b6ff27c4b | ||
|
|
2526d04397 | ||
|
|
4ffa06ae07 | ||
|
|
f68211d83e | ||
|
|
7694f915f5 | ||
|
|
b5ec7fe015 | ||
|
|
55cce46454 | ||
|
|
071745007a | ||
|
|
b177324058 | ||
|
|
e7a20b04de | ||
|
|
5245547f28 | ||
|
|
ef696d895d | ||
|
|
a15e72dc03 | ||
|
|
b7997a2677 | ||
|
|
c39ddb5991 | ||
|
|
9dd8f1b8ab | ||
|
|
744b5b6404 | ||
|
|
381d86adb7 | ||
|
|
26858c026a | ||
|
|
c454044913 | ||
|
|
6e57791397 | ||
|
|
1c5fc42772 | ||
|
|
9bab3a362f | ||
|
|
fc65380f2a | ||
|
|
c1b749e12c | ||
|
|
d310ae3bc6 | ||
|
|
9ab0cd11e7 | ||
|
|
51c3f3253b | ||
|
|
00c00b617c | ||
|
|
c0dd8cac46 | ||
|
|
8c35361878 | ||
|
|
2e59ae1340 | ||
|
|
856507a580 | ||
|
|
8899dbef3c | ||
|
|
8e4ea7e3b4 | ||
|
|
5524959f33 | ||
|
|
39959712c1 | ||
|
|
c652df10c6 | ||
|
|
131dc84256 | ||
|
|
afed6dad84 | ||
|
|
b18033d023 | ||
|
|
26bb68fcb7 | ||
|
|
2c4f850e5f | ||
|
|
502fd90a8d | ||
|
|
f2c6ab27e3 | ||
|
|
40bbeebd27 | ||
|
|
f9d802f832 | ||
|
|
a6f95d21af | ||
|
|
87f0edc652 | ||
|
|
97c0800701 | ||
|
|
da96043a24 | ||
|
|
f6fcf8ca38 | ||
|
|
43b826bd52 | ||
|
|
cef03d52cb | ||
|
|
29cdfdc13e | ||
|
|
2b8a5b4bd1 | ||
|
|
910cb29a7f | ||
|
|
3261332e0b | ||
|
|
6939d2d70b | ||
|
|
df65a3b7fc | ||
|
|
7d9299d870 | ||
|
|
00ae7c3cd3 | ||
|
|
769c4f43bd | ||
|
|
7fec659979 | ||
|
|
d104d15c53 | ||
|
|
22137671da | ||
|
|
9577607c22 | ||
|
|
4340cee991 | ||
|
|
d385de9139 | ||
|
|
c4e0122846 | ||
|
|
6374f012de | ||
|
|
7d4c2aa54f | ||
|
|
c5024ff04d | ||
|
|
63117686b1 | ||
|
|
f6bd78083d | ||
|
|
f176aeed8d | ||
|
|
51746dc751 | ||
|
|
94d6ef126f | ||
|
|
14f2df2a72 | ||
|
|
82693aae35 | ||
|
|
c4e55464c9 | ||
|
|
4a4b786a60 | ||
|
|
d7d65df9e0 | ||
|
|
40400d696b | ||
|
|
4c201a9b83 | ||
|
|
b338506229 | ||
|
|
7805508e8d | ||
|
|
9837b0ea2e | ||
|
|
60d5bb81f2 | ||
|
|
76cb68600c | ||
|
|
a6b270b02d | ||
|
|
f68a899185 | ||
|
|
3299d27197 | ||
|
|
a39bf61977 | ||
|
|
6a290864af | ||
|
|
20ab55752d | ||
|
|
4190816023 | ||
|
|
e33a15d410 | ||
|
|
419f7b41af | ||
|
|
670b85a86f | ||
|
|
e835d51bdf | ||
|
|
242134d2af | ||
|
|
f0f2834cfe | ||
|
|
860bddb1f5 | ||
|
|
14f9cd57e1 | ||
|
|
063112bf59 | ||
|
|
e764329701 | ||
|
|
27a17b332f | ||
|
|
373688cfb0 | ||
|
|
09d37d7dfd | ||
|
|
b2dd4f652e | ||
|
|
6bbff07e00 | ||
|
|
09c7e66844 | ||
|
|
c371b82900 | ||
|
|
5da990e8fb | ||
|
|
b96beb478c | ||
|
|
ad3a16fd3b | ||
|
|
21b6b89577 | ||
|
|
55a66737c0 | ||
|
|
198e499798 | ||
|
|
9d3b276f61 | ||
|
|
b0967463ca | ||
|
|
1cc33caaa3 | ||
|
|
0777bedde8 | ||
|
|
be978ab76b | ||
|
|
21a64b306d | ||
|
|
5a66c2bfba | ||
|
|
e5a27e6558 | ||
|
|
6f3a92d772 | ||
|
|
4feb69e342 | ||
|
|
d2b2c501bc | ||
|
|
465660e235 | ||
|
|
4eea8624b7 | ||
|
|
09213950c3 | ||
|
|
d93f0bb56a | ||
|
|
4de23007a5 | ||
|
|
8543106f5e | ||
|
|
ced937cc46 | ||
|
|
9476aedaf6 | ||
|
|
68bc6749e5 | ||
|
|
c5d4ccc78d | ||
|
|
e847b105f2 | ||
|
|
d6e9b50b99 | ||
|
|
61beedd3d9 | ||
|
|
35333f0105 | ||
|
|
be700d0719 | ||
|
|
5dd2f5e2cf | ||
|
|
e9bd6a3b0d | ||
|
|
d505e515e4 | ||
|
|
9fd813267e | ||
|
|
f14e6cdb60 | ||
|
|
fe87ac0f3d | ||
|
|
a6f36abab0 | ||
|
|
621e677898 | ||
|
|
626a94cf8f | ||
|
|
d66074d2ea | ||
|
|
bf28f6514f | ||
|
|
cf62e22409 | ||
|
|
900d063d4f | ||
|
|
b911e86b02 | ||
|
|
54bfdb7704 | ||
|
|
566152c230 | ||
|
|
dcbf39bcfa | ||
|
|
c73913a864 | ||
|
|
d3ba4a2b80 | ||
|
|
af7affa9dd | ||
|
|
89e738003c | ||
|
|
a3f7399d7d | ||
|
|
dff195d120 | ||
|
|
48552e3027 | ||
|
|
c6ce417fac | ||
|
|
a7510d3b3a | ||
|
|
aad10c9b8d | ||
|
|
ca96e00135 | ||
|
|
536189340d | ||
|
|
23b97efb69 | ||
|
|
2c8e3bb0a3 | ||
|
|
7a48cb9979 | ||
|
|
2f5caa27fd | ||
|
|
d69f00741f | ||
|
|
8c4a52e58d | ||
|
|
fd22d80dfd | ||
|
|
e071dc52fd | ||
|
|
e1cbeb7e02 | ||
|
|
9d367cf9f2 | ||
|
|
3890e61fbc | ||
|
|
3df853b74b | ||
|
|
10bc483305 | ||
|
|
f55fa45b73 | ||
|
|
acb24dd3e1 | ||
|
|
4b87c45298 | ||
|
|
a2fb56bf48 | ||
|
|
37095dc2cd | ||
|
|
a57ac5a954 | ||
|
|
29045609a3 | ||
|
|
b4dad425aa | ||
|
|
c73414f1a1 | ||
|
|
6920bee5e2 | ||
|
|
6a5e203884 | ||
|
|
6b1f44ed6d | ||
|
|
ab8cd3e5d5 | ||
|
|
78f7cc0d64 | ||
|
|
b607650d5c | ||
|
|
1bfa72fa7c | ||
|
|
0030ca3af7 | ||
|
|
a53e08032f | ||
|
|
62febda165 | ||
|
|
a726de0e99 | ||
|
|
918d527b14 | ||
|
|
5919c9a788 | ||
|
|
14f2248ea1 | ||
|
|
81499fc6ea | ||
|
|
ffb285c6ff | ||
|
|
e08e8cf131 | ||
|
|
40b4b47023 | ||
|
|
2565caf62a | ||
|
|
d63df79b85 | ||
|
|
697dd7e929 | ||
|
|
f613be9276 | ||
|
|
f5a08b1c12 | ||
|
|
f40bbb1602 | ||
|
|
aeb766ee37 | ||
|
|
cd67046b33 | ||
|
|
66f4c170cb | ||
|
|
a485760028 | ||
|
|
0b5a2cd6a3 | ||
|
|
8e7733b2ce | ||
|
|
08d2c17c65 | ||
|
|
09f7136cf4 | ||
|
|
c4b77e247e | ||
|
|
9f9daba33d | ||
|
|
dc3831c86b | ||
|
|
ab14f1908c | ||
|
|
bf6e1d6c75 | ||
|
|
5d8d402403 | ||
|
|
b8eb3076ce | ||
|
|
d16e48e128 | ||
|
|
e46c906a8b | ||
|
|
83e8a9076b | ||
|
|
56b28756ad | ||
|
|
13fad75811 | ||
|
|
1cf367aae5 | ||
|
|
70909f86c8 | ||
|
|
1fd908b2c4 | ||
|
|
f0108c17b9 | ||
|
|
0566bde61b | ||
|
|
a31fc8a612 | ||
|
|
2ba9e16a6c | ||
|
|
e6dce6ad7b | ||
|
|
c87caebcf7 | ||
|
|
121a557fe5 | ||
|
|
6aa7f219cd | ||
|
|
e9e05bec90 | ||
|
|
8421661a89 | ||
|
|
7fea7c589d | ||
|
|
0e3b735a60 | ||
|
|
236f5757a2 | ||
|
|
0a44e3ee09 | ||
|
|
ee5a9c97be | ||
|
|
2126654979 | ||
|
|
df40a8c5cf | ||
|
|
34fb647903 | ||
|
|
5de4f1e2da | ||
|
|
18dd31f51a | ||
|
|
40689f7d1e | ||
|
|
4ce0345842 | ||
|
|
844e38702a | ||
|
|
5f074c8c82 | ||
|
|
5c2b1d396b | ||
|
|
b0b7837c4d | ||
|
|
7789c5a703 | ||
|
|
b64cb8d339 | ||
|
|
3891928092 | ||
|
|
f5983208eb | ||
|
|
0ef5931212 | ||
|
|
6964cec6f1 | ||
|
|
a35ef93d19 | ||
|
|
e5f75d1e48 | ||
|
|
231af66b90 | ||
|
|
f386fc75df | ||
|
|
cc45a24aff | ||
|
|
e06d0b2e70 | ||
|
|
0281ac4afe | ||
|
|
7227c01d79 | ||
|
|
c5abde1616 | ||
|
|
c2a4951f20 | ||
|
|
0fde15246b | ||
|
|
b3423de80a | ||
|
|
743449e635 | ||
|
|
405182025d | ||
|
|
bd6d14d741 | ||
|
|
0e190cadcd | ||
|
|
408f5a4a51 | ||
|
|
53f5957b92 | ||
|
|
fb32a0be5a | ||
|
|
474e1ec7cc | ||
|
|
1e9d09b82e | ||
|
|
c3b1bf4b76 | ||
|
|
e2d9c31f5e | ||
|
|
7b81e9d248 | ||
|
|
6e6c438e2a | ||
|
|
4606c7512e | ||
|
|
88e373c960 | ||
|
|
f2deb39dac | ||
|
|
8a5793ce23 | ||
|
|
a36c5f2ee6 | ||
|
|
c63bf31328 | ||
|
|
5d811163a6 | ||
|
|
78a98cbf08 | ||
|
|
91348909b5 | ||
|
|
73f2543a6f | ||
|
|
d80458b726 | ||
|
|
22385c44c8 | ||
|
|
40261d3472 | ||
|
|
06ff562cd2 | ||
|
|
e7b023778a | ||
|
|
3e12fe15bc | ||
|
|
95634e8276 | ||
|
|
6c19346855 | ||
|
|
2e4419a295 | ||
|
|
bdc95a1544 | ||
|
|
68e143de1b | ||
|
|
5d6aadb268 | ||
|
|
4368c57243 | ||
|
|
ef54491760 | ||
|
|
d88f696604 | ||
|
|
82b0171a86 | ||
|
|
ff786ad2c7 | ||
|
|
c95696e8a0 | ||
|
|
4dbed63f0b | ||
|
|
3de99315e2 | ||
|
|
5945793031 | ||
|
|
449e7b2a84 | ||
|
|
cdebc1c5cc | ||
|
|
e95ee85804 | ||
|
|
5e69c9fa05 | ||
|
|
370890b704 |
@@ -1,4 +0,0 @@
|
||||
This is a modified version of openal-soft from GIT (56cc03860378e2758370b773b2a6f1b4e086b49a).
|
||||
The modified source which this was built from is available here:
|
||||
http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/openal-soft-linden-56cc03860378e2758370b773b2a6f1b4e086b49a.tar.bz2
|
||||
|
||||
@@ -670,19 +670,19 @@
|
||||
<key>EstateChangeInfo</key>
|
||||
<boolean>true</boolean>
|
||||
|
||||
<key>FetchInventoryDescendents</key>
|
||||
<key>FetchInventoryDescendents2</key>
|
||||
<boolean>false</boolean>
|
||||
|
||||
<key>WebFetchInventoryDescendents</key>
|
||||
<boolean>false</boolean>
|
||||
|
||||
<key>FetchInventory</key>
|
||||
<key>FetchInventory2</key>
|
||||
<boolean>true</boolean>
|
||||
|
||||
<key>FetchLibDescendents</key>
|
||||
<key>FetchLibDescendents2</key>
|
||||
<boolean>true</boolean>
|
||||
|
||||
<key>FetchLib</key>
|
||||
<key>FetchLib2</key>
|
||||
<boolean>true</boolean>
|
||||
</map>
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ if (WINDOWS)
|
||||
|
||||
endif (WINDOWS)
|
||||
|
||||
set (GCC_EXTRA_OPTIMIZATION "-ffast-math -frounding-math")
|
||||
set (GCC_EXTRA_OPTIMIZATIONS "-ffast-math -frounding-math")
|
||||
|
||||
if (LINUX)
|
||||
set(CMAKE_SKIP_RPATH TRUE)
|
||||
@@ -182,53 +182,29 @@ if (LINUX)
|
||||
-pthread
|
||||
)
|
||||
|
||||
if (SERVER)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-60")
|
||||
if (EXISTS /etc/debian_version)
|
||||
FILE(READ /etc/debian_version DEBIAN_VERSION)
|
||||
else (EXISTS /etc/debian_version)
|
||||
set(DEBIAN_VERSION "")
|
||||
endif (EXISTS /etc/debian_version)
|
||||
|
||||
if (NOT DEBIAN_VERSION STREQUAL "3.1")
|
||||
add_definitions(-DCTYPE_WORKAROUND)
|
||||
endif (NOT DEBIAN_VERSION STREQUAL "3.1")
|
||||
|
||||
if (EXISTS /usr/lib/mysql4/mysql)
|
||||
link_directories(/usr/lib/mysql4/mysql)
|
||||
endif (EXISTS /usr/lib/mysql4/mysql)
|
||||
|
||||
add_definitions(
|
||||
-msse2
|
||||
-mfpmath=sse
|
||||
)
|
||||
endif (SERVER)
|
||||
|
||||
if (VIEWER)
|
||||
add_definitions(-DAPPID=secondlife)
|
||||
add_definitions(-fvisibility=hidden)
|
||||
# don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The viewer doesn't need to catch SIGCHLD anyway.
|
||||
add_definitions(-DLL_IGNORE_SIGCHLD)
|
||||
add_definitions(-DAPPID=secondlife)
|
||||
add_definitions(-fvisibility=hidden)
|
||||
# don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The viewer doesn't need to catch SIGCHLD anyway.
|
||||
add_definitions(-DLL_IGNORE_SIGCHLD)
|
||||
if (NOT STANDALONE)
|
||||
# this stops us requiring a really recent glibc at runtime
|
||||
add_definitions(-fno-stack-protector)
|
||||
endif (NOT STANDALONE)
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
add_definitions(-DLINUX64=1 -pipe)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
else (${ARCH} STREQUAL "x86_64")
|
||||
if (NOT STANDALONE)
|
||||
# this stops us requiring a really recent glibc at runtime
|
||||
add_definitions(-fno-stack-protector)
|
||||
set(MARCH_FLAG " -march=pentium4")
|
||||
endif (NOT STANDALONE)
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
add_definitions(-DLINUX64=1 -pipe)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
|
||||
else (${ARCH} STREQUAL "x86_64")
|
||||
if (NOT STANDALONE)
|
||||
set(MARCH_FLAG " -march=pentium4")
|
||||
endif (NOT STANDALONE)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 "${GCC_EXTRA_OPTIMIZATIONS})
|
||||
endif (${ARCH} STREQUAL "x86_64")
|
||||
endif (VIEWER)
|
||||
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
endif (${ARCH} STREQUAL "x86_64")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG} -msse2")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
@@ -258,13 +234,13 @@ endif (DARWIN)
|
||||
|
||||
|
||||
if (LINUX OR DARWIN)
|
||||
set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor -Woverloaded-virtual")
|
||||
set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs")
|
||||
|
||||
if (NOT GCC_DISABLE_FATAL_WARNINGS)
|
||||
set(GCC_WARNINGS "${GCC_WARNINGS} -Werror")
|
||||
endif (NOT GCC_DISABLE_FATAL_WARNINGS)
|
||||
|
||||
set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder")
|
||||
set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
|
||||
|
||||
set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}")
|
||||
@@ -298,10 +274,6 @@ if(1 EQUAL 1)
|
||||
add_definitions(-DMESH_ENABLED=1)
|
||||
endif(1 EQUAL 1)
|
||||
|
||||
if(SERVER)
|
||||
include_directories(${LIBS_PREBUILT_DIR}/include/havok)
|
||||
endif(SERVER)
|
||||
|
||||
SET( CMAKE_EXE_LINKER_FLAGS_RELEASESSE2
|
||||
"${CMAKE_EXE_LINKER_FLAGS_RELEASE}" CACHE STRING
|
||||
"Flags used for linking binaries under SSE2 build."
|
||||
|
||||
@@ -6,6 +6,11 @@ set(DB_FIND_REQUIRED ON)
|
||||
if (STANDALONE)
|
||||
include(FindBerkeleyDB)
|
||||
else (STANDALONE)
|
||||
set(DB_LIBRARIES db-4.2)
|
||||
if (LINUX)
|
||||
# Need to add dependency pthread explicitely to support ld.gold.
|
||||
set(DB_LIBRARIES db-4.2 pthread)
|
||||
else (LINUX)
|
||||
set(DB_LIBRARIES db-4.2)
|
||||
endif (LINUX)
|
||||
set(DB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
|
||||
endif (STANDALONE)
|
||||
|
||||
@@ -35,7 +35,7 @@ set(cmake_SOURCE_FILES
|
||||
FindNDOF.cmake
|
||||
FindOpenJPEG.cmake
|
||||
FindXmlRpcEpi.cmake
|
||||
FMOD.cmake
|
||||
FMOD.cmake
|
||||
FreeType.cmake
|
||||
GStreamer010Plugin.cmake
|
||||
GooglePerfTools.cmake
|
||||
@@ -84,6 +84,10 @@ set(cmake_SOURCE_FILES
|
||||
ZLIB.cmake
|
||||
)
|
||||
|
||||
if(FMODEX)
|
||||
list(APPEND cmake_SOURCE_FILES FMODEX.cmake)
|
||||
endif(FMODEX)
|
||||
|
||||
source_group("Shared Rules" FILES ${cmake_SOURCE_FILES})
|
||||
|
||||
set(master_SOURCE_FILES
|
||||
|
||||
@@ -243,12 +243,51 @@ set(all_targets ${all_targets} ${out_targets})
|
||||
set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
|
||||
set(release_files
|
||||
libtcmalloc_minimal.dll
|
||||
fmod.dll
|
||||
libhunspell.dll
|
||||
libapr-1.dll
|
||||
libaprutil-1.dll
|
||||
libapriconv-1.dll
|
||||
)
|
||||
|
||||
if(FMODEX)
|
||||
find_path(FMODEX_BINARY_DIR fmodex.dll
|
||||
${release_src_dir}
|
||||
${FMODEX_SDK_DIR}/api
|
||||
${FMODEX_SDK_DIR}
|
||||
)
|
||||
|
||||
if(FMODEX_BINARY_DIR)
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/ReleaseSSE2" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmodex.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
endif(FMODEX_BINARY_DIR)
|
||||
endif(FMODEX)
|
||||
|
||||
if(FMOD)
|
||||
find_path(FMOD_BINARY_DIR fmod.dll
|
||||
${release_src_dir}
|
||||
${FMOD_SDK_DIR}/api
|
||||
${FMOD_SDK_DIR}
|
||||
)
|
||||
|
||||
if(FMOD_BINARY_DIR)
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/ReleaseSSE2" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmod.dll)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
else(FMOD_BINARY_DIR)
|
||||
list(APPEND release_files fmod.dll) #Required for compile. This will cause an error in copying binaries.
|
||||
endif(FMOD_BINARY_DIR)
|
||||
endif(FMOD)
|
||||
|
||||
copy_if_different(
|
||||
${release_src_dir}
|
||||
|
||||
@@ -6,6 +6,7 @@ set(install_dir "@CMAKE_SOURCE_DIR@/..")
|
||||
set(scp "@SCP_EXECUTABLE@")
|
||||
set(scripts_dir "@SCRIPTS_DIR@")
|
||||
set(sentinel_dir "@CMAKE_BINARY_DIR@/prepare")
|
||||
set(prebuilt_type "@PREBUILT_TYPE@")
|
||||
|
||||
# In proprietary mode we use scp for download.
|
||||
set(proprietary "@INSTALL_PROPRIETARY@")
|
||||
@@ -19,7 +20,7 @@ foreach(package ${packages})
|
||||
# This package is missing or out of date.
|
||||
message(STATUS "Obtaining${proprietary_message} prebuilt '${package}'")
|
||||
execute_process(
|
||||
COMMAND ${python} install.py --install-dir=${install_dir} ${scp_option} ${package}
|
||||
COMMAND ${python} install.py -p${prebuilt_type} --install-dir=${install_dir} ${scp_option} ${package}
|
||||
WORKING_DIRECTORY ${scripts_dir}
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
|
||||
83
indra/cmake/FMODEX.cmake
Normal file
83
indra/cmake/FMODEX.cmake
Normal file
@@ -0,0 +1,83 @@
|
||||
# -*- cmake -*-
|
||||
|
||||
include(Linking)
|
||||
|
||||
if(INSTALL_PROPRIETARY)
|
||||
include(Prebuilt)
|
||||
use_prebuilt_binary(fmodex)
|
||||
endif(INSTALL_PROPRIETARY)
|
||||
|
||||
find_library(FMODEX_LIBRARY_RELEASE
|
||||
NAMES fmodex fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${ARCH_PREBUILT_DIRS_RELEASE}
|
||||
)
|
||||
|
||||
find_library(FMODEX_LIBRARY_DEBUG
|
||||
NAMES fmodex fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${ARCH_PREBUILT_DIRS_DEBUG}
|
||||
)
|
||||
|
||||
if (FMODEX_LIBRARY_RELEASE AND FMODEX_LIBRARY_DEBUG)
|
||||
set(FMODEX_LIBRARY
|
||||
debug ${FMODEX_LIBRARY_DEBUG}
|
||||
optimized ${FMODEX_LIBRARY_RELEASE})
|
||||
elseif (FMODEX_LIBRARY_RELEASE)
|
||||
set(FMODEX_LIBRARY ${FMODEX_LIBRARY_RELEASE})
|
||||
endif (FMODEX_LIBRARY_RELEASE AND FMODEX_LIBRARY_DEBUG)
|
||||
|
||||
if (NOT FMODEX_LIBRARY)
|
||||
set(FMODEX_SDK_DIR CACHE PATH "Path to the FMOD Ex SDK.")
|
||||
if (FMODEX_SDK_DIR)
|
||||
find_library(FMODEX_LIBRARY
|
||||
fmodex fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${FMODEX_SDK_DIR}/api/lib
|
||||
${FMODEX_SDK_DIR}/api
|
||||
${FMODEX_SDK_DIR}/lib
|
||||
${FMODEX_SDK_DIR}
|
||||
)
|
||||
|
||||
|
||||
endif(FMODEX_SDK_DIR)
|
||||
if(WINDOWS AND NOT FMODEX_LIBRARY)
|
||||
set(FMODEX_PROG_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows")
|
||||
find_library(FMODEX_LIBRARY
|
||||
fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
${FMODEX_PROG_DIR}/api/lib
|
||||
${FMODEX_PROG_DIR}/api
|
||||
${FMODEX_PROG_DIR}
|
||||
)
|
||||
if(FMODEX_LIBRARY)
|
||||
message(STATUS "Found fmodex in ${FMODEX_PROG_DIR}")
|
||||
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR})
|
||||
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR} CACHE PATH "Path to the FMOD Ex SDK." FORCE)
|
||||
endif(FMODEX_LIBRARY)
|
||||
endif(WINDOWS AND NOT FMODEX_LIBRARY)
|
||||
endif (NOT FMODEX_LIBRARY)
|
||||
|
||||
find_path(FMODEX_INCLUDE_DIR fmod.h
|
||||
${LIBS_PREBUILT_DIR}/include/fmodex
|
||||
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/fmodex
|
||||
${FMODEX_SDK_DIR}/api/inc
|
||||
${FMODEX_SDK_DIR}/inc
|
||||
${FMODEX_SDK_DIR}
|
||||
)
|
||||
|
||||
if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||
set(FMODEX ON CACHE BOOL "Use closed source FMOD Ex sound library.")
|
||||
else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||
set(FMODEX_LIBRARY "")
|
||||
set(FMODEX_INCLUDE_DIR "")
|
||||
if (FMODEX)
|
||||
message(STATUS "No support for FMOD Ex audio (need to set FMODEX_SDK_DIR?)")
|
||||
endif (FMODEX)
|
||||
set(FMODEX OFF CACHE BOOL "Use closed source FMOD Ex sound library.")
|
||||
set(FMODEX OFF)
|
||||
endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||
|
||||
if (FMODEX)
|
||||
message(STATUS "Building with FMOD Ex audio support")
|
||||
endif (FMODEX)
|
||||
@@ -18,7 +18,14 @@ set(LLCOMMON_INCLUDE_DIRS
|
||||
${Boost_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(LLCOMMON_LIBRARIES llcommon)
|
||||
if (LINUX)
|
||||
# In order to support using ld.gold on linux, we need to explicitely
|
||||
# specify all libraries that llcommon uses.
|
||||
# llcommon uses `clock_gettime' which is provided by librt on linux.
|
||||
set(LLCOMMON_LIBRARIES llcommon rt)
|
||||
else (LINUX)
|
||||
set(LLCOMMON_LIBRARIES llcommon)
|
||||
endif (LINUX)
|
||||
|
||||
set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.")
|
||||
if(LLCOMMON_LINK_SHARED)
|
||||
|
||||
@@ -5,4 +5,10 @@ set(LLPLUGIN_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/llplugin
|
||||
)
|
||||
|
||||
set(LLPLUGIN_LIBRARIES llplugin)
|
||||
if (LINUX)
|
||||
# In order to support using ld.gold on linux, we need to explicitely
|
||||
# specify all libraries that llplugin uses.
|
||||
set(LLPLUGIN_LIBRARIES llplugin pthread)
|
||||
else (LINUX)
|
||||
set(LLPLUGIN_LIBRARIES llplugin)
|
||||
endif (LINUX)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
if (NOT STANDALONE)
|
||||
if (NOT (STANDALONE OR DARWIN))
|
||||
use_prebuilt_binary(glext)
|
||||
# possible glh_linear should have its own .cmake file instead
|
||||
#use_prebuilt_binary(glh_linear)
|
||||
# actually... not any longer, it's now in git -SG
|
||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
||||
endif (NOT STANDALONE)
|
||||
endif ()
|
||||
|
||||
@@ -76,24 +76,16 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(DARWIN 1)
|
||||
|
||||
# NOTE: If specifying a different SDK with CMAKE_OSX_SYSROOT at configure
|
||||
# time you should also specify CMAKE_OSX_DEPLOYMENT_TARGET explicitly,
|
||||
# otherwise CMAKE_OSX_SYSROOT will be overridden here. We can't just check
|
||||
# for it being unset, as it gets set to the system default :(
|
||||
|
||||
# Default to building against the 10.5 SDK if no deployment target is
|
||||
# specified.
|
||||
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
# NOTE: setting -isysroot is NOT adequate: http://lists.apple.com/archives/Xcode-users/2007/Oct/msg00696.html
|
||||
# see http://public.kitware.com/Bug/view.php?id=9959 + poppy
|
||||
#SDK Compiler and Deployment targets for XCode
|
||||
if (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
|
||||
endif (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
set(CMAKE_XCODE_ATTIBUTE_GCC_VERSION "4.2")
|
||||
else (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42")
|
||||
endif (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
|
||||
# Use GCC 4.2
|
||||
if (${CMAKE_OSX_SYSROOT} MATCHES "10.5")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "4.2")
|
||||
endif (${CMAKE_OSX_SYSROOT} MATCHES "10.5")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
|
||||
|
||||
# NOTE: To attempt an i386/PPC Universal build, add this on the configure line:
|
||||
# -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'
|
||||
@@ -118,6 +110,17 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
|
||||
|
||||
if (WINDOWS)
|
||||
set(PREBUILT_TYPE windows)
|
||||
elseif(DARWIN)
|
||||
set(PREBUILT_TYPE darwin)
|
||||
elseif(LINUX AND WORD_SIZE EQUAL 32)
|
||||
set(PREBUILT_TYPE linux)
|
||||
elseif(LINUX AND WORD_SIZE EQUAL 64)
|
||||
set(PREBUILT_TYPE linux64)
|
||||
endif(WINDOWS)
|
||||
|
||||
|
||||
# Default deploy grid
|
||||
set(GRID agni CACHE STRING "Target Grid")
|
||||
|
||||
|
||||
@@ -775,9 +775,8 @@ Options:
|
||||
-p | --project=NAME set the root project name. (Doesn't effect makefiles)
|
||||
|
||||
Commands:
|
||||
build configure and build default target
|
||||
clean delete all build directories, does not affect sources
|
||||
configure configure project by running cmake (default command if none given)
|
||||
build configure and build default target
|
||||
clean delete all build directories, does not affect sources
|
||||
configure configure project by running cmake (default if none given)
|
||||
printbuilddirs print the build directory that will be used
|
||||
|
||||
|
||||
@@ -168,7 +168,10 @@ ARGUMENTS=[
|
||||
dict(name='version',
|
||||
description="""This specifies the version of Second Life that is
|
||||
being packaged up.""",
|
||||
default=get_default_version)
|
||||
default=get_default_version),
|
||||
dict(name='extra_libraries',
|
||||
description="""List of extra libraries to include in package""",
|
||||
default=None)
|
||||
]
|
||||
|
||||
def usage(srctree=""):
|
||||
|
||||
@@ -1,105 +1,84 @@
|
||||
# Main CMakeLists.txt to build the OpenJPEG project using CMake (www.cmake.org)
|
||||
# Written by Mathieu Malaterre
|
||||
# -*- cmake -*-
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
project(openjpeg)
|
||||
|
||||
IF(COMMAND CMAKE_POLICY)
|
||||
CMAKE_POLICY(SET CMP0003 NEW)
|
||||
ENDIF(COMMAND CMAKE_POLICY)
|
||||
include(00-Common)
|
||||
|
||||
PROJECT(openjpeg)
|
||||
|
||||
# Do full dependency headers.
|
||||
INCLUDE_REGULAR_EXPRESSION("^.*$")
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# OPENJPEG version number, useful for packaging and doxygen doc:
|
||||
SET(OPENJPEG_VERSION_MAJOR 1)
|
||||
SET(OPENJPEG_VERSION_MINOR 4)
|
||||
SET(OPENJPEG_VERSION_BUILD 0)
|
||||
SET(OPENJPEG_VERSION
|
||||
set(OPENJPEG_VERSION_MAJOR 1)
|
||||
set(OPENJPEG_VERSION_MINOR 4)
|
||||
set(OPENJPEG_VERSION_BUILD 0)
|
||||
set(OPENJPEG_VERSION
|
||||
"${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}")
|
||||
|
||||
set(openjpeg_SOURCE_FILES
|
||||
bio.c
|
||||
cio.c
|
||||
dwt.c
|
||||
event.c
|
||||
image.c
|
||||
j2k.c
|
||||
j2k_lib.c
|
||||
jp2.c
|
||||
jpt.c
|
||||
mct.c
|
||||
mqc.c
|
||||
openjpeg.c
|
||||
pi.c
|
||||
raw.c
|
||||
t1.c
|
||||
t2.c
|
||||
tcd.c
|
||||
tgt.c
|
||||
)
|
||||
|
||||
set(openjpeg_HEADER_FILES
|
||||
bio.h
|
||||
cio.h
|
||||
dwt.h
|
||||
event.h
|
||||
fix.h
|
||||
image.h
|
||||
int.h
|
||||
j2k.h
|
||||
j2k_lib.h
|
||||
jp2.h
|
||||
jpt.h
|
||||
mct.h
|
||||
mqc.h
|
||||
openjpeg.h
|
||||
opj_includes.h
|
||||
opj_malloc.h
|
||||
pi.h
|
||||
raw.h
|
||||
t1.h
|
||||
t1_luts.h
|
||||
t2.h
|
||||
tcd.h
|
||||
tgt.h
|
||||
)
|
||||
|
||||
IF(WINDOWS)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-DOPJ_STATIC)
|
||||
ENDIF(WINDOWS)
|
||||
|
||||
|
||||
set_source_files_properties(${openjpeg_HEADER_FILES}
|
||||
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
list(APPEND openjpeg_SOURCE_FILES ${openjpeg_HEADER_FILES})
|
||||
|
||||
add_library (openjpeg ${openjpeg_SOURCE_FILES})
|
||||
|
||||
# This setting of SOVERSION assumes that any API change
|
||||
# will increment either the minor or major version number of openjpeg
|
||||
SET(OPENJPEG_LIBRARY_PROPERTIES
|
||||
set(OPENJPEG_LIBRARY_PROPERTIES
|
||||
VERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}"
|
||||
SOVERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}"
|
||||
)
|
||||
|
||||
# On Visual Studio 8 MS deprecated C. This removes all 1.276E1265 security
|
||||
# warnings
|
||||
IF(WIN32)
|
||||
IF(NOT BORLAND)
|
||||
IF(NOT CYGWIN)
|
||||
IF(NOT MINGW)
|
||||
IF(NOT ITK_ENABLE_VISUAL_STUDIO_DEPRECATED_C_WARNINGS)
|
||||
ADD_DEFINITIONS(
|
||||
-D_CRT_FAR_MAPPINGS_NO_DEPRECATE
|
||||
-D_CRT_IS_WCTYPE_NO_DEPRECATE
|
||||
-D_CRT_MANAGED_FP_NO_DEPRECATE
|
||||
-D_CRT_NONSTDC_NO_DEPRECATE
|
||||
-D_CRT_SECURE_NO_DEPRECATE
|
||||
-D_CRT_SECURE_NO_DEPRECATE_GLOBALS
|
||||
-D_CRT_SETERRORMODE_BEEP_SLEEP_NO_DEPRECATE
|
||||
-D_CRT_TIME_FUNCTIONS_NO_DEPRECATE
|
||||
-D_CRT_VCCLRIT_NO_DEPRECATE
|
||||
-D_SCL_SECURE_NO_DEPRECATE
|
||||
)
|
||||
ENDIF(NOT ITK_ENABLE_VISUAL_STUDIO_DEPRECATED_C_WARNINGS)
|
||||
ENDIF(NOT MINGW)
|
||||
ENDIF(NOT CYGWIN)
|
||||
ENDIF(NOT BORLAND)
|
||||
ENDIF(WIN32)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Test for some required system information.
|
||||
# INCLUDE (${CMAKE_ROOT}/Modules/CMakeBackwardCompatibilityC.cmake)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Compiler specific flags:
|
||||
IF(CMAKE_COMPILER_IS_GNUCC)
|
||||
# For all builds, make sure openjpeg is std99 compliant:
|
||||
# SET(CMAKE_C_FLAGS "-Wall -std=c99 ${CMAKE_C_FLAGS}") # FIXME: this setting prevented us from setting a coverage build.
|
||||
# Do not use ffast-math for all build, it would produce incorrect results, only set for release:
|
||||
SET(CMAKE_C_FLAGS_RELEASE "-ffast-math ${CMAKE_C_FLAGS_RELEASE}")
|
||||
ENDIF(CMAKE_COMPILER_IS_GNUCC)
|
||||
|
||||
# Defines the source code for the library
|
||||
SET(OPENJPEG_SRCS
|
||||
bio.c
|
||||
cio.c
|
||||
dwt.c
|
||||
event.c
|
||||
image.c
|
||||
j2k.c
|
||||
j2k_lib.c
|
||||
jp2.c
|
||||
jpt.c
|
||||
mct.c
|
||||
mqc.c
|
||||
openjpeg.c
|
||||
pi.c
|
||||
raw.c
|
||||
t1.c
|
||||
t2.c
|
||||
tcd.c
|
||||
tgt.c
|
||||
)
|
||||
|
||||
# Pass proper definition to preprocessor to generate shared lib
|
||||
IF(WIN32)
|
||||
IF(BUILD_SHARED_LIBS)
|
||||
ADD_DEFINITIONS(-DOPJ_EXPORTS)
|
||||
ELSE(BUILD_SHARED_LIBS)
|
||||
ADD_DEFINITIONS(-DOPJ_STATIC)
|
||||
ENDIF(BUILD_SHARED_LIBS)
|
||||
ENDIF(WIN32)
|
||||
|
||||
# Create the library
|
||||
ADD_LIBRARY(openjpeg ${OPENJPEG_SRCS})
|
||||
SET_TARGET_PROPERTIES(openjpeg PROPERTIES
|
||||
set_target_properties(openjpeg PROPERTIES
|
||||
${OPENJPEG_LIBRARY_PROPERTIES})
|
||||
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1
|
||||
|
||||
int w = tilec->x1 - tilec->x0;
|
||||
|
||||
h.mem = opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int));
|
||||
h.mem = (int *)opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int));
|
||||
v.mem = h.mem;
|
||||
|
||||
while( --numres) {
|
||||
@@ -570,7 +570,7 @@ static void v4dwt_interleave_h(v4dwt_t* restrict w, float* restrict a, int x, in
|
||||
int count = w->sn;
|
||||
int i, k;
|
||||
for(k = 0; k < 2; ++k){
|
||||
if (count + 3 * x < size && ((int) a & 0x0f) == 0 && ((int) bi & 0x0f) == 0 && (x & 0x0f) == 0) {
|
||||
if (count + 3 * x < size && ((long) a & 0x0f) == 0 && ((long) bi & 0x0f) == 0 && (x & 0x0f) == 0) {
|
||||
/* Fast code path */
|
||||
for(i = 0; i < count; ++i){
|
||||
int j = i;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Herv<EFBFBD> Drolon, FreeImage Team
|
||||
* Copyright (c) 2005, Hervé Drolon, FreeImage Team
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -26,41 +26,6 @@
|
||||
|
||||
#include "opj_includes.h"
|
||||
|
||||
/* ==========================================================
|
||||
Utility functions
|
||||
==========================================================*/
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
||||
static char*
|
||||
i2a(unsigned i, char *a, unsigned r) {
|
||||
if (i/r > 0) a = i2a(i/r,a,r);
|
||||
*a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r];
|
||||
return a+1;
|
||||
}
|
||||
|
||||
/**
|
||||
Transforms integer i into an ascii string and stores the result in a;
|
||||
string is encoded in the base indicated by r.
|
||||
@param i Number to be converted
|
||||
@param a String result
|
||||
@param r Base of value; must be in the range 2 - 36
|
||||
@return Returns a
|
||||
*/
|
||||
static char *
|
||||
_itoa(int i, char *a, int r) {
|
||||
r = ((r < 2) || (r > 36)) ? 10 : r;
|
||||
if(i < 0) {
|
||||
*a = '-';
|
||||
*i2a(-i, a+1, r) = 0;
|
||||
}
|
||||
else *i2a(i, a, r) = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
#endif /* !WIN32 */
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context) {
|
||||
if(cinfo) {
|
||||
opj_event_mgr_t *previous = cinfo->event_mgr;
|
||||
|
||||
@@ -236,7 +236,7 @@ static void j2k_read_unk(opj_j2k_t *j2k);
|
||||
/* ----------------------------------------------------------------------- */
|
||||
typedef struct j2k_prog_order{
|
||||
OPJ_PROG_ORDER enum_prog;
|
||||
char str_prog[4];
|
||||
char str_prog[5];
|
||||
}j2k_prog_order_t;
|
||||
|
||||
j2k_prog_order_t j2k_prog_order_list[] = {
|
||||
|
||||
@@ -1,163 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2005, Herv<72> Drolon, FreeImage Team
|
||||
* Copyright (c) 2007, Callum Lerwick <seg@haxxed.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __OPJ_MALLOC_H
|
||||
#define __OPJ_MALLOC_H
|
||||
/**
|
||||
@file opj_malloc.h
|
||||
@brief Internal functions
|
||||
|
||||
The functions in opj_malloc.h are internal utilities used for memory management.
|
||||
*/
|
||||
|
||||
/** @defgroup MISC MISC - Miscellaneous internal functions */
|
||||
/*@{*/
|
||||
|
||||
/** @name Exported functions */
|
||||
/*@{*/
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
Allocate an uninitialized memory block
|
||||
@param size Bytes to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_malloc(size_t size);
|
||||
#else
|
||||
#define opj_malloc(size) malloc(size)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocate a memory block with elements initialized to 0
|
||||
@param num Blocks to allocate
|
||||
@param size Bytes per block to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements);
|
||||
#else
|
||||
#define opj_calloc(num, size) calloc(num, size)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocate memory aligned to a 16 byte boundry
|
||||
@param size Bytes to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */
|
||||
#ifdef WIN32
|
||||
/* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */
|
||||
#ifdef __GNUC__
|
||||
#include <mm_malloc.h>
|
||||
#define HAVE_MM_MALLOC
|
||||
#else /* MSVC, Intel C++ */
|
||||
#include <malloc.h>
|
||||
#ifdef _mm_malloc
|
||||
#define HAVE_MM_MALLOC
|
||||
#endif
|
||||
#endif
|
||||
#else /* Not WIN32 */
|
||||
#if defined(__sun)
|
||||
#define HAVE_MEMALIGN
|
||||
/* Linux x86_64 and OSX always align allocations to 16 bytes */
|
||||
#elif !defined(__amd64__) && !defined(__APPLE__)
|
||||
#define HAVE_MEMALIGN
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define opj_aligned_malloc(size) malloc(size)
|
||||
#define opj_aligned_free(m) free(m)
|
||||
|
||||
#ifdef HAVE_MM_MALLOC
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) _mm_malloc(size, 16)
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) _mm_free(m)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMALIGN
|
||||
extern void* memalign(size_t, size_t);
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) memalign(16, (size))
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_MEMALIGN
|
||||
#undef opj_aligned_malloc
|
||||
extern int posix_memalign(void**, size_t, size_t);
|
||||
|
||||
static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){
|
||||
void* mem = NULL;
|
||||
posix_memalign(&mem, 16, size);
|
||||
return mem;
|
||||
}
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) opj_malloc(size)
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) opj_free(m)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Reallocate memory blocks.
|
||||
@param memblock Pointer to previously allocated memory block
|
||||
@param size New size in bytes
|
||||
@return Returns a void pointer to the reallocated (and possibly moved) memory block
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_realloc(void * _Memory, size_t NewSize);
|
||||
#else
|
||||
#define opj_realloc(m, s) realloc(m, s)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Deallocates or frees a memory block.
|
||||
@param memblock Previously allocated memory block to be freed
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void OPJ_CALLCONV opj_free(void * _Memory);
|
||||
#else
|
||||
#define opj_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC poison malloc calloc realloc free
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/*@}*/
|
||||
|
||||
/*@}*/
|
||||
|
||||
#endif /* __OPJ_MALLOC_H */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, Herv<72> Drolon, FreeImage Team
|
||||
* Copyright (c) 2007, Callum Lerwick <seg@haxxed.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __OPJ_MALLOC_H
|
||||
#define __OPJ_MALLOC_H
|
||||
/**
|
||||
@file opj_malloc.h
|
||||
@brief Internal functions
|
||||
|
||||
The functions in opj_malloc.h are internal utilities used for memory management.
|
||||
*/
|
||||
|
||||
/** @defgroup MISC MISC - Miscellaneous internal functions */
|
||||
/*@{*/
|
||||
|
||||
/** @name Exported functions */
|
||||
/*@{*/
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
Allocate an uninitialized memory block
|
||||
@param size Bytes to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_malloc(size_t size);
|
||||
#else
|
||||
#define opj_malloc(size) malloc(size)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocate a memory block with elements initialized to 0
|
||||
@param num Blocks to allocate
|
||||
@param size Bytes per block to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements);
|
||||
#else
|
||||
#define opj_calloc(num, size) calloc(num, size)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocate memory aligned to a 16 byte boundry
|
||||
@param size Bytes to allocate
|
||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||
*/
|
||||
/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */
|
||||
#ifdef WIN32
|
||||
/* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */
|
||||
#ifdef __GNUC__
|
||||
#include <mm_malloc.h>
|
||||
#define HAVE_MM_MALLOC
|
||||
#else /* MSVC, Intel C++ */
|
||||
#include <malloc.h>
|
||||
#ifdef _mm_malloc
|
||||
#define HAVE_MM_MALLOC
|
||||
#endif
|
||||
#endif
|
||||
#else /* Not WIN32 */
|
||||
#if defined(__sun)
|
||||
#define HAVE_MEMALIGN
|
||||
/* Linux x86_64 and OSX always align allocations to 16 bytes */
|
||||
#elif !defined(__amd64__) && !defined(__APPLE__)
|
||||
#define HAVE_MEMALIGN
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define opj_aligned_malloc(size) malloc(size)
|
||||
#define opj_aligned_free(m) free(m)
|
||||
|
||||
#ifdef HAVE_MM_MALLOC
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) _mm_malloc(size, 16)
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) _mm_free(m)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMALIGN
|
||||
extern void* memalign(size_t, size_t);
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) memalign(16, (size))
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POSIX_MEMALIGN
|
||||
#undef opj_aligned_malloc
|
||||
extern int posix_memalign(void**, size_t, size_t);
|
||||
|
||||
static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){
|
||||
void* mem = NULL;
|
||||
posix_memalign(&mem, 16, size);
|
||||
return mem;
|
||||
}
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
#undef opj_aligned_malloc
|
||||
#define opj_aligned_malloc(size) opj_malloc(size)
|
||||
#undef opj_aligned_free
|
||||
#define opj_aligned_free(m) opj_free(m)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Reallocate memory blocks.
|
||||
@param memblock Pointer to previously allocated memory block
|
||||
@param size New size in bytes
|
||||
@return Returns a void pointer to the reallocated (and possibly moved) memory block
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void * OPJ_CALLCONV opj_realloc(void * _Memory, size_t NewSize);
|
||||
#else
|
||||
#define opj_realloc(m, s) realloc(m, s)
|
||||
#endif
|
||||
|
||||
/**
|
||||
Deallocates or frees a memory block.
|
||||
@param memblock Previously allocated memory block to be freed
|
||||
*/
|
||||
#ifdef ALLOC_PERF_OPT
|
||||
void OPJ_CALLCONV opj_free(void * _Memory);
|
||||
#else
|
||||
#define opj_free(m) free(m)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC poison malloc calloc realloc free
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/*@}*/
|
||||
|
||||
/*@}*/
|
||||
|
||||
#endif /* __OPJ_MALLOC_H */
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ list(APPEND linux_crash_logger_SOURCE_FILES
|
||||
${linux_crash_logger_HEADER_FILES}
|
||||
)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lrt -lapr-1 -Wl,--as-needed")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
|
||||
|
||||
add_executable(linux-crash-logger ${linux_crash_logger_SOURCE_FILES})
|
||||
|
||||
@@ -47,11 +47,18 @@ target_link_libraries(linux-crash-logger
|
||||
${LLVFS_LIBRARIES}
|
||||
${LLXML_LIBRARIES}
|
||||
${LLMESSAGE_LIBRARIES}
|
||||
${LLUI_LIBRARIES}
|
||||
${LLVFS_LIBRARIES}
|
||||
${LLMATH_LIBRARIES}
|
||||
${LLCOMMON_LIBRARIES}
|
||||
${UI_LIBRARIES}
|
||||
${DB_LIBRARIES}
|
||||
${XMLRPCEPI_LIBRARIES}
|
||||
${CURL_LIBRARIES}
|
||||
${APR_LIBRARIES}
|
||||
${APRUTIL_LIBRARIES}
|
||||
${CRYPTO_LIBRARIES}
|
||||
rt
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
|
||||
@@ -5,16 +5,30 @@ project(llaudio)
|
||||
include(00-Common)
|
||||
include(Audio)
|
||||
include(LLAudio)
|
||||
include(FMOD)
|
||||
if(FMODEX)
|
||||
include(FMODEX)
|
||||
if(FMODEX)
|
||||
set(FMOD OFF)
|
||||
endif(FMODEX)
|
||||
endif(FMODEX)
|
||||
if(NOT FMODEX)
|
||||
include(FMOD)
|
||||
endif(NOT FMODEX)
|
||||
include(OPENAL)
|
||||
include(LLCommon)
|
||||
include(LLMath)
|
||||
include(LLMessage)
|
||||
include(LLVFS)
|
||||
|
||||
if(FMODEX)
|
||||
include_directories(${FMODEX_INCLUDE_DIR})
|
||||
endif(FMODEX)
|
||||
if(FMOD)
|
||||
include_directories(${FMOD_INCLUDE_DIR})
|
||||
endif(FMOD)
|
||||
|
||||
include_directories(
|
||||
${LLAUDIO_INCLUDE_DIRS}
|
||||
${FMOD_INCLUDE_DIR}
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
${LLMATH_INCLUDE_DIRS}
|
||||
${LLMESSAGE_INCLUDE_DIRS}
|
||||
@@ -46,6 +60,19 @@ set(llaudio_HEADER_FILES
|
||||
llwindgen.h
|
||||
)
|
||||
|
||||
if (FMODEX)
|
||||
list(APPEND llaudio_SOURCE_FILES
|
||||
llaudioengine_fmodex.cpp
|
||||
lllistener_fmodex.cpp
|
||||
llstreamingaudio_fmodex.cpp
|
||||
)
|
||||
|
||||
list(APPEND llaudio_HEADER_FILES
|
||||
llaudioengine_fmodex.h
|
||||
lllistener_fmodex.h
|
||||
llstreamingaudio_fmodex.h
|
||||
)
|
||||
endif (FMODEX)
|
||||
if (FMOD)
|
||||
list(APPEND llaudio_SOURCE_FILES
|
||||
llaudioengine_fmod.cpp
|
||||
|
||||
782
indra/llaudio/llaudioengine_fmodex.cpp
Normal file
782
indra/llaudio/llaudioengine_fmodex.cpp
Normal file
@@ -0,0 +1,782 @@
|
||||
/**
|
||||
* @file audioengine_FMODEX.cpp
|
||||
* @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llstreamingaudio.h"
|
||||
#include "llstreamingaudio_fmodex.h"
|
||||
|
||||
#include "llaudioengine_fmodex.h"
|
||||
#include "lllistener_fmodex.h"
|
||||
|
||||
#include "llerror.h"
|
||||
#include "llmath.h"
|
||||
#include "llrand.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_errors.h"
|
||||
#include "lldir.h"
|
||||
#include "llapr.h"
|
||||
|
||||
#include "sound_ids.h"
|
||||
|
||||
#if LL_WINDOWS //Some ugly code to make missing fmodex.dll not cause a fatal error.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "windows.h"
|
||||
#include <DelayImp.h>
|
||||
#pragma comment(lib, "delayimp.lib")
|
||||
|
||||
bool attemptDelayLoad()
|
||||
{
|
||||
__try
|
||||
{
|
||||
if( FAILED( __HrLoadAllImportsForDll( "fmodex.dll" ) ) )
|
||||
return false;
|
||||
}
|
||||
__except( EXCEPTION_EXECUTE_HANDLER )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
|
||||
LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler)
|
||||
{
|
||||
mInited = false;
|
||||
mWindGen = NULL;
|
||||
mWindDSP = NULL;
|
||||
mSystem = NULL;
|
||||
mEnableProfiler = enable_profiler;
|
||||
}
|
||||
|
||||
|
||||
LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
|
||||
{
|
||||
if(result == FMOD_OK)
|
||||
return false;
|
||||
llwarns << string << " Error: " << FMOD_ErrorString(result) << llendl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
|
||||
{
|
||||
|
||||
#if LL_WINDOWS
|
||||
if(!attemptDelayLoad())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
U32 version;
|
||||
FMOD_RESULT result;
|
||||
int numdrivers;
|
||||
FMOD_SPEAKERMODE speakermode;
|
||||
FMOD_CAPS caps;
|
||||
char name[256];
|
||||
|
||||
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL;
|
||||
|
||||
result = FMOD::System_Create(&mSystem);
|
||||
if(Check_FMOD_Error(result, "FMOD::System_Create"))
|
||||
return false;
|
||||
|
||||
//will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer.
|
||||
LLAudioEngine::init(num_channels, userdata);
|
||||
|
||||
result = mSystem->getVersion(&version);
|
||||
Check_FMOD_Error(result, "FMOD::System::getVersion");
|
||||
|
||||
if (version < FMOD_VERSION)
|
||||
{
|
||||
LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version
|
||||
<< ")! You should be using FMOD " << FMOD_VERSION << LL_ENDL;
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
//Is this block applicable to linux?
|
||||
{
|
||||
result = mSystem->getNumDrivers(&numdrivers);
|
||||
Check_FMOD_Error(result, "FMOD::System::getNumDrivers");
|
||||
if (numdrivers == 0)
|
||||
{
|
||||
result = mSystem->setOutput(FMOD_OUTPUTTYPE_NOSOUND);
|
||||
Check_FMOD_Error(result, "FMOD::System::setOutput");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = mSystem->getDriverCaps(0, &caps, 0, &speakermode);
|
||||
Check_FMOD_Error(result,"FMOD::System::getDriverCaps");
|
||||
/*
|
||||
Set the user selected speaker mode.
|
||||
*/
|
||||
result = mSystem->setSpeakerMode(speakermode);
|
||||
Check_FMOD_Error(result, "FMOD::System::setSpeakerMode");
|
||||
if (caps & FMOD_CAPS_HARDWARE_EMULATED)
|
||||
{
|
||||
/*
|
||||
The user has the 'Acceleration' slider set to off! This is really bad
|
||||
for latency! You might want to warn the user about this.
|
||||
*/
|
||||
result = mSystem->setDSPBufferSize(1024, 10);
|
||||
Check_FMOD_Error(result, "FMOD::System::setDSPBufferSize");
|
||||
}
|
||||
result = mSystem->getDriverInfo(0, name, 256, 0);
|
||||
Check_FMOD_Error(result, "FMOD::System::getDriverInfo");
|
||||
|
||||
if (strstr(name, "SigmaTel"))
|
||||
{
|
||||
/*
|
||||
Sigmatel sound devices crackle for some reason if the format is PCM 16bit.
|
||||
PCM floating point output seems to solve it.
|
||||
*/
|
||||
result = mSystem->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0,0, FMOD_DSP_RESAMPLER_LINEAR);
|
||||
Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //LL_WINDOWS
|
||||
|
||||
// In this case, all sounds, PLUS wind and stream will be software.
|
||||
result = mSystem->setSoftwareChannels(num_channels+2);
|
||||
Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels");
|
||||
|
||||
U32 fmod_flags = FMOD_INIT_NORMAL;
|
||||
if(mEnableProfiler)
|
||||
fmod_flags |= FMOD_INIT_ENABLE_PROFILE;
|
||||
|
||||
#if LL_LINUX
|
||||
// If we don't set an output method, Linux FMOD always
|
||||
// decides on OSS and fails otherwise. So we'll manually
|
||||
// try ESD, then OSS, then ALSA.
|
||||
// Why this order? See SL-13250, but in short, OSS emulated
|
||||
// on top of ALSA is ironically more reliable than raw ALSA.
|
||||
// Ack, and ESD has more reliable failure modes - but has worse
|
||||
// latency - than all of them, so wins for now.
|
||||
bool audio_ok = false;
|
||||
|
||||
if (!audio_ok)
|
||||
{
|
||||
if (NULL == getenv("LL_BAD_FMODEX_ESD")) /*Flawfinder: ignore*/
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL;
|
||||
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_ESD) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "ESD audio output FAILED to initialize");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ESD audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
if (NULL == getenv("LL_BAD_FMODEX_OSS")) /*Flawfinder: ignore*/
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL;
|
||||
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_OSS) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "OSS audio output FAILED to initialize" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
if (NULL == getenv("LL_BAD_FMODEX_ALSA")) /*Flawfinder: ignore*/
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
|
||||
if(mSystem->SetOutput(FMOD_OUTPUTTYPE_ALSA) &&
|
||||
(result = mSystem->init(num_channels, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "ALSA audio output FAILED to initialize");
|
||||
}
|
||||
} else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// On Linux, FMOD causes a SIGPIPE for some netstream error
|
||||
// conditions (an FMOD bug); ignore SIGPIPE so it doesn't crash us.
|
||||
// NOW FIXED in FMOD 3.x since 2006-10-01.
|
||||
//signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
// We're interested in logging which output method we
|
||||
// ended up with, for QA purposes.
|
||||
FMOD_OUTPUTTYPE output_type;
|
||||
mSystem->getOutput(output_type);
|
||||
switch (output_type)
|
||||
{
|
||||
case FSOUND_OUTPUT_NOSOUND:
|
||||
LL_DEBUGS("AppInit") << "Audio output: NoSound" << LL_ENDL; break;
|
||||
case FSOUND_OUTPUT_OSS:
|
||||
LL_DEBUGS("AppInit") << "Audio output: OSS" << LL_ENDL; break;
|
||||
case FSOUND_OUTPUT_ESD:
|
||||
LL_DEBUGS("AppInit") << "Audio output: ESD" << LL_ENDL; break;
|
||||
case FSOUND_OUTPUT_ALSA:
|
||||
LL_DEBUGS("AppInit") << "Audio output: ALSA" << LL_ENDL; break;
|
||||
default:
|
||||
LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
|
||||
};
|
||||
#else // LL_LINUX
|
||||
|
||||
// initialize the FMOD engine
|
||||
result = mSystem->init( num_channels + 2, fmod_flags, 0);
|
||||
if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
|
||||
{
|
||||
/*
|
||||
Ok, the speaker mode selected isn't supported by this soundcard. Switch it
|
||||
back to stereo...
|
||||
*/
|
||||
result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
|
||||
Check_FMOD_Error(result,"Error falling back to stereo mode");
|
||||
/*
|
||||
... and re-init.
|
||||
*/
|
||||
result = mSystem->init(100, FMOD_INIT_NORMAL, 0);
|
||||
}
|
||||
if(Check_FMOD_Error(result, "Error initializing FMOD"))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
||||
if (!getStreamingAudioImpl()) // no existing implementation added
|
||||
setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem));
|
||||
|
||||
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD initialized correctly" << LL_ENDL;
|
||||
|
||||
mInited = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::string LLAudioEngine_FMODEX::getDriverName(bool verbose)
|
||||
{
|
||||
llassert_always(mSystem);
|
||||
if (verbose)
|
||||
{
|
||||
U32 version;
|
||||
if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion"))
|
||||
{
|
||||
return llformat("FMOD version %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF);
|
||||
}
|
||||
}
|
||||
return "FMOD";
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODEX::allocateListener(void)
|
||||
{
|
||||
mListenerp = (LLListener *) new LLListener_FMODEX(mSystem);
|
||||
if (!mListenerp)
|
||||
{
|
||||
llwarns << "Listener creation failed" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODEX::shutdown()
|
||||
{
|
||||
stopInternetStream();
|
||||
|
||||
LLAudioEngine::shutdown();
|
||||
|
||||
llinfos << "LLAudioEngine_FMODEX::shutdown() closing FMOD" << llendl;
|
||||
mSystem->close();
|
||||
mSystem->release();
|
||||
llinfos << "LLAudioEngine_FMODEX::shutdown() done closing FMOD" << llendl;
|
||||
|
||||
delete mListenerp;
|
||||
mListenerp = NULL;
|
||||
}
|
||||
|
||||
|
||||
LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer()
|
||||
{
|
||||
return new LLAudioBufferFMODEX(mSystem);
|
||||
}
|
||||
|
||||
|
||||
LLAudioChannel * LLAudioEngine_FMODEX::createChannel()
|
||||
{
|
||||
return new LLAudioChannelFMODEX(mSystem);
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODEX::initWind()
|
||||
{
|
||||
mNextWindUpdate = 0.0;
|
||||
|
||||
if (!mWindDSP)
|
||||
{
|
||||
FMOD_DSP_DESCRIPTION dspdesc;
|
||||
memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero
|
||||
strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit"
|
||||
dspdesc.read = &windCallback; //Assign callback.
|
||||
if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP"))
|
||||
return false;
|
||||
|
||||
if(mWindGen)
|
||||
delete mWindGen;
|
||||
|
||||
float frequency = 44100;
|
||||
mWindDSP->getDefaults(&frequency,0,0,0);
|
||||
mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency);
|
||||
mWindDSP->setUserData((void*)mWindGen);
|
||||
}
|
||||
|
||||
if (mWindDSP)
|
||||
{
|
||||
mSystem->playDSP(FMOD_CHANNEL_FREE, mWindDSP, false, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODEX::cleanupWind()
|
||||
{
|
||||
if (mWindDSP)
|
||||
{
|
||||
mWindDSP->remove();
|
||||
mWindDSP->release();
|
||||
mWindDSP = NULL;
|
||||
}
|
||||
|
||||
delete mWindGen;
|
||||
mWindGen = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLAudioEngine_FMODEX::updateWind(LLVector3 wind_vec, F32 camera_height_above_water)
|
||||
{
|
||||
LLVector3 wind_pos;
|
||||
F64 pitch;
|
||||
F64 center_freq;
|
||||
|
||||
if (!mEnableWind)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
|
||||
{
|
||||
|
||||
// wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
|
||||
// need to convert this to the conventional orientation DS3D and OpenAL use
|
||||
// where +X = right, +Y = up, +Z = backwards
|
||||
|
||||
wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
|
||||
|
||||
// cerr << "Wind update" << endl;
|
||||
|
||||
pitch = 1.0 + mapWindVecToPitch(wind_vec);
|
||||
center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0));
|
||||
|
||||
mWindGen->mTargetFreq = (F32)center_freq;
|
||||
mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
|
||||
mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLAudioEngine_FMODEX::setInternalGain(F32 gain)
|
||||
{
|
||||
if (!mInited)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gain = llclamp( gain, 0.0f, 1.0f );
|
||||
|
||||
FMOD::ChannelGroup *master_group;
|
||||
mSystem->getMasterChannelGroup(&master_group);
|
||||
|
||||
master_group->setVolume(gain);
|
||||
|
||||
LLStreamingAudioInterface *saimpl = getStreamingAudioImpl();
|
||||
if ( saimpl )
|
||||
{
|
||||
// fmod likes its streaming audio channel gain re-asserted after
|
||||
// master volume change.
|
||||
saimpl->setGain(saimpl->getGain());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLAudioChannelFMODEX implementation
|
||||
//
|
||||
|
||||
LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioChannelFMODEX::~LLAudioChannelFMODEX()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
bool LLAudioChannelFMODEX::updateBuffer()
|
||||
{
|
||||
if (LLAudioChannel::updateBuffer())
|
||||
{
|
||||
// Base class update returned true, which means that we need to actually
|
||||
// set up the channel for a different buffer.
|
||||
|
||||
LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentSourcep->getCurrentBuffer();
|
||||
|
||||
// Grab the FMOD sample associated with the buffer
|
||||
FMOD::Sound *soundp = bufferp->getSound();
|
||||
if (!soundp)
|
||||
{
|
||||
// This is bad, there should ALWAYS be a sound associated with a legit
|
||||
// buffer.
|
||||
llerrs << "No FMOD sound!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Actually play the sound. Start it off paused so we can do all the necessary
|
||||
// setup.
|
||||
if(!mChannelp)
|
||||
{
|
||||
FMOD_RESULT result = getSystem()->playSound(FMOD_CHANNEL_FREE, soundp, true, &mChannelp);
|
||||
Check_FMOD_Error(result, "FMOD::System::playSound");
|
||||
}
|
||||
|
||||
//llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl;
|
||||
}
|
||||
|
||||
// If we have a source for the channel, we need to update its gain.
|
||||
if (mCurrentSourcep)
|
||||
{
|
||||
// SJB: warnings can spam and hurt framerate, disabling
|
||||
FMOD_RESULT result;
|
||||
|
||||
result = mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain());
|
||||
//Check_FMOD_Error(result, "FMOD::Channel::setVolume");
|
||||
|
||||
result = mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
|
||||
/*if(Check_FMOD_Error(result, "FMOD::Channel::setMode"))
|
||||
{
|
||||
S32 index;
|
||||
mChannelp->getIndex(&index);
|
||||
llwarns << "Channel " << index << "Source ID: " << mCurrentSourcep->getID()
|
||||
<< " at " << mCurrentSourcep->getPositionGlobal() << llendl;
|
||||
}*/
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::update3DPosition()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
// We're not actually a live channel (i.e., we're not playing back anything)
|
||||
return;
|
||||
}
|
||||
|
||||
LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentBufferp;
|
||||
if (!bufferp)
|
||||
{
|
||||
// We don't have a buffer associated with us (should really have been picked up
|
||||
// by the above if.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentSourcep->isAmbient())
|
||||
{
|
||||
// Ambient sound, don't need to do any positional updates.
|
||||
set3DMode(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Localized sound. Update the position and velocity of the sound.
|
||||
set3DMode(true);
|
||||
|
||||
LLVector3 float_pos;
|
||||
float_pos.setVec(mCurrentSourcep->getPositionGlobal());
|
||||
FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV);
|
||||
Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::updateLoop()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
// May want to clear up the loop/sample counters.
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Hack: We keep track of whether we looped or not by seeing when the
|
||||
// sample position looks like it's going backwards. Not reliable; may
|
||||
// yield false negatives.
|
||||
//
|
||||
U32 cur_pos;
|
||||
mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES);
|
||||
|
||||
if (cur_pos < (U32)mLastSamplePos)
|
||||
{
|
||||
mLoopedThisFrame = true;
|
||||
}
|
||||
mLastSamplePos = cur_pos;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::cleanup()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
//llinfos << "Aborting cleanup with no channel handle." << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
//llinfos << "Cleaning up channel: " << mChannelID << llendl;
|
||||
Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop");
|
||||
|
||||
mCurrentBufferp = NULL;
|
||||
mChannelp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::play()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
llwarns << "Playing without a channel handle, aborting" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause");
|
||||
|
||||
getSource()->setPlayedOnce(true);
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp)
|
||||
{
|
||||
LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)channelp;
|
||||
if (!(fmod_channelp->mChannelp && mChannelp))
|
||||
{
|
||||
// Don't have channels allocated to both the master and the slave
|
||||
return;
|
||||
}
|
||||
|
||||
U32 cur_pos;
|
||||
if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position"))
|
||||
return;
|
||||
|
||||
cur_pos %= mCurrentBufferp->getLength();
|
||||
|
||||
// Try to match the position of our sync master
|
||||
Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position");
|
||||
|
||||
// Start us playing
|
||||
play();
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioChannelFMODEX::isPlaying()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool paused, playing;
|
||||
mChannelp->getPaused(&paused);
|
||||
mChannelp->isPlaying(&playing);
|
||||
return !paused && playing;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLAudioChannelFMODEX implementation
|
||||
//
|
||||
|
||||
|
||||
LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : mSystemp(system), mSoundp(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioBufferFMODEX::~LLAudioBufferFMODEX()
|
||||
{
|
||||
if(mSoundp)
|
||||
{
|
||||
mSoundp->release();
|
||||
mSoundp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioBufferFMODEX::loadWAV(const std::string& filename)
|
||||
{
|
||||
// Try to open a wav file from disk. This will eventually go away, as we don't
|
||||
// really want to block doing this.
|
||||
if (filename.empty())
|
||||
{
|
||||
// invalid filename, abort.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LLAPRFile::isExist(filename, LL_APR_RPB))
|
||||
{
|
||||
// File not found, abort.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSoundp)
|
||||
{
|
||||
// If there's already something loaded in this buffer, clean it up.
|
||||
mSoundp->release();
|
||||
mSoundp = NULL;
|
||||
}
|
||||
|
||||
FMOD_MODE base_mode = FMOD_LOOP_NORMAL | FMOD_SOFTWARE;
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
memset(&exinfo,0,sizeof(exinfo));
|
||||
exinfo.cbsize = sizeof(exinfo);
|
||||
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading.
|
||||
// Load up the wav file into an fmod sample
|
||||
#if LL_WINDOWS
|
||||
FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode | FMOD_UNICODE, &exinfo, &mSoundp);
|
||||
#else
|
||||
FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp);
|
||||
#endif
|
||||
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
// We failed to load the file for some reason.
|
||||
llwarns << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << llendl;
|
||||
|
||||
//
|
||||
// If we EVER want to load wav files provided by end users, we need
|
||||
// to rethink this!
|
||||
//
|
||||
// file is probably corrupt - remove it.
|
||||
LLFile::remove(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everything went well, return true
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
U32 LLAudioBufferFMODEX::getLength()
|
||||
{
|
||||
if (!mSoundp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
U32 length;
|
||||
mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODEX::set3DMode(bool use3d)
|
||||
{
|
||||
FMOD_MODE current_mode;
|
||||
if(mChannelp->getMode(¤t_mode) != FMOD_OK)
|
||||
return;
|
||||
FMOD_MODE new_mode = current_mode;
|
||||
new_mode &= ~(use3d ? FMOD_2D : FMOD_3D);
|
||||
new_mode |= use3d ? FMOD_3D : FMOD_2D;
|
||||
|
||||
if(current_mode != new_mode)
|
||||
{
|
||||
mChannelp->setMode(new_mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels)
|
||||
{
|
||||
// originalbuffer = fmod's original mixbuffer.
|
||||
// newbuffer = the buffer passed from the previous DSP unit.
|
||||
// length = length in samples at this mix time.
|
||||
// userdata = user parameter passed through in FSOUND_DSP_Create.
|
||||
|
||||
LLWindGen<LLAudioEngine_FMODEX::MIXBUFFERFORMAT> *windgen;
|
||||
FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;
|
||||
|
||||
thisdsp->getUserData((void **)&windgen);
|
||||
S32 channels, configwidth, configheight;
|
||||
thisdsp->getInfo(0, 0, &channels, &configwidth, &configheight);
|
||||
|
||||
windgen->windGenerate((LLAudioEngine_FMODEX::MIXBUFFERFORMAT *)newbuffer, length);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
131
indra/llaudio/llaudioengine_fmodex.h
Normal file
131
indra/llaudio/llaudioengine_fmodex.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file audioengine_FMODEX.h
|
||||
* @brief Definition of LLAudioEngine class abstracting the audio
|
||||
* support as a FMOD 3D implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_AUDIOENGINE_FMODEX_H
|
||||
#define LL_AUDIOENGINE_FMODEX_H
|
||||
|
||||
#include "llaudioengine.h"
|
||||
#include "lllistener_fmod.h"
|
||||
#include "llwindgen.h"
|
||||
|
||||
//Stubs
|
||||
class LLAudioStreamManagerFMODEX;
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
class Channel;
|
||||
class Sound;
|
||||
class DSP;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLAudioEngine_FMODEX : public LLAudioEngine
|
||||
{
|
||||
public:
|
||||
LLAudioEngine_FMODEX(bool enable_profiler);
|
||||
virtual ~LLAudioEngine_FMODEX();
|
||||
|
||||
// initialization/startup/shutdown
|
||||
virtual bool init(const S32 num_channels, void *user_data);
|
||||
virtual std::string getDriverName(bool verbose);
|
||||
virtual void allocateListener();
|
||||
|
||||
virtual void shutdown();
|
||||
|
||||
/*virtual*/ bool initWind();
|
||||
/*virtual*/ void cleanupWind();
|
||||
|
||||
/*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water);
|
||||
|
||||
typedef F32 MIXBUFFERFORMAT;
|
||||
|
||||
FMOD::System *getSystem() const {return mSystem;}
|
||||
protected:
|
||||
/*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to.
|
||||
/*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel.
|
||||
|
||||
/*virtual*/ void setInternalGain(F32 gain);
|
||||
|
||||
bool mInited;
|
||||
|
||||
LLWindGen<MIXBUFFERFORMAT> *mWindGen;
|
||||
|
||||
FMOD::DSP *mWindDSP;
|
||||
FMOD::System *mSystem;
|
||||
bool mEnableProfiler;
|
||||
};
|
||||
|
||||
|
||||
class LLAudioChannelFMODEX : public LLAudioChannel
|
||||
{
|
||||
public:
|
||||
LLAudioChannelFMODEX(FMOD::System *audioengine);
|
||||
virtual ~LLAudioChannelFMODEX();
|
||||
|
||||
protected:
|
||||
/*virtual*/ void play();
|
||||
/*virtual*/ void playSynced(LLAudioChannel *channelp);
|
||||
/*virtual*/ void cleanup();
|
||||
/*virtual*/ bool isPlaying();
|
||||
|
||||
/*virtual*/ bool updateBuffer();
|
||||
/*virtual*/ void update3DPosition();
|
||||
/*virtual*/ void updateLoop();
|
||||
|
||||
void set3DMode(bool use3d);
|
||||
protected:
|
||||
FMOD::System *getSystem() const {return mSystemp;}
|
||||
FMOD::System *mSystemp;
|
||||
FMOD::Channel *mChannelp;
|
||||
S32 mLastSamplePos;
|
||||
};
|
||||
|
||||
|
||||
class LLAudioBufferFMODEX : public LLAudioBuffer
|
||||
{
|
||||
public:
|
||||
LLAudioBufferFMODEX(FMOD::System *audioengine);
|
||||
virtual ~LLAudioBufferFMODEX();
|
||||
|
||||
/*virtual*/ bool loadWAV(const std::string& filename);
|
||||
/*virtual*/ U32 getLength();
|
||||
friend class LLAudioChannelFMODEX;
|
||||
protected:
|
||||
FMOD::System *getSystem() const {return mSystemp;}
|
||||
FMOD::System *mSystemp;
|
||||
FMOD::Sound *getSound() const{ return mSoundp; }
|
||||
FMOD::Sound *mSoundp;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_AUDIOENGINE_FMODEX_H
|
||||
132
indra/llaudio/lllistener_fmodex.cpp
Normal file
132
indra/llaudio/lllistener_fmodex.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @file listener_fmod.cpp
|
||||
* @brief implementation of LISTENER class abstracting the audio
|
||||
* support as a FMOD 3D implementation (windows only)
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llaudioengine.h"
|
||||
#include "lllistener_fmodex.h"
|
||||
#include "fmod.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// constructor
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system)
|
||||
{
|
||||
mSystem = system;
|
||||
init();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODEX::~LLListener_FMODEX()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::init(void)
|
||||
{
|
||||
// do inherited
|
||||
LLListener::init();
|
||||
mDopplerFactor = 1.0f;
|
||||
mRolloffFactor = 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::translate(LLVector3 offset)
|
||||
{
|
||||
LLListener::translate(offset);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::setPosition(LLVector3 pos)
|
||||
{
|
||||
LLListener::setPosition(pos);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::setVelocity(LLVector3 vel)
|
||||
{
|
||||
LLListener::setVelocity(vel);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at)
|
||||
{
|
||||
LLListener::orient(up, at);
|
||||
|
||||
// Welcome to the transition between right and left
|
||||
// (coordinate systems, that is)
|
||||
// Leaving the at vector alone results in a L/R reversal
|
||||
// since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed
|
||||
at = -at;
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::commitDeferredChanges()
|
||||
{
|
||||
mSystem->update();
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODEX::setRolloffFactor(F32 factor)
|
||||
{
|
||||
mRolloffFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODEX::getRolloffFactor()
|
||||
{
|
||||
return mRolloffFactor;
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODEX::setDopplerFactor(F32 factor)
|
||||
{
|
||||
mDopplerFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODEX::getDopplerFactor()
|
||||
{
|
||||
return mDopplerFactor;
|
||||
}
|
||||
|
||||
|
||||
71
indra/llaudio/lllistener_fmodex.h
Normal file
71
indra/llaudio/lllistener_fmodex.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @file listener_fmod.h
|
||||
* @brief Description of LISTENER class abstracting the audio support
|
||||
* as an FMOD 3D implementation (windows and Linux)
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LISTENER_FMODEX_H
|
||||
#define LL_LISTENER_FMODEX_H
|
||||
|
||||
#include "lllistener.h"
|
||||
|
||||
//Stubs
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLListener_FMODEX : public LLListener
|
||||
{
|
||||
public:
|
||||
LLListener_FMODEX(FMOD::System *system);
|
||||
virtual ~LLListener_FMODEX();
|
||||
virtual void init();
|
||||
|
||||
virtual void translate(LLVector3 offset);
|
||||
virtual void setPosition(LLVector3 pos);
|
||||
virtual void setVelocity(LLVector3 vel);
|
||||
virtual void orient(LLVector3 up, LLVector3 at);
|
||||
virtual void commitDeferredChanges();
|
||||
|
||||
virtual void setDopplerFactor(F32 factor);
|
||||
virtual F32 getDopplerFactor();
|
||||
virtual void setRolloffFactor(F32 factor);
|
||||
virtual F32 getRolloffFactor();
|
||||
protected:
|
||||
FMOD::System *mSystem;
|
||||
F32 mDopplerFactor;
|
||||
F32 mRolloffFactor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#include "stdtypes.h" // from llcommon
|
||||
|
||||
class LLSD;
|
||||
|
||||
// Entirely abstract. Based exactly on the historic API.
|
||||
class LLStreamingAudioInterface
|
||||
{
|
||||
@@ -51,6 +53,11 @@ class LLStreamingAudioInterface
|
||||
virtual void setGain(F32 vol) = 0;
|
||||
virtual F32 getGain() = 0;
|
||||
virtual std::string getURL() = 0;
|
||||
|
||||
virtual bool supportsMetaData() = 0;
|
||||
virtual const LLSD *getMetaData() = 0;
|
||||
virtual bool supportsWaveData() = 0;
|
||||
virtual bool getWaveData(float* arr, S32 count, S32 stride = 1) = 0;
|
||||
};
|
||||
|
||||
#endif // LL_STREAMINGAUDIO_H
|
||||
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
const std::string& getURL() { return mInternetStreamURL; }
|
||||
|
||||
int getOpenState();
|
||||
|
||||
FSOUND_STREAM* getStream() { return mInternetStream; }
|
||||
protected:
|
||||
FSOUND_STREAM* mInternetStream;
|
||||
bool mReady;
|
||||
@@ -66,7 +68,8 @@ protected:
|
||||
LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() :
|
||||
mCurrentInternetStreamp(NULL),
|
||||
mFMODInternetStreamChannel(-1),
|
||||
mGain(1.0f)
|
||||
mGain(1.0f),
|
||||
mMetaData(NULL)
|
||||
{
|
||||
// Number of milliseconds of audio to buffer for the audio card.
|
||||
// Must be larger than the usual Second Life frame stutter time.
|
||||
@@ -87,6 +90,17 @@ LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD()
|
||||
// nothing interesting/safe to do.
|
||||
}
|
||||
|
||||
signed char F_CALLBACKAPI MetaDataCallback(char *name, char *value, void *userdata)
|
||||
{
|
||||
std::string szName(name);
|
||||
if(szName == "TITLE" || szName=="TIT2" || szName=="Title")
|
||||
(*(LLSD*)userdata)["TITLE"] = value;
|
||||
if(szName == "ARTIST" || szName=="TPE1" || szName =="WM/AlbumTitle")
|
||||
(*(LLSD*)userdata)["ARTIST"] = value;
|
||||
else
|
||||
(*(LLSD*)userdata)[std::string(name)] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMOD::start(const std::string& url)
|
||||
{
|
||||
@@ -104,6 +118,10 @@ void LLStreamingAudio_FMOD::start(const std::string& url)
|
||||
llinfos << "Starting internet stream: " << url << llendl;
|
||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url);
|
||||
mURL = url;
|
||||
if(mCurrentInternetStreamp->getStream())
|
||||
{
|
||||
mMetaData = new LLSD;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -154,6 +172,10 @@ void LLStreamingAudio_FMOD::update()
|
||||
// Reset volume to previously set volume
|
||||
setGain(getGain());
|
||||
FSOUND_SetPaused(mFMODInternetStreamChannel, false);
|
||||
if(mCurrentInternetStreamp->getStream() && mMetaData)
|
||||
{
|
||||
FSOUND_Stream_Net_SetMetadataCallback(mCurrentInternetStreamp->getStream(),&MetaDataCallback, mMetaData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,11 +206,17 @@ void LLStreamingAudio_FMOD::update()
|
||||
// buffering
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMOD::stop()
|
||||
{
|
||||
if(mMetaData)
|
||||
{
|
||||
if(mCurrentInternetStreamp && mCurrentInternetStreamp->getStream())
|
||||
FSOUND_Stream_Net_SetMetadataCallback(mCurrentInternetStreamp->getStream(),NULL,NULL);
|
||||
delete mMetaData;
|
||||
mMetaData = NULL;
|
||||
}
|
||||
if (mFMODInternetStreamChannel != -1)
|
||||
{
|
||||
FSOUND_SetPaused(mFMODInternetStreamChannel, true);
|
||||
|
||||
@@ -55,6 +55,10 @@ class LLStreamingAudio_FMOD : public LLStreamingAudioInterface
|
||||
/*virtual*/ F32 getGain();
|
||||
/*virtual*/ std::string getURL();
|
||||
|
||||
/*virtual*/ bool supportsMetaData(){return true;}
|
||||
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
|
||||
/*virtual*/ bool supportsWaveData(){return false;}
|
||||
/*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1){return false;}
|
||||
private:
|
||||
LLAudioStreamManagerFMOD *mCurrentInternetStreamp;
|
||||
int mFMODInternetStreamChannel;
|
||||
@@ -62,6 +66,8 @@ private:
|
||||
|
||||
std::string mURL;
|
||||
F32 mGain;
|
||||
|
||||
LLSD *mMetaData;
|
||||
};
|
||||
|
||||
|
||||
|
||||
448
indra/llaudio/llstreamingaudio_fmodex.cpp
Normal file
448
indra/llaudio/llstreamingaudio_fmodex.cpp
Normal file
@@ -0,0 +1,448 @@
|
||||
/**
|
||||
* @file streamingaudio_fmod.cpp
|
||||
* @brief LLStreamingAudio_FMODEX implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llmath.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_errors.h"
|
||||
|
||||
#include "llstreamingaudio_fmodex.h"
|
||||
|
||||
|
||||
class LLAudioStreamManagerFMODEX
|
||||
{
|
||||
public:
|
||||
LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url);
|
||||
FMOD::Channel* startStream();
|
||||
bool stopStream(); // Returns true if the stream was successfully stopped.
|
||||
bool ready();
|
||||
|
||||
const std::string& getURL() { return mInternetStreamURL; }
|
||||
|
||||
FMOD_OPENSTATE getOpenState();
|
||||
protected:
|
||||
FMOD::System* mSystem;
|
||||
FMOD::Channel* mStreamChannel;
|
||||
FMOD::Sound* mInternetStream;
|
||||
bool mReady;
|
||||
|
||||
std::string mInternetStreamURL;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Internet Streaming
|
||||
//---------------------------------------------------------------------------
|
||||
LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) :
|
||||
mSystem(system),
|
||||
mCurrentInternetStreamp(NULL),
|
||||
mFMODInternetStreamChannelp(NULL),
|
||||
mGain(1.0f),
|
||||
mMetaData(NULL)
|
||||
{
|
||||
// Number of milliseconds of audio to buffer for the audio card.
|
||||
// Must be larger than the usual Second Life frame stutter time.
|
||||
mSystem->setStreamBufferSize(200, FMOD_TIMEUNIT_MS);
|
||||
|
||||
// Here's where we set the size of the network buffer and some buffering
|
||||
// parameters. In this case we want a network buffer of 16k, we want it
|
||||
// to prebuffer 40% of that when we first connect, and we want it
|
||||
// to rebuffer 80% of that whenever we encounter a buffer underrun.
|
||||
|
||||
// Leave the net buffer properties at the default.
|
||||
//FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
|
||||
}
|
||||
|
||||
|
||||
LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX()
|
||||
{
|
||||
// nothing interesting/safe to do.
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODEX::start(const std::string& url)
|
||||
{
|
||||
//if (!mInited)
|
||||
//{
|
||||
// llwarns << "startInternetStream before audio initialized" << llendl;
|
||||
// return;
|
||||
//}
|
||||
|
||||
// "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
|
||||
stop();
|
||||
|
||||
if (!url.empty())
|
||||
{
|
||||
llinfos << "Starting internet stream: " << url << llendl;
|
||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url);
|
||||
mURL = url;
|
||||
mMetaData = new LLSD;
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "Set internet stream to null" << llendl;
|
||||
mURL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODEX::update()
|
||||
{
|
||||
// Kill dead internet streams, if possible
|
||||
std::list<LLAudioStreamManagerFMODEX *>::iterator iter;
|
||||
for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
|
||||
{
|
||||
LLAudioStreamManagerFMODEX *streamp = *iter;
|
||||
if (streamp->stopStream())
|
||||
{
|
||||
llinfos << "Closed dead stream" << llendl;
|
||||
delete streamp;
|
||||
mDeadStreams.erase(iter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't do anything if there are no streams playing
|
||||
if (!mCurrentInternetStreamp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState();
|
||||
|
||||
if (open_state == FMOD_OPENSTATE_READY)
|
||||
{
|
||||
// Stream is live
|
||||
|
||||
// start the stream if it's ready
|
||||
if (!mFMODInternetStreamChannelp &&
|
||||
(mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream()))
|
||||
{
|
||||
// Reset volume to previously set volume
|
||||
setGain(getGain());
|
||||
mFMODInternetStreamChannelp->setPaused(false);
|
||||
}
|
||||
}
|
||||
else if(open_state == FMOD_OPENSTATE_ERROR)
|
||||
{
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(mFMODInternetStreamChannelp)
|
||||
{
|
||||
if(!mMetaData)
|
||||
mMetaData = new LLSD;
|
||||
|
||||
FMOD::Sound *sound = NULL;
|
||||
|
||||
if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
|
||||
{
|
||||
FMOD_TAG tag;
|
||||
S32 tagcount, dirtytagcount;
|
||||
if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount)
|
||||
{
|
||||
mMetaData->clear();
|
||||
|
||||
for(S32 i = 0; i < tagcount; ++i)
|
||||
{
|
||||
if(sound->getTag(NULL, i, &tag)!=FMOD_OK)
|
||||
continue;
|
||||
std::string name = tag.name;
|
||||
switch(tag.type) //Crappy tag translate table.
|
||||
{
|
||||
case(FMOD_TAGTYPE_ID3V2):
|
||||
if(name == "TIT2") name = "TITLE";
|
||||
else if(name == "TPE1") name = "ARTIST";
|
||||
break;
|
||||
case(FMOD_TAGTYPE_ASF):
|
||||
if(name == "Title") name = "TITLE";
|
||||
else if(name == "WM/AlbumArtist") name = "ARTIST";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch(tag.datatype)
|
||||
{
|
||||
case(FMOD_TAGDATATYPE_INT):
|
||||
(*mMetaData)[name]=*(LLSD::Integer*)(tag.data);
|
||||
llinfos << tag.name << ": " << *(int*)(tag.data) << llendl;
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_FLOAT):
|
||||
(*mMetaData)[name]=*(LLSD::Float*)(tag.data);
|
||||
llinfos << tag.name << ": " << *(float*)(tag.data) << llendl;
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_STRING):
|
||||
{
|
||||
std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen));
|
||||
(*mMetaData)[name]=out;
|
||||
llinfos << tag.name << ": " << out << llendl;
|
||||
}
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_STRING_UTF16):
|
||||
{
|
||||
std::string out((char*)tag.data,tag.datalen);
|
||||
(*mMetaData)[std::string(tag.name)]=out;
|
||||
llinfos << tag.name << ": " << out << llendl;
|
||||
}
|
||||
break;
|
||||
case(FMOD_TAGDATATYPE_STRING_UTF16BE):
|
||||
{
|
||||
std::string out((char*)tag.data,tag.datalen);
|
||||
U16* buf = (U16*)out.c_str();
|
||||
for(U32 j = 0; j < out.size()/2; ++j)
|
||||
(((buf[j] & 0xff)<<8) | ((buf[j] & 0xff00)>>8));
|
||||
(*mMetaData)[std::string(tag.name)]=out;
|
||||
llinfos << tag.name << ": " << out << llendl;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODEX::stop()
|
||||
{
|
||||
if(mMetaData)
|
||||
{
|
||||
delete mMetaData;
|
||||
mMetaData = NULL;
|
||||
}
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
mFMODInternetStreamChannelp->setPaused(true);
|
||||
mFMODInternetStreamChannelp->setPriority(0);
|
||||
mFMODInternetStreamChannelp = NULL;
|
||||
}
|
||||
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl;
|
||||
if (mCurrentInternetStreamp->stopStream())
|
||||
{
|
||||
delete mCurrentInternetStreamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl;
|
||||
mDeadStreams.push_back(mCurrentInternetStreamp);
|
||||
}
|
||||
mCurrentInternetStreamp = NULL;
|
||||
//mURL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODEX::pause(int pauseopt)
|
||||
{
|
||||
if (pauseopt < 0)
|
||||
{
|
||||
pauseopt = mCurrentInternetStreamp ? 1 : 0;
|
||||
}
|
||||
|
||||
if (pauseopt)
|
||||
{
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
stop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
start(getURL());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A stream is "playing" if it has been requested to start. That
|
||||
// doesn't necessarily mean audio is coming out of the speakers.
|
||||
int LLStreamingAudio_FMODEX::isPlaying()
|
||||
{
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
return 1; // Active and playing
|
||||
}
|
||||
else if (!mURL.empty())
|
||||
{
|
||||
return 2; // "Paused"
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
F32 LLStreamingAudio_FMODEX::getGain()
|
||||
{
|
||||
return mGain;
|
||||
}
|
||||
|
||||
|
||||
std::string LLStreamingAudio_FMODEX::getURL()
|
||||
{
|
||||
return mURL;
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODEX::setGain(F32 vol)
|
||||
{
|
||||
mGain = vol;
|
||||
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here?
|
||||
|
||||
mFMODInternetStreamChannelp->setVolume(vol);
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ bool LLStreamingAudio_FMODEX::getWaveData(float* arr, S32 count, S32 stride/*=1*/)
|
||||
{
|
||||
if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp)
|
||||
return false;
|
||||
|
||||
static std::vector<float> local_array(count); //Have to have an extra buffer to mix channels. Bleh.
|
||||
if(count > (S32)local_array.size()) //Expand the array if needed. Try to minimize allocation calls, so don't ever shrink.
|
||||
local_array.resize(count);
|
||||
|
||||
if( mFMODInternetStreamChannelp->getWaveData(&local_array[0],count,0) == FMOD_OK &&
|
||||
mFMODInternetStreamChannelp->getWaveData(&arr[0],count,1) == FMOD_OK )
|
||||
{
|
||||
for(S32 i = count-1;i>=0;i-=stride)
|
||||
{
|
||||
arr[i] += local_array[i];
|
||||
arr[i] *= .5f;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// manager of possibly-multiple internet audio streams
|
||||
|
||||
LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) :
|
||||
mSystem(system),
|
||||
mStreamChannel(NULL),
|
||||
mInternetStream(NULL),
|
||||
mReady(false)
|
||||
{
|
||||
mInternetStreamURL = url;
|
||||
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
memset(&exinfo,0,sizeof(exinfo));
|
||||
exinfo.cbsize = sizeof(exinfo);
|
||||
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_MPEG; //Hint to speed up loading.
|
||||
|
||||
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING, &exinfo, &mInternetStream);
|
||||
|
||||
if (result!= FMOD_OK)
|
||||
{
|
||||
llwarns << "Couldn't open fmod stream, error "
|
||||
<< FMOD_ErrorString(result)
|
||||
<< llendl;
|
||||
mReady = false;
|
||||
return;
|
||||
}
|
||||
|
||||
mReady = true;
|
||||
}
|
||||
|
||||
FMOD::Channel *LLAudioStreamManagerFMODEX::startStream()
|
||||
{
|
||||
// We need a live and opened stream before we try and play it.
|
||||
if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY)
|
||||
{
|
||||
llwarns << "No internet stream to start playing!" << llendl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(mStreamChannel)
|
||||
return mStreamChannel; //Already have a channel for this stream.
|
||||
|
||||
mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel);
|
||||
return mStreamChannel;
|
||||
}
|
||||
|
||||
bool LLAudioStreamManagerFMODEX::stopStream()
|
||||
{
|
||||
if (mInternetStream)
|
||||
{
|
||||
|
||||
|
||||
bool close = true;
|
||||
switch (getOpenState())
|
||||
{
|
||||
case FMOD_OPENSTATE_CONNECTING:
|
||||
close = false;
|
||||
break;
|
||||
/*case FSOUND_STREAM_NET_NOTCONNECTED:
|
||||
case FSOUND_STREAM_NET_BUFFERING:
|
||||
case FSOUND_STREAM_NET_READY:
|
||||
case FSOUND_STREAM_NET_ERROR:*/
|
||||
default:
|
||||
close = true;
|
||||
}
|
||||
|
||||
if (close)
|
||||
{
|
||||
mInternetStream->release();
|
||||
mStreamChannel = NULL;
|
||||
mInternetStream = NULL;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState()
|
||||
{
|
||||
FMOD_OPENSTATE state;
|
||||
mInternetStream->getOpenState(&state,NULL,NULL,NULL);
|
||||
return state;
|
||||
}
|
||||
83
indra/llaudio/llstreamingaudio_fmodex.h
Normal file
83
indra/llaudio/llstreamingaudio_fmodex.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @file streamingaudio_fmod.h
|
||||
* @author Tofu Linden
|
||||
* @brief Definition of LLStreamingAudio_FMOD implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_STREAMINGAUDIO_FMOD_H
|
||||
#define LL_STREAMINGAUDIO_FMOD_H
|
||||
|
||||
#include "stdtypes.h" // from llcommon
|
||||
|
||||
#include "llstreamingaudio.h"
|
||||
|
||||
//Stubs
|
||||
class LLAudioStreamManagerFMODEX;
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
class Channel;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface
|
||||
{
|
||||
public:
|
||||
LLStreamingAudio_FMODEX(FMOD::System *system);
|
||||
/*virtual*/ ~LLStreamingAudio_FMODEX();
|
||||
|
||||
/*virtual*/ void start(const std::string& url);
|
||||
/*virtual*/ void stop();
|
||||
/*virtual*/ void pause(int pause);
|
||||
/*virtual*/ void update();
|
||||
/*virtual*/ int isPlaying();
|
||||
/*virtual*/ void setGain(F32 vol);
|
||||
/*virtual*/ F32 getGain();
|
||||
/*virtual*/ std::string getURL();
|
||||
|
||||
/*virtual*/ bool supportsMetaData(){return true;}
|
||||
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
|
||||
/*virtual*/ bool supportsWaveData(){return true;}
|
||||
/*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1);
|
||||
private:
|
||||
FMOD::System *mSystem;
|
||||
|
||||
LLAudioStreamManagerFMODEX *mCurrentInternetStreamp;
|
||||
FMOD::Channel *mFMODInternetStreamChannelp;
|
||||
std::list<LLAudioStreamManagerFMODEX *> mDeadStreams;
|
||||
|
||||
std::string mURL;
|
||||
F32 mGain;
|
||||
|
||||
LLSD *mMetaData;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_STREAMINGAUDIO_FMOD_H
|
||||
@@ -133,10 +133,10 @@ BOOL decode_vorbis_file(LLVFS *vfs, const LLUUID &in_uuid, char *out_fname)
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
//**********************************
|
||||
// **********************************
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(out_fname,LL_APR_WPB);
|
||||
//**********************************
|
||||
// **********************************
|
||||
if (!outfile.getFileHandle())
|
||||
{
|
||||
llwarning("unable to open vorbis destination file for writing",0);
|
||||
@@ -308,9 +308,9 @@ BOOL decode_vorbis_file(LLVFS *vfs, const LLUUID &in_uuid, char *out_fname)
|
||||
|
||||
outfile.seek(SEEK_END,-fade_length*2);
|
||||
outfile.write(pcmout,2*fade_length); //write back xfaded last 16 samples
|
||||
//*******************
|
||||
// *******************
|
||||
outfile.close();
|
||||
//*******************
|
||||
// *******************
|
||||
|
||||
if ((36 == data_length) || (!(eof)))
|
||||
{
|
||||
|
||||
@@ -87,10 +87,10 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
|
||||
|
||||
error_msg.clear();
|
||||
|
||||
//********************************
|
||||
// ********************************
|
||||
LLAPRFile infile ;
|
||||
infile.open(in_fname,LL_APR_RB);
|
||||
//********************************
|
||||
// ********************************
|
||||
if (!infile.getFileHandle())
|
||||
{
|
||||
error_msg = "CannotUploadSoundFile";
|
||||
@@ -159,9 +159,9 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
|
||||
file_pos += (chunk_length + 8);
|
||||
chunk_length = 0;
|
||||
}
|
||||
//****************
|
||||
// ****************
|
||||
infile.close();
|
||||
//****************
|
||||
// ****************
|
||||
|
||||
if (!uncompressed_pcm)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#define WINDGEN_H
|
||||
|
||||
#include "llcommon.h"
|
||||
#include "llrand.h"
|
||||
|
||||
template <class MIXBUFFERFORMAT_T>
|
||||
class LLWindGen
|
||||
@@ -60,7 +61,9 @@ public:
|
||||
}
|
||||
|
||||
const U32 getInputSamplingRate() { return mInputSamplingRate; }
|
||||
|
||||
const F32 getNextSample();
|
||||
const F32 getClampedSample(bool clamp, F32 sample);
|
||||
|
||||
// newbuffer = the buffer passed from the previous DSP unit.
|
||||
// numsamples = length in samples-per-channel at this mix time.
|
||||
// NOTE: generates L/R interleaved stereo
|
||||
@@ -95,7 +98,7 @@ public:
|
||||
|
||||
// Start with white noise
|
||||
// This expression is fragile, rearrange it and it will break!
|
||||
next_sample = (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8);
|
||||
next_sample = getNextSample();
|
||||
|
||||
// Apply a pinking filter
|
||||
// Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
|
||||
@@ -132,23 +135,13 @@ public:
|
||||
for (U8 i=mSubSamples; i && numsamples; --i, --numsamples)
|
||||
{
|
||||
mLastSample = mLastSample + delta;
|
||||
S32 sample_right = (S32)(mLastSample * mCurrentPanGainR);
|
||||
S32 sample_left = (S32)mLastSample - sample_right;
|
||||
MIXBUFFERFORMAT_T sample_right = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample * mCurrentPanGainR);
|
||||
MIXBUFFERFORMAT_T sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right);
|
||||
|
||||
if (!clip)
|
||||
{
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)sample_left;
|
||||
++cursamplep;
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)sample_right;
|
||||
++cursamplep;
|
||||
}
|
||||
else
|
||||
{
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_left, (S32)S16_MIN, (S32)S16_MAX);
|
||||
++cursamplep;
|
||||
*cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_right, (S32)S16_MIN, (S32)S16_MAX);
|
||||
++cursamplep;
|
||||
}
|
||||
*cursamplep = sample_left;
|
||||
++cursamplep;
|
||||
*cursamplep = sample_right;
|
||||
++cursamplep;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,4 +172,9 @@ private:
|
||||
F32 mLastSample;
|
||||
};
|
||||
|
||||
template<class T> inline const F32 LLWindGen<T>::getNextSample() { return (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8); }
|
||||
template<> inline const F32 LLWindGen<F32>::getNextSample() { return ll_frand()-.5f; }
|
||||
template<class T> inline const F32 LLWindGen<T>::getClampedSample(bool clamp, F32 sample) { return clamp ? (F32)llclamp((S32)sample,(S32)S16_MIN,(S32)S16_MAX) : sample; }
|
||||
template<> inline const F32 LLWindGen<F32>::getClampedSample(bool clamp, F32 sample) { return sample; }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -195,15 +195,19 @@ void LLCharacter::requestStopMotion( LLMotion* motion)
|
||||
//-----------------------------------------------------------------------------
|
||||
// updateMotions()
|
||||
//-----------------------------------------------------------------------------
|
||||
static LLFastTimer::DeclareTimer FTM_UPDATE_ANIMATION("Update Animation");
|
||||
static LLFastTimer::DeclareTimer FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim");
|
||||
|
||||
void LLCharacter::updateMotions(e_update_t update_type)
|
||||
{
|
||||
LLFastTimer t(LLFastTimer::FTM_UPDATE_ANIMATION);
|
||||
if (update_type == HIDDEN_UPDATE)
|
||||
{
|
||||
LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION);
|
||||
mMotionController.updateMotionsMinimal();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLFastTimer t(FTM_UPDATE_ANIMATION);
|
||||
// unpause if the number of outstanding pause requests has dropped to the initial one
|
||||
if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
|
||||
{
|
||||
|
||||
@@ -56,9 +56,7 @@ LLJoint::LLJoint()
|
||||
mUpdateXform = TRUE;
|
||||
mJointNum = -1;
|
||||
touch();
|
||||
#if MESH_ENABLED
|
||||
mResetAfterRestoreOldXform = false;
|
||||
#endif //MESH_ENABLED
|
||||
}
|
||||
|
||||
|
||||
@@ -242,7 +240,6 @@ void LLJoint::setPosition( const LLVector3& pos )
|
||||
}
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
//--------------------------------------------------------------------
|
||||
// setPosition()
|
||||
//--------------------------------------------------------------------
|
||||
@@ -278,7 +275,6 @@ void LLJoint::restoreToDefaultXform( void )
|
||||
mXform = mDefaultXform;
|
||||
setPosition( mXform.getPosition() );
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// getWorldPosition()
|
||||
|
||||
@@ -86,19 +86,14 @@ protected:
|
||||
|
||||
// explicit transformation members
|
||||
LLXformMatrix mXform;
|
||||
#if MESH_ENABLED
|
||||
LLXformMatrix mOldXform;
|
||||
LLXformMatrix mDefaultXform;
|
||||
|
||||
LLUUID mId;
|
||||
#endif //MESH_ENABLED
|
||||
public:
|
||||
U32 mDirtyFlags;
|
||||
BOOL mUpdateXform;
|
||||
|
||||
#if MESH_ENABLED
|
||||
BOOL mResetAfterRestoreOldXform;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// describes the skin binding pose
|
||||
LLVector3 mSkinOffset;
|
||||
@@ -188,8 +183,6 @@ public:
|
||||
S32 getJointNum() const { return mJointNum; }
|
||||
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
|
||||
|
||||
#if MESH_ENABLED
|
||||
|
||||
void restoreOldXform( void );
|
||||
void restoreToDefaultXform( void );
|
||||
void setDefaultFromCurrentXform( void );
|
||||
@@ -204,7 +197,6 @@ public:
|
||||
const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
|
||||
//Setter for joint reset flag
|
||||
void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// <edit>
|
||||
std::string exportString(U32 tabs = 0);
|
||||
|
||||
@@ -637,9 +637,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
motionp->fadeIn();
|
||||
}
|
||||
|
||||
//**********************
|
||||
// **********************
|
||||
// MOTION INACTIVE
|
||||
//**********************
|
||||
// **********************
|
||||
if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
|
||||
{
|
||||
// this motion has gone on too long, deactivate it
|
||||
@@ -659,9 +659,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
}
|
||||
}
|
||||
|
||||
//**********************
|
||||
// **********************
|
||||
// MOTION EASE OUT
|
||||
//**********************
|
||||
// **********************
|
||||
else if (motionp->isStopped() && mAnimTime > motionp->getStopTime())
|
||||
{
|
||||
// is this the first iteration in the ease out phase?
|
||||
@@ -684,9 +684,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
|
||||
}
|
||||
|
||||
//**********************
|
||||
// **********************
|
||||
// MOTION ACTIVE
|
||||
//**********************
|
||||
// **********************
|
||||
else if (mAnimTime > motionp->mActivationTimestamp + motionp->getEaseInDuration())
|
||||
{
|
||||
posep->setWeight(motionp->getFadeWeight());
|
||||
@@ -707,9 +707,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
||||
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
|
||||
}
|
||||
|
||||
//**********************
|
||||
// **********************
|
||||
// MOTION EASE IN
|
||||
//**********************
|
||||
// **********************
|
||||
else if (mAnimTime >= motionp->mActivationTimestamp)
|
||||
{
|
||||
if (mLastTime < motionp->mActivationTimestamp)
|
||||
|
||||
@@ -15,6 +15,7 @@ include_directories(
|
||||
)
|
||||
|
||||
set(llcommon_SOURCE_FILES
|
||||
aiframetimer.cpp
|
||||
imageids.cpp
|
||||
indra_constants.cpp
|
||||
llapp.cpp
|
||||
@@ -35,7 +36,7 @@ set(llcommon_SOURCE_FILES
|
||||
llerrorthread.cpp
|
||||
llevent.cpp
|
||||
lleventtimer.cpp
|
||||
llfasttimer.cpp
|
||||
llfasttimer_class.cpp
|
||||
llfile.cpp
|
||||
llfindlocale.cpp
|
||||
llfixedbuffer.cpp
|
||||
@@ -54,6 +55,7 @@ set(llcommon_SOURCE_FILES
|
||||
llmetrics.cpp
|
||||
llmortician.cpp
|
||||
lloptioninterface.cpp
|
||||
llptrto.cpp
|
||||
llprocesslauncher.cpp
|
||||
llprocessor.cpp
|
||||
llqueuedthread.cpp
|
||||
@@ -89,6 +91,7 @@ set(llcommon_SOURCE_FILES
|
||||
set(llcommon_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
aiframetimer.h
|
||||
aithreadsafe.h
|
||||
bitpack.h
|
||||
ctype_workaround.h
|
||||
@@ -136,6 +139,7 @@ set(llcommon_HEADER_FILES
|
||||
llextendedstatus.h
|
||||
lleventtimer.h
|
||||
llfasttimer.h
|
||||
llfasttimer_class.h
|
||||
llfile.h
|
||||
llfindlocale.h
|
||||
llfixedbuffer.h
|
||||
@@ -171,6 +175,7 @@ set(llcommon_HEADER_FILES
|
||||
llprocessor.h
|
||||
llptrskiplist.h
|
||||
llptrskipmap.h
|
||||
llptrto.h
|
||||
llqueuedthread.h
|
||||
llrand.h
|
||||
llrefcount.h
|
||||
|
||||
150
indra/llcommon/aiframetimer.cpp
Normal file
150
indra/llcommon/aiframetimer.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* @file aiframetimer.cpp
|
||||
*
|
||||
* Copyright (c) 2011, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 06/08/2011
|
||||
* - Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "aiframetimer.h"
|
||||
|
||||
static F64 const NEVER = 1e16; // 317 million years.
|
||||
|
||||
F64 AIFrameTimer::sNextExpiration;
|
||||
AIFrameTimer::timer_list_type AIFrameTimer::sTimerList;
|
||||
LLMutex AIFrameTimer::sMutex;
|
||||
|
||||
// Notes on thread-safety of AIRunningFrameTimer (continued from aiframetimer.h)
|
||||
//
|
||||
// Most notably, the constructor and init() should be called as follows:
|
||||
// 1) The object is constructed (AIRunningFrameTimer::AIRunningFrameTimer).
|
||||
// 2) The lock is obtained.
|
||||
// 3) The object is inserted in the list (operator<(AIRunningFrameTimer const&, AIRunningFrameTimer const&)).
|
||||
// 4) The object is initialized (AIRunningFrameTimer::init).
|
||||
// 5) The lock is released.
|
||||
// This assures that the object is not yet shared at the moment that it is initialized.
|
||||
|
||||
void AIFrameTimer::create(F64 expiration, signal_type::slot_type const& slot)
|
||||
{
|
||||
AIRunningFrameTimer new_timer(expiration, this);
|
||||
sMutex.lock();
|
||||
llassert(mHandle.mRunningTimer == sTimerList.end()); // Create may only be called when the timer isn't already running.
|
||||
mHandle.init(sTimerList.insert(new_timer), slot);
|
||||
sNextExpiration = sTimerList.begin()->expiration();
|
||||
sMutex.unlock();
|
||||
}
|
||||
|
||||
void AIFrameTimer::cancel(void)
|
||||
{
|
||||
// In order to stop us from returning from cancel() while
|
||||
// the callback function is being called (which is done
|
||||
// in AIFrameTimer::handleExpiration after obtaining the
|
||||
// mHandle.mMutex lock), we start with trying to obtain
|
||||
// it here and as such wait till the callback function
|
||||
// returned.
|
||||
mHandle.mMutex.lock();
|
||||
// Next we have to grab this lock in order to stop
|
||||
// AIFrameTimer::handleExpiration from even entering
|
||||
// in the case we manage to get it first.
|
||||
sMutex.lock();
|
||||
if (mHandle.mRunningTimer != sTimerList.end())
|
||||
{
|
||||
sTimerList.erase(mHandle.mRunningTimer);
|
||||
mHandle.mRunningTimer = sTimerList.end();
|
||||
sNextExpiration = sTimerList.empty() ? NEVER : sTimerList.begin()->expiration();
|
||||
}
|
||||
sMutex.unlock();
|
||||
mHandle.mMutex.unlock();
|
||||
}
|
||||
|
||||
void AIFrameTimer::handleExpiration(F64 current_frame_time)
|
||||
{
|
||||
sMutex.lock();
|
||||
for(;;)
|
||||
{
|
||||
if (sTimerList.empty())
|
||||
{
|
||||
// No running timers left.
|
||||
sNextExpiration = NEVER;
|
||||
break;
|
||||
}
|
||||
timer_list_type::iterator running_timer = sTimerList.begin();
|
||||
sNextExpiration = running_timer->expiration();
|
||||
if (sNextExpiration > current_frame_time)
|
||||
{
|
||||
// Didn't expire yet.
|
||||
break;
|
||||
}
|
||||
|
||||
// Obtain handle of running timer through the associated AIFrameTimer object.
|
||||
// Note that if the AIFrameTimer object was destructed (when running_timer->getTimer()
|
||||
// would return an invalid pointer) then it called cancel(), so we can't be here.
|
||||
Handle& handle(running_timer->getTimer()->mHandle);
|
||||
llassert_always(running_timer == handle.mRunningTimer);
|
||||
|
||||
// We're going to erase this timer, so stop cancel() from doing the same.
|
||||
handle.mRunningTimer = sTimerList.end();
|
||||
|
||||
// We keep handle.mMutex during the callback to prevent the thread that
|
||||
// owns the AIFrameTimer from deleting the callback function while we
|
||||
// call it: in order to do so it first has to call cancel(), which will
|
||||
// block until we release this mutex again, or we won't call the callback
|
||||
// function here because the trylock fails.
|
||||
//
|
||||
// Assuming the main thread arrived here, there are two possible states
|
||||
// for the other thread that tries to delete the call back function,
|
||||
// right after calling the cancel() function too:
|
||||
//
|
||||
// 1. It hasn't obtained the first lock yet, we obtain the handle.mMutex
|
||||
// lock and the other thread will stall on the first line of cancel().
|
||||
// After do_callback returns, the other thread will do nothing because
|
||||
// handle.mRunningTimer equals sTimerList.end(), exit the function and
|
||||
// (possibly) delete the callback object, but that is ok as we already
|
||||
// returned from the callback function.
|
||||
//
|
||||
// 2. It already called cancel() and hangs on the second line trying to
|
||||
// obtain sMutex.lock(). The trylock below fails and we never call the
|
||||
// callback function. We erase the running timer here and release sMutex
|
||||
// at the end, after which the other thread does nothing because
|
||||
// handle.mRunningTimer equals sTimerList.end(), exits the function and
|
||||
// (possibly) deletes the callback object.
|
||||
//
|
||||
// Note that if the other thread actually obtained the sMutex then we
|
||||
// can't be here: this is still inside the critical area of sMutex.
|
||||
if (handle.mMutex.tryLock()) // If this fails then another thread is in the process of cancelling this timer, so do nothing.
|
||||
{
|
||||
sMutex.unlock();
|
||||
running_timer->do_callback(); // May not throw exceptions.
|
||||
sMutex.lock();
|
||||
handle.mMutex.unlock(); // Allow other thread to return from cancel() and possibly delete the callback object.
|
||||
}
|
||||
|
||||
// Erase the timer from the running list.
|
||||
sTimerList.erase(running_timer);
|
||||
}
|
||||
sMutex.unlock();
|
||||
}
|
||||
|
||||
136
indra/llcommon/aiframetimer.h
Normal file
136
indra/llcommon/aiframetimer.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @file aiframetimer.h
|
||||
* @brief Implementation of AIFrameTimer.
|
||||
*
|
||||
* Copyright (c) 2011, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 05/08/2011
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AIFRAMETIMER_H
|
||||
#define AIFRAMETIMER_H
|
||||
|
||||
#include "llframetimer.h"
|
||||
#include "llthread.h"
|
||||
#include <boost/signals2.hpp>
|
||||
#include <set>
|
||||
|
||||
class LL_COMMON_API AIFrameTimer
|
||||
{
|
||||
protected:
|
||||
typedef boost::signals2::signal<void (void)> signal_type;
|
||||
|
||||
private:
|
||||
// Use separate struct for this object because it is non-copyable.
|
||||
struct Signal {
|
||||
signal_type mSignal;
|
||||
};
|
||||
|
||||
// Notes on Thread-Safety
|
||||
//
|
||||
// This is the type of the objects stored in AIFrameTimer::sTimerList, and as such leans
|
||||
// for it's thread-safety on the same lock as is used for that std::multiset as follows.
|
||||
// An arbitrary thread can create, insert and initialize this object. Other threads can
|
||||
// not access it until that has completed.
|
||||
//
|
||||
// After creation two threads can access it: the thread that created it (owns the
|
||||
// AIFrameTimer object, which has an mHandle that points to this object), or the main
|
||||
// thread by finding it in sTimerList.
|
||||
//
|
||||
// See aiframetimer.cpp for more notes.
|
||||
class AIRunningFrameTimer {
|
||||
private:
|
||||
F64 mExpire; // Time at which the timer expires, in seconds since application start (compared to LLFrameTimer::sFrameTime).
|
||||
Signal* mCallback;
|
||||
AIFrameTimer* mTimer;
|
||||
|
||||
public:
|
||||
AIRunningFrameTimer(F64 expiration, AIFrameTimer* timer) : mExpire(LLFrameTimer::getElapsedSeconds() + expiration), mCallback(new Signal), mTimer(timer) { }
|
||||
~AIRunningFrameTimer() { delete mCallback; }
|
||||
void init(signal_type::slot_type const& slot) const { mCallback->mSignal.connect(slot); }
|
||||
|
||||
friend bool operator<(AIRunningFrameTimer const& ft1, AIRunningFrameTimer const& ft2) { return ft1.mExpire < ft2.mExpire; }
|
||||
|
||||
void do_callback(void) const { mCallback->mSignal(); }
|
||||
F64 expiration(void) const { return mExpire; }
|
||||
AIFrameTimer* getTimer(void) const { return mTimer; }
|
||||
};
|
||||
|
||||
typedef std::multiset<AIRunningFrameTimer> timer_list_type;
|
||||
|
||||
static LLMutex sMutex; // Mutex for the two global variables below.
|
||||
static timer_list_type sTimerList; // List with all running timers.
|
||||
static F64 sNextExpiration; // Cache of smallest value in sTimerList.
|
||||
friend class LLFrameTimer; // Access to sNextExpiration.
|
||||
|
||||
class Handle {
|
||||
public:
|
||||
timer_list_type::iterator mRunningTimer; // Points to the running timer, or to sTimerList.end() when not running.
|
||||
// Access to this iterator is protected by the AIFrameTimer::sMutex!
|
||||
LLMutex mMutex; // A mutex used to protect us from deletion of the callback object while
|
||||
// calling the callback function in the case of simultaneous expiration
|
||||
// and cancellation by the thread owning the AIFrameTimer (by calling
|
||||
// AIFrameTimer::cancel).
|
||||
|
||||
// Constructor for a not-running timer.
|
||||
Handle(void) : mRunningTimer(sTimerList.end()) { }
|
||||
|
||||
// Actual initialization used by AIFrameTimer::create.
|
||||
void init(timer_list_type::iterator const& running_timer, signal_type::slot_type const& slot)
|
||||
{
|
||||
// Locking AIFrameTimer::sMutex is not neccessary here, because we're creating
|
||||
// the object and no other thread knows of mRunningTimer at this point.
|
||||
mRunningTimer = running_timer;
|
||||
mRunningTimer->init(slot);
|
||||
}
|
||||
|
||||
private:
|
||||
// LLMutex has no assignment operator.
|
||||
Handle& operator=(Handle const&) { return *this; }
|
||||
};
|
||||
|
||||
Handle mHandle;
|
||||
|
||||
public:
|
||||
// Construct an AIFrameTimer that is not running.
|
||||
AIFrameTimer(void) { }
|
||||
|
||||
// Construction of a running AIFrameTimer with expiration time expiration in seconds, and callback slot.
|
||||
AIFrameTimer(F64 expiration, signal_type::slot_type const& slot) { create(expiration, slot); }
|
||||
|
||||
// Destructing the AIFrameTimer object terminates the running timer (if still running).
|
||||
// Note that cancel() must have returned BEFORE anything is destructed that would disallow the callback function to be called.
|
||||
// So, if the AIFrameTimer is a member of an object whose callback function is called then cancel() has
|
||||
// to be called manually (or from the destructor of THAT object), before that object is destructed.
|
||||
// Cancel may be called multiple times.
|
||||
~AIFrameTimer() { cancel(); }
|
||||
|
||||
void create(F64 expiration, signal_type::slot_type const& slot);
|
||||
void cancel(void);
|
||||
|
||||
protected:
|
||||
static void handleExpiration(F64 current_frame_time);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -124,7 +124,7 @@ public:
|
||||
|
||||
// NOTE: This next two funtions are only included here
|
||||
// for those too familiar with the LLLinkedList template class.
|
||||
// They are depreciated. resetList() is unecessary while
|
||||
// They are deprecated. resetList() is unecessary while
|
||||
// getCurrentData() is identical to getNextData() and has
|
||||
// a misleading name.
|
||||
//
|
||||
@@ -604,7 +604,7 @@ BOOL LLDoubleLinkedList<DATA_TYPE>::checkData(const DATA_TYPE *data)
|
||||
|
||||
// NOTE: This next two funtions are only included here
|
||||
// for those too familiar with the LLLinkedList template class.
|
||||
// They are depreciated. resetList() is unecessary while
|
||||
// They are deprecated. resetList() is unecessary while
|
||||
// getCurrentData() is identical to getNextData() and has
|
||||
// a misleading name.
|
||||
//
|
||||
|
||||
@@ -153,11 +153,6 @@ const char LAND_LAYER_CODE = 'L';
|
||||
const char WATER_LAYER_CODE = 'W';
|
||||
const char WIND_LAYER_CODE = '7';
|
||||
const char CLOUD_LAYER_CODE = '8';
|
||||
// Extended land layer for Aurora Sim
|
||||
const char AURORA_LAND_LAYER_CODE = 'M';
|
||||
const char AURORA_WATER_LAYER_CODE = 'X';
|
||||
const char AURORA_WIND_LAYER_CODE = '9';
|
||||
const char AURORA_CLOUD_LAYER_CODE = ':';
|
||||
|
||||
// keys
|
||||
// Bit masks for various keyboard modifier keys.
|
||||
|
||||
@@ -249,7 +249,7 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
|
||||
}
|
||||
|
||||
//
|
||||
//*******************************************************************************************************************************
|
||||
// *******************************************************************************************************************************
|
||||
//static components of LLAPRFile
|
||||
//
|
||||
|
||||
@@ -504,5 +504,5 @@ bool LLAPRFile::removeDir(const std::string& dirname)
|
||||
}
|
||||
//
|
||||
//end of static components of LLAPRFile
|
||||
//*******************************************************************************************************************************
|
||||
// *******************************************************************************************************************************
|
||||
//
|
||||
|
||||
@@ -168,7 +168,7 @@ public:
|
||||
apr_file_t* getFileHandle() {return mFile;}
|
||||
|
||||
//
|
||||
//*******************************************************************************************************************************
|
||||
// *******************************************************************************************************************************
|
||||
//static components
|
||||
//
|
||||
private:
|
||||
@@ -185,7 +185,7 @@ public:
|
||||
// Returns bytes read/written, 0 if read/write fails:
|
||||
static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes);
|
||||
static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes);
|
||||
//*******************************************************************************************************************************
|
||||
// *******************************************************************************************************************************
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -214,17 +214,16 @@ LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_
|
||||
bool LLAssetType::lookupCanLink(EType asset_type)
|
||||
{
|
||||
//Check that enabling all these other types as linkable doesn't break things.
|
||||
/*const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
|
||||
const AssetEntry *entry = dict->lookup(asset_type);
|
||||
if (entry)
|
||||
{
|
||||
return entry->mCanLink;
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
|
||||
return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY ||
|
||||
asset_type == AT_BODYPART || asset_type == AT_GESTURE);
|
||||
/*return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY ||
|
||||
asset_type == AT_BODYPART || asset_type == AT_GESTURE);*/
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "llfasttimer.h"
|
||||
#include "lltimer.h"
|
||||
#include "llstring.h"
|
||||
|
||||
@@ -94,9 +95,11 @@ std::string LLDate::asRFC1123() const
|
||||
return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));
|
||||
}
|
||||
|
||||
LLFastTimer::DeclareTimer FT_DATE_FORMAT("Date Format");
|
||||
|
||||
std::string LLDate::toHTTPDateString (std::string fmt) const
|
||||
{
|
||||
LLFastTimer ft1(FT_DATE_FORMAT);
|
||||
|
||||
time_t locSeconds = (time_t) mSecondsSinceEpoch;
|
||||
struct tm * gmt = gmtime (&locSeconds);
|
||||
@@ -105,7 +108,7 @@ std::string LLDate::toHTTPDateString (std::string fmt) const
|
||||
|
||||
std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt)
|
||||
{
|
||||
// Return Epoch UTC date
|
||||
LLFastTimer ft1(FT_DATE_FORMAT);
|
||||
|
||||
// avoid calling setlocale() unnecessarily - it's expensive.
|
||||
static std::string prev_locale = "";
|
||||
|
||||
@@ -107,7 +107,14 @@ const int LL_ERR_PRICE_MISMATCH = -23018;
|
||||
|
||||
#define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl;
|
||||
|
||||
#define llassert_always(func) if (LL_UNLIKELY(!(func))) llerrs << "ASSERT (" << #func << ")" << llendl;
|
||||
#define liru_slashpos std::string(__FILE__).find_last_of("/\\")
|
||||
#define liru_slashpos2 std::string(__FILE__).substr(0,liru_slashpos).find_last_of("/\\")
|
||||
#define liru_assert_strip /*strip path down to lastlevel directory and filename for assert.*/\
|
||||
(liru_slashpos == std::string::npos ? std::string(__FILE__)/*just filename, print as is*/\
|
||||
: liru_slashpos2 == std::string::npos ? std::string(__FILE__)/*Apparently, we're in / or perhaps the top of the drive, print as is*/\
|
||||
: std::string(__FILE__).substr(1+liru_slashpos2))/*print foo/bar.cpp or perhaps foo\bar.cpp*/
|
||||
|
||||
#define llassert_always(func) if (LL_UNLIKELY(!(func))) llerrs <<"\nASSERT(" #func ")\nfile:"<<liru_assert_strip<<" line:"<<__LINE__ << llendl;
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
#define llassert(func) llassert_always(func)
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
/**
|
||||
* @file llfasttimer.cpp
|
||||
* @brief Implementation of the fast timer.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2004-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llfasttimer.h"
|
||||
#include "llmemory.h"
|
||||
#include "llprocessor.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "lltimer.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// statics
|
||||
|
||||
LLFastTimer::EFastTimerType LLFastTimer::sCurType = LLFastTimer::FTM_OTHER;
|
||||
int LLFastTimer::sCurDepth = 0;
|
||||
U64 LLFastTimer::sStart[LLFastTimer::FTM_MAX_DEPTH];
|
||||
U64 LLFastTimer::sCounter[LLFastTimer::FTM_NUM_TYPES];
|
||||
U64 LLFastTimer::sCountHistory[LLFastTimer::FTM_HISTORY_NUM][LLFastTimer::FTM_NUM_TYPES];
|
||||
U64 LLFastTimer::sCountAverage[LLFastTimer::FTM_NUM_TYPES];
|
||||
U64 LLFastTimer::sCalls[LLFastTimer::FTM_NUM_TYPES];
|
||||
U64 LLFastTimer::sCallHistory[LLFastTimer::FTM_HISTORY_NUM][LLFastTimer::FTM_NUM_TYPES];
|
||||
U64 LLFastTimer::sCallAverage[LLFastTimer::FTM_NUM_TYPES];
|
||||
S32 LLFastTimer::sCurFrameIndex = -1;
|
||||
S32 LLFastTimer::sLastFrameIndex = -1;
|
||||
int LLFastTimer::sPauseHistory = 0;
|
||||
int LLFastTimer::sResetHistory = 0;
|
||||
|
||||
U64 LLFastTimer::sClockResolution = calc_clock_frequency(50U); // Resolution of get_clock_count()
|
||||
|
||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
||||
{
|
||||
return sClockResolution >> 8;
|
||||
}
|
||||
|
||||
void LLFastTimer::reset()
|
||||
{
|
||||
countsPerSecond(); // good place to calculate clock frequency
|
||||
|
||||
if (sCurDepth != 0)
|
||||
{
|
||||
llerrs << "LLFastTimer::Reset() when sCurDepth != 0" << llendl;
|
||||
}
|
||||
if (sPauseHistory)
|
||||
{
|
||||
sResetHistory = 1;
|
||||
}
|
||||
else if (sResetHistory)
|
||||
{
|
||||
sCurFrameIndex = -1;
|
||||
sResetHistory = 0;
|
||||
}
|
||||
else if (sCurFrameIndex >= 0)
|
||||
{
|
||||
int hidx = sCurFrameIndex % FTM_HISTORY_NUM;
|
||||
for (S32 i=0; i<FTM_NUM_TYPES; i++)
|
||||
{
|
||||
sCountHistory[hidx][i] = sCounter[i];
|
||||
sCountAverage[i] = (sCountAverage[i]*sCurFrameIndex + sCounter[i]) / (sCurFrameIndex+1);
|
||||
sCallHistory[hidx][i] = sCalls[i];
|
||||
sCallAverage[i] = (sCallAverage[i]*sCurFrameIndex + sCalls[i]) / (sCurFrameIndex+1);
|
||||
}
|
||||
sLastFrameIndex = sCurFrameIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (S32 i=0; i<FTM_NUM_TYPES; i++)
|
||||
{
|
||||
sCountAverage[i] = 0;
|
||||
sCallAverage[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sCurFrameIndex++;
|
||||
|
||||
for (S32 i=0; i<FTM_NUM_TYPES; i++)
|
||||
{
|
||||
sCounter[i] = 0;
|
||||
sCalls[i] = 0;
|
||||
}
|
||||
sCurDepth = 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Important note: These implementations must be FAST!
|
||||
//
|
||||
|
||||
// shift off lower 8 bits for lower resolution but longer term timing
|
||||
// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
|
||||
|
||||
//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
|
||||
// On windows these use QueryPerformanceCounter, which is arguably fine and also works on amd architectures.
|
||||
U32 LLFastTimer::getCPUClockCount32()
|
||||
{
|
||||
return get_clock_count() >> 8;
|
||||
}
|
||||
|
||||
U64 LLFastTimer::getCPUClockCount64()
|
||||
{
|
||||
return get_clock_count();
|
||||
}
|
||||
@@ -1,294 +1,35 @@
|
||||
/**
|
||||
/**
|
||||
* @file llfasttimer.h
|
||||
* @brief Declaration of a fast timer.
|
||||
* @brief Inline implementations of fast timers.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2004-2009, Linden Research, Inc.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFASTTIMER_H
|
||||
#define LL_LLFASTTIMER_H
|
||||
#ifndef LL_FASTTIMER_H
|
||||
#define LL_FASTTIMER_H
|
||||
|
||||
#define FAST_TIMER_ON 1
|
||||
|
||||
|
||||
class LL_COMMON_API LLFastTimer
|
||||
{
|
||||
public:
|
||||
enum EFastTimerType
|
||||
{
|
||||
// high level
|
||||
FTM_FRAME,
|
||||
FTM_UPDATE,
|
||||
FTM_RENDER,
|
||||
FTM_SWAP,
|
||||
FTM_CLIENT_COPY,
|
||||
FTM_IDLE,
|
||||
FTM_SLEEP,
|
||||
|
||||
// general timers
|
||||
FT_STRING_FORMAT,
|
||||
|
||||
// common messaging components
|
||||
FTM_PUMP,
|
||||
FTM_CURL,
|
||||
FTM_PUMPIO,
|
||||
|
||||
// common simulation components
|
||||
FTM_UPDATE_ANIMATION,
|
||||
FTM_UPDATE_TERRAIN,
|
||||
FTM_UPDATE_PRIMITIVES,
|
||||
FTM_UPDATE_PARTICLES,
|
||||
FTM_SIMULATE_PARTICLES,
|
||||
FTM_UPDATE_SKY,
|
||||
FTM_UPDATE_TEXTURES,
|
||||
FTM_UPDATE_WLPARAM,
|
||||
FTM_UPDATE_WATER,
|
||||
FTM_UPDATE_CLOUDS,
|
||||
FTM_UPDATE_GRASS,
|
||||
FTM_UPDATE_TREE,
|
||||
FTM_UPDATE_AVATAR,
|
||||
#if MESH_ENABLED
|
||||
FTM_UPDATE_RIGGED_VOLUME,
|
||||
FTM_SKIN_RIGGED,
|
||||
FTM_RIGGED_OCTREE,
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// common render components
|
||||
FTM_SHADOW_GEOMETRY,
|
||||
FTM_SHADOW_RENDER,
|
||||
FTM_SHADOW_TERRAIN,
|
||||
FTM_SHADOW_AVATAR,
|
||||
FTM_SHADOW_SIMPLE,
|
||||
FTM_SHADOW_ALPHA,
|
||||
FTM_SHADOW_TREE,
|
||||
|
||||
FTM_RENDER_GEOMETRY,
|
||||
FTM_RENDER_TERRAIN,
|
||||
FTM_RENDER_SIMPLE,
|
||||
FTM_RENDER_FULLBRIGHT,
|
||||
FTM_RENDER_GLOW,
|
||||
FTM_RENDER_GRASS,
|
||||
FTM_RENDER_INVISIBLE,
|
||||
FTM_RENDER_SHINY,
|
||||
FTM_RENDER_BUMP,
|
||||
FTM_RENDER_TREES,
|
||||
FTM_RENDER_CHARACTERS,
|
||||
FTM_RENDER_OCCLUSION,
|
||||
FTM_RENDER_ALPHA,
|
||||
FTM_RENDER_CLOUDS,
|
||||
FTM_RENDER_HUD,
|
||||
FTM_RENDER_PARTICLES,
|
||||
FTM_RENDER_WATER,
|
||||
FTM_RENDER_WL_SKY,
|
||||
FTM_RENDER_FAKE_VBO_UPDATE,
|
||||
FTM_RENDER_TIMER,
|
||||
FTM_RENDER_UI,
|
||||
FTM_RENDER_BLOOM,
|
||||
FTM_RENDER_BLOOM_FBO,
|
||||
FTM_RENDER_FONTS,
|
||||
|
||||
// deferred rendering
|
||||
FTM_RENDER_DEFERRED,
|
||||
FTM_BIND_DEFERRED,
|
||||
FTM_SUN_SHADOW,
|
||||
FTM_SOFTEN_SHADOW,
|
||||
FTM_EDGE_DETECTION,
|
||||
FTM_GI_TRACE,
|
||||
FTM_GI_GATHER,
|
||||
FTM_ATMOSPHERICS,
|
||||
FTM_LOCAL_LIGHTS,
|
||||
FTM_FULLSCREEN_LIGHTS,
|
||||
FTM_PROJECTORS,
|
||||
FTM_POST,
|
||||
|
||||
FTM_VISIBLE_CLOUD,
|
||||
|
||||
// newview specific
|
||||
FTM_MESSAGES,
|
||||
FTM_MOUSEHANDLER,
|
||||
FTM_KEYHANDLER,
|
||||
FTM_REBUILD,
|
||||
FTM_STATESORT,
|
||||
FTM_STATESORT_DRAWABLE,
|
||||
FTM_STATESORT_POSTSORT,
|
||||
#if MESH_ENABLED
|
||||
FTM_MESH_UPDATE,
|
||||
FTM_MESH_LOCK1,
|
||||
FTM_MESH_LOCK2,
|
||||
FTM_LOAD_MESH_LOD,
|
||||
#endif //MESH_ENABLED
|
||||
FTM_REBUILD_VBO,
|
||||
FTM_REBUILD_VOLUME_VB,
|
||||
FTM_REBUILD_BRIDGE_VB,
|
||||
FTM_REBUILD_HUD_VB,
|
||||
FTM_REBUILD_TERRAIN_VB,
|
||||
FTM_REBUILD_WATER_VB,
|
||||
FTM_REBUILD_TREE_VB,
|
||||
FTM_REBUILD_PARTICLE_VB,
|
||||
FTM_REBUILD_CLOUD_VB,
|
||||
FTM_REBUILD_GRASS_VB,
|
||||
FTM_REBUILD_NONE_VB,
|
||||
FTM_REBUILD_OCCLUSION_VB,
|
||||
FTM_POOLS,
|
||||
FTM_POOLRENDER,
|
||||
FTM_IDLE_CB,
|
||||
FTM_WORLD_UPDATE,
|
||||
FTM_UPDATE_MOVE,
|
||||
FTM_OCTREE_BALANCE,
|
||||
FTM_UPDATE_LIGHTS,
|
||||
FTM_CULL,
|
||||
FTM_CULL_REBOUND,
|
||||
FTM_FRUSTUM_CULL,
|
||||
FTM_GEO_UPDATE,
|
||||
FTM_GEO_RESERVE,
|
||||
FTM_GEO_LIGHT,
|
||||
FTM_GEO_SHADOW,
|
||||
FTM_GEO_SKY,
|
||||
FTM_GEN_VOLUME,
|
||||
FTM_GEN_TRIANGLES,
|
||||
FTM_GEN_FLEX,
|
||||
FTM_AUDIO_UPDATE,
|
||||
FTM_RESET_DRAWORDER,
|
||||
FTM_OBJECTLIST_UPDATE,
|
||||
FTM_AVATAR_UPDATE,
|
||||
FTM_JOINT_UPDATE,
|
||||
FTM_ATTACHMENT_UPDATE,
|
||||
FTM_LOD_UPDATE,
|
||||
FTM_REGION_UPDATE,
|
||||
FTM_CLEANUP,
|
||||
FTM_NETWORK,
|
||||
FTM_IDLE_NETWORK,
|
||||
FTM_CREATE_OBJECT,
|
||||
FTM_LOAD_AVATAR,
|
||||
FTM_PROCESS_MESSAGES,
|
||||
FTM_PROCESS_OBJECTS,
|
||||
FTM_PROCESS_IMAGES,
|
||||
FTM_IMAGE_UPDATE,
|
||||
FTM_IMAGE_CREATE,
|
||||
FTM_IMAGE_DECODE,
|
||||
FTM_IMAGE_READBACK,
|
||||
FTM_IMAGE_MARK_DIRTY,
|
||||
FTM_PIPELINE,
|
||||
FTM_VFILE_WAIT,
|
||||
FTM_FLEXIBLE_UPDATE,
|
||||
FTM_OCCLUSION_READBACK,
|
||||
FTM_HUD_EFFECTS,
|
||||
FTM_HUD_UPDATE,
|
||||
FTM_INVENTORY,
|
||||
FTM_AUTO_SELECT,
|
||||
FTM_ARRANGE,
|
||||
FTM_FILTER,
|
||||
FTM_REFRESH,
|
||||
FTM_SORT,
|
||||
FTM_PICK,
|
||||
FTM_STATEMACHINE,
|
||||
|
||||
// Temp
|
||||
FTM_TEMP1,
|
||||
FTM_TEMP2,
|
||||
FTM_TEMP3,
|
||||
FTM_TEMP4,
|
||||
FTM_TEMP5,
|
||||
FTM_TEMP6,
|
||||
FTM_TEMP7,
|
||||
FTM_TEMP8,
|
||||
|
||||
FTM_OTHER, // Special, used by display code
|
||||
|
||||
FTM_NUM_TYPES
|
||||
};
|
||||
enum { FTM_HISTORY_NUM = 60 };
|
||||
enum { FTM_MAX_DEPTH = 64 };
|
||||
|
||||
public:
|
||||
static EFastTimerType sCurType;
|
||||
|
||||
LLFastTimer(EFastTimerType type)
|
||||
{
|
||||
#if FAST_TIMER_ON
|
||||
mType = type;
|
||||
sCurType = type;
|
||||
// These don't get counted, because they use CPU clockticks
|
||||
//gTimerBins[gCurTimerBin]++;
|
||||
//LLTimer::sNumTimerCalls++;
|
||||
|
||||
U64 cpu_clocks = getCPUClockCount32();
|
||||
|
||||
sStart[sCurDepth] = cpu_clocks;
|
||||
sCurDepth++;
|
||||
#endif
|
||||
};
|
||||
~LLFastTimer()
|
||||
{
|
||||
#if FAST_TIMER_ON
|
||||
U64 end,delta;
|
||||
int i;
|
||||
|
||||
// These don't get counted, because they use CPU clockticks
|
||||
//gTimerBins[gCurTimerBin]++;
|
||||
//LLTimer::sNumTimerCalls++;
|
||||
end = getCPUClockCount32();
|
||||
|
||||
sCurDepth--;
|
||||
delta = end - sStart[sCurDepth];
|
||||
sCounter[mType] += delta;
|
||||
sCalls[mType]++;
|
||||
// Subtract delta from parents
|
||||
for (i=0; i<sCurDepth; i++)
|
||||
sStart[i] += delta;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void reset();
|
||||
static U64 countsPerSecond();
|
||||
|
||||
public:
|
||||
static int sCurDepth;
|
||||
static U64 sStart[FTM_MAX_DEPTH];
|
||||
static U64 sCounter[FTM_NUM_TYPES];
|
||||
static U64 sCalls[FTM_NUM_TYPES];
|
||||
static U64 sCountAverage[FTM_NUM_TYPES];
|
||||
static U64 sCallAverage[FTM_NUM_TYPES];
|
||||
static U64 sCountHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES];
|
||||
static U64 sCallHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES];
|
||||
|
||||
static int sPauseHistory;
|
||||
static int sResetHistory;
|
||||
|
||||
static U32 getCPUClockCount32();
|
||||
static U64 getCPUClockCount64();
|
||||
|
||||
static U64 sClockResolution;
|
||||
static S32 sCurFrameIndex;
|
||||
static S32 sLastFrameIndex;
|
||||
|
||||
EFastTimerType mType;
|
||||
};
|
||||
// Implementation of getCPUClockCount32() and getCPUClockCount64 are now in llfastertimer_class.cpp.
|
||||
|
||||
// pull in the actual class definition
|
||||
#include "llfasttimer_class.h"
|
||||
|
||||
#endif // LL_LLFASTTIMER_H
|
||||
|
||||
812
indra/llcommon/llfasttimer_class.cpp
Normal file
812
indra/llcommon/llfasttimer_class.cpp
Normal file
@@ -0,0 +1,812 @@
|
||||
/**
|
||||
* @file llfasttimer_class.cpp
|
||||
* @brief Implementation of the fast timer.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llprocessor.h"
|
||||
#include "llsingleton.h"
|
||||
#include "lltreeiterators.h"
|
||||
#include "llsdserialize.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
|
||||
#if LL_WINDOWS
|
||||
#include "lltimer.h"
|
||||
#elif LL_LINUX || LL_SOLARIS
|
||||
#include <sys/time.h>
|
||||
#include <sched.h>
|
||||
#include "lltimer.h"
|
||||
#elif LL_DARWIN
|
||||
#include <sys/time.h>
|
||||
#include "lltimer.h" // get_clock_count()
|
||||
#else
|
||||
#error "architecture not supported"
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// statics
|
||||
|
||||
S32 LLFastTimer::sCurFrameIndex = -1;
|
||||
S32 LLFastTimer::sLastFrameIndex = -1;
|
||||
U64 LLFastTimer::sLastFrameTime = LLFastTimer::getCPUClockCount64();
|
||||
bool LLFastTimer::sPauseHistory = 0;
|
||||
bool LLFastTimer::sResetHistory = 0;
|
||||
LLFastTimer::CurTimerData LLFastTimer::sCurTimerData;
|
||||
BOOL LLFastTimer::sLog = FALSE;
|
||||
std::string LLFastTimer::sLogName = "";
|
||||
BOOL LLFastTimer::sMetricLog = FALSE;
|
||||
LLMutex* LLFastTimer::sLogLock = NULL;
|
||||
std::queue<LLSD> LLFastTimer::sLogQueue;
|
||||
|
||||
#define USE_RDTSC 0
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution
|
||||
#else
|
||||
U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution
|
||||
#endif
|
||||
|
||||
std::vector<LLFastTimer::FrameState>* LLFastTimer::sTimerInfos = NULL;
|
||||
U64 LLFastTimer::sTimerCycles = 0;
|
||||
U32 LLFastTimer::sTimerCalls = 0;
|
||||
|
||||
|
||||
// FIXME: move these declarations to the relevant modules
|
||||
|
||||
// helper functions
|
||||
typedef LLTreeDFSPostIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_bottom_up_iterator_t;
|
||||
|
||||
static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& id)
|
||||
{
|
||||
return timer_tree_bottom_up_iterator_t(&id,
|
||||
boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1),
|
||||
boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
|
||||
}
|
||||
|
||||
static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
|
||||
{
|
||||
return timer_tree_bottom_up_iterator_t();
|
||||
}
|
||||
|
||||
typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_dfs_iterator_t;
|
||||
|
||||
|
||||
static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id)
|
||||
{
|
||||
return timer_tree_dfs_iterator_t(&id,
|
||||
boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1),
|
||||
boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
|
||||
}
|
||||
|
||||
static timer_tree_dfs_iterator_t end_timer_tree()
|
||||
{
|
||||
return timer_tree_dfs_iterator_t();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// factory class that creates NamedTimers via static DeclareTimer objects
|
||||
class NamedTimerFactory : public LLSingleton<NamedTimerFactory>
|
||||
{
|
||||
public:
|
||||
NamedTimerFactory()
|
||||
: mActiveTimerRoot(NULL),
|
||||
mTimerRoot(NULL),
|
||||
mAppTimer(NULL),
|
||||
mRootFrameState(NULL)
|
||||
{}
|
||||
|
||||
/*virtual */ void initSingleton()
|
||||
{
|
||||
mTimerRoot = new LLFastTimer::NamedTimer("root");
|
||||
|
||||
mActiveTimerRoot = new LLFastTimer::NamedTimer("Frame");
|
||||
mActiveTimerRoot->setCollapsed(false);
|
||||
|
||||
mRootFrameState = new LLFastTimer::FrameState(mActiveTimerRoot);
|
||||
mRootFrameState->mParent = &mTimerRoot->getFrameState();
|
||||
mActiveTimerRoot->setParent(mTimerRoot);
|
||||
|
||||
mAppTimer = new LLFastTimer(mRootFrameState);
|
||||
}
|
||||
|
||||
~NamedTimerFactory()
|
||||
{
|
||||
std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer());
|
||||
|
||||
delete mAppTimer;
|
||||
delete mActiveTimerRoot;
|
||||
delete mTimerRoot;
|
||||
delete mRootFrameState;
|
||||
}
|
||||
|
||||
LLFastTimer::NamedTimer& createNamedTimer(const std::string& name)
|
||||
{
|
||||
timer_map_t::iterator found_it = mTimers.find(name);
|
||||
if (found_it != mTimers.end())
|
||||
{
|
||||
return *found_it->second;
|
||||
}
|
||||
|
||||
LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name);
|
||||
timer->setParent(mTimerRoot);
|
||||
mTimers.insert(std::make_pair(name, timer));
|
||||
|
||||
return *timer;
|
||||
}
|
||||
|
||||
LLFastTimer::NamedTimer* getTimerByName(const std::string& name)
|
||||
{
|
||||
timer_map_t::iterator found_it = mTimers.find(name);
|
||||
if (found_it != mTimers.end())
|
||||
{
|
||||
return found_it->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLFastTimer::NamedTimer* getActiveRootTimer() { return mActiveTimerRoot; }
|
||||
LLFastTimer::NamedTimer* getRootTimer() { return mTimerRoot; }
|
||||
const LLFastTimer* getAppTimer() { return mAppTimer; }
|
||||
LLFastTimer::FrameState& getRootFrameState() { return *mRootFrameState; }
|
||||
|
||||
typedef std::map<std::string, LLFastTimer::NamedTimer*> timer_map_t;
|
||||
timer_map_t::iterator beginTimers() { return mTimers.begin(); }
|
||||
timer_map_t::iterator endTimers() { return mTimers.end(); }
|
||||
S32 timerCount() { return mTimers.size(); }
|
||||
|
||||
private:
|
||||
timer_map_t mTimers;
|
||||
|
||||
LLFastTimer::NamedTimer* mActiveTimerRoot;
|
||||
LLFastTimer::NamedTimer* mTimerRoot;
|
||||
LLFastTimer* mAppTimer;
|
||||
LLFastTimer::FrameState* mRootFrameState;
|
||||
};
|
||||
|
||||
void update_cached_pointers_if_changed()
|
||||
{
|
||||
// detect when elements have moved and update cached pointers
|
||||
static LLFastTimer::FrameState* sFirstTimerAddress = NULL;
|
||||
if (&*(LLFastTimer::getFrameStateList().begin()) != sFirstTimerAddress)
|
||||
{
|
||||
LLFastTimer::DeclareTimer::updateCachedPointers();
|
||||
}
|
||||
sFirstTimerAddress = &*(LLFastTimer::getFrameStateList().begin());
|
||||
}
|
||||
|
||||
LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open )
|
||||
: mTimer(NamedTimerFactory::instance().createNamedTimer(name))
|
||||
{
|
||||
mTimer.setCollapsed(!open);
|
||||
mFrameState = &mTimer.getFrameState();
|
||||
update_cached_pointers_if_changed();
|
||||
}
|
||||
|
||||
LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name)
|
||||
: mTimer(NamedTimerFactory::instance().createNamedTimer(name))
|
||||
{
|
||||
mFrameState = &mTimer.getFrameState();
|
||||
update_cached_pointers_if_changed();
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFastTimer::DeclareTimer::updateCachedPointers()
|
||||
{
|
||||
// propagate frame state pointers to timer declarations
|
||||
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
{
|
||||
// update cached pointer
|
||||
it->mFrameState = &it->mTimer.getFrameState();
|
||||
}
|
||||
|
||||
// also update frame states of timers on stack
|
||||
LLFastTimer* cur_timerp = LLFastTimer::sCurTimerData.mCurTimer;
|
||||
while(cur_timerp->mLastTimerData.mCurTimer != cur_timerp)
|
||||
{
|
||||
cur_timerp->mFrameState = &cur_timerp->mFrameState->mTimer->getFrameState();
|
||||
cur_timerp = cur_timerp->mLastTimerData.mCurTimer;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
|
||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
||||
{
|
||||
return sClockResolution >> 8;
|
||||
}
|
||||
#else // windows or x86-mac or x86-linux or x86-solaris
|
||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
||||
{
|
||||
#if USE_RDTSC || !LL_WINDOWS
|
||||
//getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
|
||||
static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
|
||||
|
||||
// we drop the low-order byte in our timers, so report a lower frequency
|
||||
#else
|
||||
// If we're not using RDTSC, each fasttimer tick is just a performance counter tick.
|
||||
// Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency())
|
||||
// since that would change displayed MHz stats for CPUs
|
||||
static bool firstcall = true;
|
||||
static U64 sCPUClockFrequency;
|
||||
if (firstcall)
|
||||
{
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);
|
||||
firstcall = false;
|
||||
}
|
||||
#endif
|
||||
return sCPUClockFrequency >> 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
LLFastTimer::FrameState::FrameState(LLFastTimer::NamedTimer* timerp)
|
||||
: mActiveCount(0),
|
||||
mCalls(0),
|
||||
mSelfTimeCounter(0),
|
||||
mParent(NULL),
|
||||
mLastCaller(NULL),
|
||||
mMoveUpTree(false),
|
||||
mTimer(timerp)
|
||||
{}
|
||||
|
||||
|
||||
LLFastTimer::NamedTimer::NamedTimer(const std::string& name)
|
||||
: mName(name),
|
||||
mCollapsed(true),
|
||||
mParent(NULL),
|
||||
mTotalTimeCounter(0),
|
||||
mCountAverage(0),
|
||||
mCallAverage(0),
|
||||
mNeedsSorting(false)
|
||||
{
|
||||
info_list_t& frame_state_list = getFrameStateList();
|
||||
mFrameStateIndex = frame_state_list.size();
|
||||
getFrameStateList().push_back(FrameState(this));
|
||||
|
||||
mCountHistory = new U32[HISTORY_NUM];
|
||||
memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
|
||||
mCallHistory = new U32[HISTORY_NUM];
|
||||
memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
|
||||
}
|
||||
|
||||
LLFastTimer::NamedTimer::~NamedTimer()
|
||||
{
|
||||
delete[] mCountHistory;
|
||||
delete[] mCallHistory;
|
||||
}
|
||||
|
||||
std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx)
|
||||
{
|
||||
F64 ms_multiplier = 1000.0 / (F64)LLFastTimer::countsPerSecond();
|
||||
if (history_idx < 0)
|
||||
{
|
||||
// by default, show average number of call
|
||||
return llformat("%s (%.2f ms, %d calls)", getName().c_str(), (F32)((F32)getCountAverage() * ms_multiplier), (S32)getCallAverage());
|
||||
}
|
||||
else
|
||||
{
|
||||
return llformat("%s (%.2f ms, %d calls)", getName().c_str(), (F32)((F32)getHistoricalCount(history_idx) * ms_multiplier), (S32)getHistoricalCalls(history_idx));
|
||||
}
|
||||
}
|
||||
|
||||
void LLFastTimer::NamedTimer::setParent(NamedTimer* parent)
|
||||
{
|
||||
llassert_always(parent != this);
|
||||
llassert_always(parent != NULL);
|
||||
|
||||
if (mParent)
|
||||
{
|
||||
// subtract our accumulated from previous parent
|
||||
for (S32 i = 0; i < HISTORY_NUM; i++)
|
||||
{
|
||||
mParent->mCountHistory[i] -= mCountHistory[i];
|
||||
}
|
||||
|
||||
// subtract average timing from previous parent
|
||||
mParent->mCountAverage -= mCountAverage;
|
||||
|
||||
std::vector<NamedTimer*>& children = mParent->getChildren();
|
||||
std::vector<NamedTimer*>::iterator found_it = std::find(children.begin(), children.end(), this);
|
||||
if (found_it != children.end())
|
||||
{
|
||||
children.erase(found_it);
|
||||
}
|
||||
}
|
||||
|
||||
mParent = parent;
|
||||
if (parent)
|
||||
{
|
||||
getFrameState().mParent = &parent->getFrameState();
|
||||
parent->getChildren().push_back(this);
|
||||
parent->mNeedsSorting = true;
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLFastTimer::NamedTimer::getDepth()
|
||||
{
|
||||
S32 depth = 0;
|
||||
NamedTimer* timerp = mParent;
|
||||
while(timerp)
|
||||
{
|
||||
depth++;
|
||||
timerp = timerp->mParent;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFastTimer::NamedTimer::processTimes()
|
||||
{
|
||||
if (sCurFrameIndex < 0) return;
|
||||
|
||||
buildHierarchy();
|
||||
accumulateTimings();
|
||||
}
|
||||
|
||||
// sort timer info structs by depth first traversal order
|
||||
struct SortTimersDFS
|
||||
{
|
||||
bool operator()(const LLFastTimer::FrameState& i1, const LLFastTimer::FrameState& i2)
|
||||
{
|
||||
return i1.mTimer->getFrameStateIndex() < i2.mTimer->getFrameStateIndex();
|
||||
}
|
||||
};
|
||||
|
||||
// sort child timers by name
|
||||
struct SortTimerByName
|
||||
{
|
||||
bool operator()(const LLFastTimer::NamedTimer* i1, const LLFastTimer::NamedTimer* i2)
|
||||
{
|
||||
return i1->getName() < i2->getName();
|
||||
}
|
||||
};
|
||||
|
||||
//static
|
||||
void LLFastTimer::NamedTimer::buildHierarchy()
|
||||
{
|
||||
if (sCurFrameIndex < 0 ) return;
|
||||
|
||||
// set up initial tree
|
||||
{
|
||||
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
{
|
||||
NamedTimer& timer = *it;
|
||||
if (&timer == NamedTimerFactory::instance().getRootTimer()) continue;
|
||||
|
||||
// bootstrap tree construction by attaching to last timer to be on stack
|
||||
// when this timer was called
|
||||
if (timer.getFrameState().mLastCaller && timer.mParent == NamedTimerFactory::instance().getRootTimer())
|
||||
{
|
||||
timer.setParent(timer.getFrameState().mLastCaller->mTimer);
|
||||
// no need to push up tree on first use, flag can be set spuriously
|
||||
timer.getFrameState().mMoveUpTree = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bump timers up tree if they've been flagged as being in the wrong place
|
||||
// do this in a bottom up order to promote descendants first before promoting ancestors
|
||||
// this preserves partial order derived from current frame's observations
|
||||
for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer());
|
||||
it != end_timer_tree_bottom_up();
|
||||
++it)
|
||||
{
|
||||
NamedTimer* timerp = *it;
|
||||
// skip root timer
|
||||
if (timerp == NamedTimerFactory::instance().getRootTimer()) continue;
|
||||
|
||||
if (timerp->getFrameState().mMoveUpTree)
|
||||
{
|
||||
// since ancestors have already been visited, reparenting won't affect tree traversal
|
||||
//step up tree, bringing our descendants with us
|
||||
//llinfos << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() <<
|
||||
// " to child of " << timerp->getParent()->getParent()->getName() << llendl;
|
||||
timerp->setParent(timerp->getParent()->getParent());
|
||||
timerp->getFrameState().mMoveUpTree = false;
|
||||
|
||||
// don't bubble up any ancestors until descendants are done bubbling up
|
||||
it.skipAncestors();
|
||||
}
|
||||
}
|
||||
|
||||
// sort timers by time last called, so call graph makes sense
|
||||
for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
|
||||
it != end_timer_tree();
|
||||
++it)
|
||||
{
|
||||
NamedTimer* timerp = (*it);
|
||||
if (timerp->mNeedsSorting)
|
||||
{
|
||||
std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName());
|
||||
}
|
||||
timerp->mNeedsSorting = false;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFastTimer::NamedTimer::accumulateTimings()
|
||||
{
|
||||
U32 cur_time = getCPUClockCount32();
|
||||
|
||||
// walk up stack of active timers and accumulate current time while leaving timing structures active
|
||||
LLFastTimer* cur_timer = sCurTimerData.mCurTimer;
|
||||
// root defined by parent pointing to self
|
||||
CurTimerData* cur_data = &sCurTimerData;
|
||||
while(cur_timer->mLastTimerData.mCurTimer != cur_timer)
|
||||
{
|
||||
U32 cumulative_time_delta = cur_time - cur_timer->mStartTime;
|
||||
U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime;
|
||||
cur_data->mChildTime = 0;
|
||||
cur_timer->mFrameState->mSelfTimeCounter += self_time_delta;
|
||||
cur_timer->mStartTime = cur_time;
|
||||
|
||||
cur_data = &cur_timer->mLastTimerData;
|
||||
cur_data->mChildTime += cumulative_time_delta;
|
||||
|
||||
cur_timer = cur_timer->mLastTimerData.mCurTimer;
|
||||
}
|
||||
|
||||
// traverse tree in DFS post order, or bottom up
|
||||
for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getActiveRootTimer());
|
||||
it != end_timer_tree_bottom_up();
|
||||
++it)
|
||||
{
|
||||
NamedTimer* timerp = (*it);
|
||||
timerp->mTotalTimeCounter = timerp->getFrameState().mSelfTimeCounter;
|
||||
for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it)
|
||||
{
|
||||
timerp->mTotalTimeCounter += (*child_it)->mTotalTimeCounter;
|
||||
}
|
||||
|
||||
S32 cur_frame = sCurFrameIndex;
|
||||
if (cur_frame >= 0)
|
||||
{
|
||||
// update timer history
|
||||
int hidx = cur_frame % HISTORY_NUM;
|
||||
|
||||
timerp->mCountHistory[hidx] = timerp->mTotalTimeCounter;
|
||||
timerp->mCountAverage = ((U64)timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1);
|
||||
timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls;
|
||||
timerp->mCallAverage = ((U64)timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U32 LLFastTimer::NamedTimer::getCountAverage() const
|
||||
{
|
||||
return mCountAverage;// (sCurFrameIndex <= 0 || mCountAverage <= 0) ? 0 : mCountAverage / llmin(sCurFrameIndex,(S32)HISTORY_NUM);
|
||||
}
|
||||
U32 LLFastTimer::NamedTimer::getCallAverage() const
|
||||
{
|
||||
return mCallAverage;// (sCurFrameIndex <= 0 || mCallAverage <= 0) ? 0 : mCallAverage / llmin(sCurFrameIndex,(S32)HISTORY_NUM);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFastTimer::NamedTimer::resetFrame()
|
||||
{
|
||||
if (sLog)
|
||||
{ //output current frame counts to performance log
|
||||
|
||||
static S32 call_count = 0;
|
||||
if (call_count % 100 == 0)
|
||||
{
|
||||
llinfos << "countsPerSecond (32 bit): " << countsPerSecond() << llendl;
|
||||
llinfos << "get_clock_count (64 bit): " << get_clock_count() << llendl;
|
||||
llinfos << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << llendl;
|
||||
llinfos << "getCPUClockCount32() " << getCPUClockCount32() << llendl;
|
||||
llinfos << "getCPUClockCount64() " << getCPUClockCount64() << llendl;
|
||||
llinfos << "elapsed sec " << ((F64)getCPUClockCount64())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << llendl;
|
||||
}
|
||||
call_count++;
|
||||
|
||||
F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency
|
||||
|
||||
F64 total_time = 0;
|
||||
LLSD sd;
|
||||
|
||||
{
|
||||
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
{
|
||||
NamedTimer& timer = *it;
|
||||
FrameState& info = timer.getFrameState();
|
||||
sd[timer.getName()]["Time"] = (LLSD::Real) (info.mSelfTimeCounter*iclock_freq);
|
||||
sd[timer.getName()]["Calls"] = (LLSD::Integer) info.mCalls;
|
||||
|
||||
// computing total time here because getting the root timer's getCountHistory
|
||||
// doesn't work correctly on the first frame
|
||||
total_time = total_time + info.mSelfTimeCounter * iclock_freq;
|
||||
}
|
||||
}
|
||||
|
||||
sd["Total"]["Time"] = (LLSD::Real) total_time;
|
||||
sd["Total"]["Calls"] = (LLSD::Integer) 1;
|
||||
|
||||
{
|
||||
LLMutexLock lock(sLogLock);
|
||||
sLogQueue.push(sd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// tag timers by position in depth first traversal of tree
|
||||
S32 index = 0;
|
||||
for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
|
||||
it != end_timer_tree();
|
||||
++it)
|
||||
{
|
||||
NamedTimer* timerp = (*it);
|
||||
|
||||
timerp->mFrameStateIndex = index;
|
||||
index++;
|
||||
|
||||
llassert_always(timerp->mFrameStateIndex < (S32)getFrameStateList().size());
|
||||
}
|
||||
|
||||
// sort timers by DFS traversal order to improve cache coherency
|
||||
std::sort(getFrameStateList().begin(), getFrameStateList().end(), SortTimersDFS());
|
||||
|
||||
// update pointers into framestatelist now that we've sorted it
|
||||
DeclareTimer::updateCachedPointers();
|
||||
|
||||
// reset for next frame
|
||||
{
|
||||
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
{
|
||||
NamedTimer& timer = *it;
|
||||
|
||||
FrameState& info = timer.getFrameState();
|
||||
info.mSelfTimeCounter = 0;
|
||||
info.mCalls = 0;
|
||||
info.mLastCaller = NULL;
|
||||
info.mMoveUpTree = false;
|
||||
// update parent pointer in timer state struct
|
||||
if (timer.mParent)
|
||||
{
|
||||
info.mParent = &timer.mParent->getFrameState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//sTimerCycles = 0;
|
||||
//sTimerCalls = 0;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFastTimer::NamedTimer::reset()
|
||||
{
|
||||
resetFrame(); // reset frame data
|
||||
|
||||
// walk up stack of active timers and reset start times to current time
|
||||
// effectively zeroing out any accumulated time
|
||||
U32 cur_time = getCPUClockCount32();
|
||||
|
||||
// root defined by parent pointing to self
|
||||
CurTimerData* cur_data = &sCurTimerData;
|
||||
LLFastTimer* cur_timer = cur_data->mCurTimer;
|
||||
while(cur_timer->mLastTimerData.mCurTimer != cur_timer)
|
||||
{
|
||||
cur_timer->mStartTime = cur_time;
|
||||
cur_data->mChildTime = 0;
|
||||
|
||||
cur_data = &cur_timer->mLastTimerData;
|
||||
cur_timer = cur_data->mCurTimer;
|
||||
}
|
||||
|
||||
// reset all history
|
||||
{
|
||||
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
{
|
||||
NamedTimer& timer = *it;
|
||||
if (&timer != NamedTimerFactory::instance().getRootTimer())
|
||||
{
|
||||
timer.setParent(NamedTimerFactory::instance().getRootTimer());
|
||||
}
|
||||
|
||||
timer.mCountAverage = 0;
|
||||
timer.mCallAverage = 0;
|
||||
memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
|
||||
memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
|
||||
}
|
||||
}
|
||||
|
||||
sLastFrameIndex = 0;
|
||||
sCurFrameIndex = 0;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFastTimer::info_list_t& LLFastTimer::getFrameStateList()
|
||||
{
|
||||
if (!sTimerInfos)
|
||||
{
|
||||
sTimerInfos = new info_list_t();
|
||||
}
|
||||
return *sTimerInfos;
|
||||
}
|
||||
|
||||
|
||||
U32 LLFastTimer::NamedTimer::getHistoricalCount(S32 history_index) const
|
||||
{
|
||||
S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM;
|
||||
return mCountHistory[history_idx];
|
||||
}
|
||||
|
||||
U32 LLFastTimer::NamedTimer::getHistoricalCalls(S32 history_index ) const
|
||||
{
|
||||
S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM;
|
||||
return mCallHistory[history_idx];
|
||||
}
|
||||
|
||||
LLFastTimer::FrameState& LLFastTimer::NamedTimer::getFrameState() const
|
||||
{
|
||||
llassert_always(mFrameStateIndex >= 0);
|
||||
if (this == NamedTimerFactory::instance().getActiveRootTimer())
|
||||
{
|
||||
return NamedTimerFactory::instance().getRootFrameState();
|
||||
}
|
||||
return getFrameStateList()[mFrameStateIndex];
|
||||
}
|
||||
|
||||
// static
|
||||
LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer()
|
||||
{
|
||||
return *NamedTimerFactory::instance().getActiveRootTimer();
|
||||
}
|
||||
|
||||
std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::beginChildren()
|
||||
{
|
||||
return mChildren.begin();
|
||||
}
|
||||
|
||||
std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::endChildren()
|
||||
{
|
||||
return mChildren.end();
|
||||
}
|
||||
|
||||
std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren()
|
||||
{
|
||||
return mChildren;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFastTimer::nextFrame()
|
||||
{
|
||||
countsPerSecond(); // good place to calculate clock frequency
|
||||
U64 frame_time = getCPUClockCount64();
|
||||
if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff)
|
||||
{
|
||||
llinfos << "Slow frame, fast timers inaccurate" << llendl;
|
||||
}
|
||||
|
||||
if (!sPauseHistory)
|
||||
{
|
||||
NamedTimer::processTimes();
|
||||
sLastFrameIndex = sCurFrameIndex++;
|
||||
}
|
||||
|
||||
// get ready for next frame
|
||||
NamedTimer::resetFrame();
|
||||
sLastFrameTime = frame_time;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFastTimer::dumpCurTimes()
|
||||
{
|
||||
// accumulate timings, etc.
|
||||
NamedTimer::processTimes();
|
||||
|
||||
F64 clock_freq = (F64)countsPerSecond();
|
||||
F64 iclock_freq = 1000.0 / clock_freq; // clock_ticks -> milliseconds
|
||||
|
||||
// walk over timers in depth order and output timings
|
||||
for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
|
||||
it != end_timer_tree();
|
||||
++it)
|
||||
{
|
||||
NamedTimer* timerp = (*it);
|
||||
F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq);
|
||||
// Don't bother with really brief times, keep output concise
|
||||
if (total_time_ms < 0.1) continue;
|
||||
|
||||
std::ostringstream out_str;
|
||||
for (S32 i = 0; i < timerp->getDepth(); i++)
|
||||
{
|
||||
out_str << "\t";
|
||||
}
|
||||
|
||||
|
||||
out_str << timerp->getName() << " "
|
||||
<< std::setprecision(3) << total_time_ms << " ms, "
|
||||
<< timerp->getHistoricalCalls(0) << " calls";
|
||||
|
||||
llinfos << out_str.str() << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFastTimer::reset()
|
||||
{
|
||||
NamedTimer::reset();
|
||||
}
|
||||
|
||||
|
||||
//static
|
||||
void LLFastTimer::writeLog(std::ostream& os)
|
||||
{
|
||||
while (!sLogQueue.empty())
|
||||
{
|
||||
LLSD& sd = sLogQueue.front();
|
||||
LLSDSerialize::toXML(sd, os);
|
||||
LLMutexLock lock(sLogLock);
|
||||
sLogQueue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name)
|
||||
{
|
||||
return NamedTimerFactory::instance().getTimerByName(name);
|
||||
}
|
||||
|
||||
LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state)
|
||||
: mFrameState(state)
|
||||
{
|
||||
U32 start_time = getCPUClockCount32();
|
||||
mStartTime = start_time;
|
||||
mFrameState->mActiveCount++;
|
||||
LLFastTimer::sCurTimerData.mCurTimer = this;
|
||||
LLFastTimer::sCurTimerData.mFrameState = mFrameState;
|
||||
LLFastTimer::sCurTimerData.mChildTime = 0;
|
||||
mLastTimerData = LLFastTimer::sCurTimerData;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Important note: These implementations must be FAST!
|
||||
//
|
||||
|
||||
|
||||
//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
|
||||
// These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures.
|
||||
U32 LLFastTimer::getCPUClockCount32()
|
||||
{
|
||||
return (U32)(get_clock_count()>>8);
|
||||
}
|
||||
|
||||
U64 LLFastTimer::getCPUClockCount64()
|
||||
{
|
||||
return get_clock_count();
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
|
||||
#else
|
||||
std::string LLFastTimer::sClockType = "gettimeofday";
|
||||
#endif
|
||||
|
||||
277
indra/llcommon/llfasttimer_class.h
Normal file
277
indra/llcommon/llfasttimer_class.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/**
|
||||
* @file llfasttimer_class.h
|
||||
* @brief Declaration of a fast timer.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_FASTTIMER_CLASS_H
|
||||
#define LL_FASTTIMER_CLASS_H
|
||||
|
||||
#include "llinstancetracker.h"
|
||||
|
||||
#define FAST_TIMER_ON 1
|
||||
#define TIME_FAST_TIMERS 0
|
||||
#define DEBUG_FAST_TIMER_THREADS 1
|
||||
|
||||
class LLMutex;
|
||||
|
||||
#include <queue>
|
||||
#include "llsd.h"
|
||||
|
||||
LL_COMMON_API void assert_main_thread();
|
||||
|
||||
class LL_COMMON_API LLFastTimer
|
||||
{
|
||||
public:
|
||||
class NamedTimer;
|
||||
|
||||
struct LL_COMMON_API FrameState
|
||||
{
|
||||
FrameState(NamedTimer* timerp);
|
||||
|
||||
U32 mSelfTimeCounter;
|
||||
U32 mCalls;
|
||||
FrameState* mParent; // info for caller timer
|
||||
FrameState* mLastCaller; // used to bootstrap tree construction
|
||||
NamedTimer* mTimer;
|
||||
U16 mActiveCount; // number of timers with this ID active on stack
|
||||
bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
|
||||
};
|
||||
|
||||
// stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
|
||||
class LL_COMMON_API NamedTimer
|
||||
: public LLInstanceTracker<NamedTimer>
|
||||
{
|
||||
friend class DeclareTimer;
|
||||
public:
|
||||
~NamedTimer();
|
||||
|
||||
enum { HISTORY_NUM = 300 };
|
||||
|
||||
const std::string& getName() const { return mName; }
|
||||
NamedTimer* getParent() const { return mParent; }
|
||||
void setParent(NamedTimer* parent);
|
||||
S32 getDepth();
|
||||
std::string getToolTip(S32 history_index = -1);
|
||||
|
||||
typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
|
||||
child_const_iter beginChildren();
|
||||
child_const_iter endChildren();
|
||||
std::vector<NamedTimer*>& getChildren();
|
||||
|
||||
void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
|
||||
bool getCollapsed() const { return mCollapsed; }
|
||||
|
||||
U32 getCountAverage() const; //{ return mCountAverage }
|
||||
U32 getCallAverage() const; //{ return mCallAverage }
|
||||
|
||||
U32 getHistoricalCount(S32 history_index = 0) const;
|
||||
U32 getHistoricalCalls(S32 history_index = 0) const;
|
||||
|
||||
static NamedTimer& getRootNamedTimer();
|
||||
|
||||
S32 getFrameStateIndex() const { return mFrameStateIndex; }
|
||||
|
||||
FrameState& getFrameState() const;
|
||||
|
||||
private:
|
||||
friend class LLFastTimer;
|
||||
friend class NamedTimerFactory;
|
||||
|
||||
//
|
||||
// methods
|
||||
//
|
||||
NamedTimer(const std::string& name);
|
||||
// recursive call to gather total time from children
|
||||
static void accumulateTimings();
|
||||
|
||||
// updates cumulative times and hierarchy,
|
||||
// can be called multiple times in a frame, at any point
|
||||
static void processTimes();
|
||||
|
||||
static void buildHierarchy();
|
||||
static void resetFrame();
|
||||
static void reset();
|
||||
|
||||
//
|
||||
// members
|
||||
//
|
||||
S32 mFrameStateIndex;
|
||||
|
||||
std::string mName;
|
||||
|
||||
U32 mTotalTimeCounter;
|
||||
|
||||
U32 mCountAverage;
|
||||
U32 mCallAverage;
|
||||
|
||||
U32* mCountHistory;
|
||||
U32* mCallHistory;
|
||||
|
||||
// tree structure
|
||||
NamedTimer* mParent; // NamedTimer of caller(parent)
|
||||
std::vector<NamedTimer*> mChildren;
|
||||
bool mCollapsed; // don't show children
|
||||
bool mNeedsSorting; // sort children whenever child added
|
||||
};
|
||||
|
||||
// used to statically declare a new named timer
|
||||
class LL_COMMON_API DeclareTimer
|
||||
: public LLInstanceTracker<DeclareTimer>
|
||||
{
|
||||
friend class LLFastTimer;
|
||||
public:
|
||||
DeclareTimer(const std::string& name, bool open);
|
||||
DeclareTimer(const std::string& name);
|
||||
|
||||
static void updateCachedPointers();
|
||||
|
||||
private:
|
||||
NamedTimer& mTimer;
|
||||
FrameState* mFrameState;
|
||||
};
|
||||
|
||||
public:
|
||||
LLFastTimer(LLFastTimer::FrameState* state);
|
||||
|
||||
LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer)
|
||||
: mFrameState(timer.mFrameState)
|
||||
{
|
||||
#if TIME_FAST_TIMERS
|
||||
U64 timer_start = getCPUClockCount64();
|
||||
#endif
|
||||
#if FAST_TIMER_ON
|
||||
LLFastTimer::FrameState* frame_state = mFrameState;
|
||||
mStartTime = getCPUClockCount32();
|
||||
|
||||
frame_state->mActiveCount++;
|
||||
frame_state->mCalls++;
|
||||
// keep current parent as long as it is active when we are
|
||||
frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
|
||||
|
||||
LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData;
|
||||
mLastTimerData = *cur_timer_data;
|
||||
cur_timer_data->mCurTimer = this;
|
||||
cur_timer_data->mFrameState = frame_state;
|
||||
cur_timer_data->mChildTime = 0;
|
||||
#endif
|
||||
#if TIME_FAST_TIMERS
|
||||
U64 timer_end = getCPUClockCount64();
|
||||
sTimerCycles += timer_end - timer_start;
|
||||
#endif
|
||||
#if DEBUG_FAST_TIMER_THREADS
|
||||
#if !LL_RELEASE
|
||||
assert_main_thread();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE ~LLFastTimer()
|
||||
{
|
||||
#if TIME_FAST_TIMERS
|
||||
U64 timer_start = getCPUClockCount64();
|
||||
#endif
|
||||
#if FAST_TIMER_ON
|
||||
LLFastTimer::FrameState* frame_state = mFrameState;
|
||||
U32 total_time = getCPUClockCount32() - mStartTime;
|
||||
|
||||
frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime;
|
||||
frame_state->mActiveCount--;
|
||||
|
||||
// store last caller to bootstrap tree creation
|
||||
// do this in the destructor in case of recursion to get topmost caller
|
||||
frame_state->mLastCaller = mLastTimerData.mFrameState;
|
||||
|
||||
// we are only tracking self time, so subtract our total time delta from parents
|
||||
mLastTimerData.mChildTime += total_time;
|
||||
|
||||
LLFastTimer::sCurTimerData = mLastTimerData;
|
||||
#endif
|
||||
#if TIME_FAST_TIMERS
|
||||
U64 timer_end = getCPUClockCount64();
|
||||
sTimerCycles += timer_end - timer_start;
|
||||
sTimerCalls++;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
static LLMutex* sLogLock;
|
||||
static std::queue<LLSD> sLogQueue;
|
||||
static BOOL sLog;
|
||||
static BOOL sMetricLog;
|
||||
static std::string sLogName;
|
||||
static bool sPauseHistory;
|
||||
static bool sResetHistory;
|
||||
static U64 sTimerCycles;
|
||||
static U32 sTimerCalls;
|
||||
|
||||
typedef std::vector<FrameState> info_list_t;
|
||||
static info_list_t& getFrameStateList();
|
||||
|
||||
|
||||
// call this once a frame to reset timers
|
||||
static void nextFrame();
|
||||
|
||||
// dumps current cumulative frame stats to log
|
||||
// call nextFrame() to reset timers
|
||||
static void dumpCurTimes();
|
||||
|
||||
// call this to reset timer hierarchy, averages, etc.
|
||||
static void reset();
|
||||
|
||||
static U64 countsPerSecond();
|
||||
static S32 getLastFrameIndex() { return sLastFrameIndex; }
|
||||
static S32 getCurFrameIndex() { return sCurFrameIndex; }
|
||||
|
||||
static void writeLog(std::ostream& os);
|
||||
static const NamedTimer* getTimerByName(const std::string& name);
|
||||
|
||||
struct CurTimerData
|
||||
{
|
||||
LLFastTimer* mCurTimer;
|
||||
FrameState* mFrameState;
|
||||
U32 mChildTime;
|
||||
};
|
||||
static CurTimerData sCurTimerData;
|
||||
static std::string sClockType;
|
||||
|
||||
public:
|
||||
static U32 getCPUClockCount32();
|
||||
static U64 getCPUClockCount64();
|
||||
static U64 sClockResolution;
|
||||
|
||||
private:
|
||||
static S32 sCurFrameIndex;
|
||||
static S32 sLastFrameIndex;
|
||||
static U64 sLastFrameTime;
|
||||
static info_list_t* sTimerInfos;
|
||||
|
||||
U32 mStartTime;
|
||||
LLFastTimer::FrameState* mFrameState;
|
||||
LLFastTimer::CurTimerData mLastTimerData;
|
||||
|
||||
};
|
||||
|
||||
typedef class LLFastTimer LLFastTimer;
|
||||
|
||||
#endif // LL_LLFASTTIMER_H
|
||||
@@ -35,56 +35,59 @@
|
||||
#include "u64.h"
|
||||
|
||||
#include "llframetimer.h"
|
||||
#include "aiframetimer.h"
|
||||
#include "llaprpool.h"
|
||||
|
||||
// Local constants.
|
||||
static F64 const USEC_PER_SECOND = 1000000.0;
|
||||
static F64 const USEC_TO_SEC_F64 = 0.000001;
|
||||
static F64 const NEVER = 1e16;
|
||||
|
||||
// Static members
|
||||
U64 const LLFrameTimer::sStartTotalTime = totalTime(); // Application start in microseconds since epoch.
|
||||
U64 LLFrameTimer::sTotalTime = LLFrameTimer::sStartTotalTime; // Current time in microseconds since epoch, updated at least once per frame.
|
||||
F64 LLFrameTimer::sTotalSeconds = // Current time in seconds since epoch, updated together with LLFrameTimer::sTotalTime.
|
||||
U64_to_F64(LLFrameTimer::sTotalTime) * USEC_TO_SEC_F64;
|
||||
U64_to_F64(LLFrameTimer::sTotalTime) * USEC_TO_SEC_F64;
|
||||
F64 LLFrameTimer::sFrameTime = 0.0; // Current time in seconds since application start, updated together with LLFrameTimer::sTotalTime.
|
||||
// Updated exactly once per frame:
|
||||
S32 LLFrameTimer::sFrameCount = 0; // Current frame number (number of frames since application start).
|
||||
U64 LLFrameTimer::sPrevTotalTime = LLFrameTimer::sStartTotalTime; // Previous (frame) time in microseconds since epoch, updated once per frame.
|
||||
U64 LLFrameTimer::sFrameDeltaTime = 0; // Microseconds between last two calls to LLFrameTimer::updateFrameTimeAndCount.
|
||||
// Mutex for the above.
|
||||
apr_thread_mutex_t* LLFrameTimer::sGlobalMutex;
|
||||
|
||||
// static
|
||||
void LLFrameTimer::updateFrameTime()
|
||||
void LLFrameTimer::global_initialization(void)
|
||||
{
|
||||
apr_thread_mutex_create(&sGlobalMutex, APR_THREAD_MUTEX_UNNESTED, LLAPRRootPool::get()());
|
||||
AIFrameTimer::sNextExpiration = NEVER;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFrameTimer::updateFrameTime(void)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
sTotalTime = totalTime();
|
||||
sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64;
|
||||
sFrameTime = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64;
|
||||
}
|
||||
F64 new_frame_time = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64;
|
||||
apr_thread_mutex_lock(sGlobalMutex);
|
||||
sFrameTime = new_frame_time;
|
||||
apr_thread_mutex_unlock(sGlobalMutex);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFrameTimer::updateFrameTimeAndCount()
|
||||
void LLFrameTimer::updateFrameTimeAndCount(void)
|
||||
{
|
||||
updateFrameTime();
|
||||
sFrameDeltaTime = sTotalTime - sPrevTotalTime;
|
||||
sPrevTotalTime = sTotalTime;
|
||||
++sFrameCount;
|
||||
}
|
||||
|
||||
void LLFrameTimer::reset(F32 expiration)
|
||||
{
|
||||
llassert(!mPaused);
|
||||
mStartTime = sFrameTime;
|
||||
mExpiry = sFrameTime + expiration;
|
||||
}
|
||||
|
||||
void LLFrameTimer::start(F32 expiration)
|
||||
{
|
||||
reset(expiration);
|
||||
mRunning = true; // Start, if not already started.
|
||||
}
|
||||
|
||||
void LLFrameTimer::stop()
|
||||
{
|
||||
llassert(!mPaused);
|
||||
mRunning = false;
|
||||
// Handle AIFrameTimer expiration and callbacks.
|
||||
if (AIFrameTimer::sNextExpiration <= sFrameTime)
|
||||
{
|
||||
AIFrameTimer::handleExpiration(sFrameTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't combine pause/unpause with start/stop
|
||||
@@ -95,38 +98,38 @@ void LLFrameTimer::stop()
|
||||
// foo.unpause() // unpauses
|
||||
// F32 elapsed = foo.getElapsedTimeF32() // does not include time between pause() and unpause()
|
||||
// Note: elapsed would also be valid with no unpause() call (= time run until pause() called)
|
||||
void LLFrameTimer::pause()
|
||||
void LLFrameTimer::pause(void)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
if (!mPaused)
|
||||
{
|
||||
// Only the main thread writes to sFrameTime, so there is no need for locking.
|
||||
mStartTime = sFrameTime - mStartTime; // Abuse mStartTime to store the elapsed time so far.
|
||||
}
|
||||
mPaused = true;
|
||||
}
|
||||
|
||||
void LLFrameTimer::unpause()
|
||||
void LLFrameTimer::unpause(void)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
if (mPaused)
|
||||
{
|
||||
// Only the main thread writes to sFrameTime, so there is no need for locking.
|
||||
mStartTime = sFrameTime - mStartTime; // Set mStartTime consistent with the elapsed time so far.
|
||||
}
|
||||
mPaused = false;
|
||||
}
|
||||
|
||||
void LLFrameTimer::setTimerExpirySec(F32 expiration)
|
||||
{
|
||||
llassert(!mPaused);
|
||||
mExpiry = mStartTime + expiration;
|
||||
}
|
||||
|
||||
void LLFrameTimer::setExpiryAt(F64 seconds_since_epoch)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
llassert(!mPaused);
|
||||
// Only the main thread writes to sFrameTime, so there is no need for locking.
|
||||
mStartTime = sFrameTime;
|
||||
mExpiry = seconds_since_epoch - (USEC_TO_SEC_F64 * sStartTotalTime);
|
||||
}
|
||||
|
||||
F64 LLFrameTimer::expiresAt() const
|
||||
F64 LLFrameTimer::expiresAt(void) const
|
||||
{
|
||||
F64 expires_at = U64_to_F64(sStartTotalTime) * USEC_TO_SEC_F64;
|
||||
expires_at += mExpiry;
|
||||
@@ -135,31 +138,47 @@ F64 LLFrameTimer::expiresAt() const
|
||||
|
||||
bool LLFrameTimer::checkExpirationAndReset(F32 expiration)
|
||||
{
|
||||
if (hasExpired())
|
||||
llassert(!mPaused);
|
||||
F64 frame_time = getElapsedSeconds();
|
||||
if (frame_time >= mExpiry)
|
||||
{
|
||||
reset(expiration);
|
||||
mStartTime = frame_time;
|
||||
mExpiry = mStartTime + expiration;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
F32 LLFrameTimer::getFrameDeltaTimeF32()
|
||||
F32 LLFrameTimer::getElapsedTimeAndResetF32(void)
|
||||
{
|
||||
llassert(mRunning && !mPaused);
|
||||
F64 frame_time = getElapsedSeconds();
|
||||
F32 elapsed_time = (F32)(frame_time - mStartTime);
|
||||
mExpiry = mStartTime = frame_time;
|
||||
return elapsed_time;
|
||||
}
|
||||
|
||||
// static
|
||||
// Return number of seconds between the last two frames.
|
||||
F32 LLFrameTimer::getFrameDeltaTimeF32(void)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
// Only the main thread writes to sFrameDeltaTime, so there is no need for locking.
|
||||
return (F32)(U64_to_F64(sFrameDeltaTime) * USEC_TO_SEC_F64);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
// static
|
||||
// Return seconds since the current frame started
|
||||
F32 LLFrameTimer::getCurrentFrameTime()
|
||||
F32 LLFrameTimer::getCurrentFrameTime(void)
|
||||
{
|
||||
llassert(is_main_thread());
|
||||
// Only the main thread writes to sTotalTime, so there is no need for locking.
|
||||
U64 frame_time = totalTime() - sTotalTime;
|
||||
return (F32)(U64_to_F64(frame_time) * USEC_TO_SEC_F64);
|
||||
}
|
||||
|
||||
// Glue code to avoid full class .h file #includes
|
||||
F32 getCurrentFrameTime()
|
||||
F32 getCurrentFrameTime(void)
|
||||
{
|
||||
return (F32)(LLFrameTimer::getCurrentFrameTime());
|
||||
}
|
||||
|
||||
@@ -43,88 +43,131 @@
|
||||
|
||||
#include "lltimer.h"
|
||||
#include "timing.h"
|
||||
#include <apr_thread_mutex.h>
|
||||
|
||||
class LL_COMMON_API LLFrameTimer
|
||||
{
|
||||
public:
|
||||
// Create an LLFrameTimer and start it. After creation it is running and in the state expired (hasExpired will return true).
|
||||
LLFrameTimer(void) : mStartTime(sFrameTime), mExpiry(0), mRunning(true), mPaused(false) { }
|
||||
LLFrameTimer(void) : mExpiry(0), mRunning(true), mPaused(false) { if (!sGlobalMutex) global_initialization(); setAge(0.0); }
|
||||
|
||||
// Atomic reads of static variables.
|
||||
|
||||
// Return the number of seconds since the start of the application.
|
||||
static F64 getElapsedSeconds()
|
||||
static F64 getElapsedSeconds(void)
|
||||
{
|
||||
// Loses msec precision after ~4.5 hours...
|
||||
return sFrameTime;
|
||||
apr_thread_mutex_lock(sGlobalMutex);
|
||||
F64 res = sFrameTime;
|
||||
apr_thread_mutex_unlock(sGlobalMutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Return a low precision usec since epoch.
|
||||
static U64 getTotalTime()
|
||||
static U64 getTotalTime(void)
|
||||
{
|
||||
llassert(sTotalTime);
|
||||
return sTotalTime;
|
||||
// sTotalTime is only accessed by the main thread, so no locking is necessary.
|
||||
llassert(is_main_thread());
|
||||
//apr_thread_mutex_lock(sGlobalMutex);
|
||||
U64 res = sTotalTime;
|
||||
//apr_thread_mutex_unlock(sGlobalMutex);
|
||||
llassert(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Return a low precision seconds since epoch.
|
||||
static F64 getTotalSeconds()
|
||||
static F64 getTotalSeconds(void)
|
||||
{
|
||||
return sTotalSeconds;
|
||||
// sTotalSeconds is only accessed by the main thread, so no locking is necessary.
|
||||
llassert(is_main_thread());
|
||||
//apr_thread_mutex_lock(sGlobalMutex);
|
||||
F64 res = sTotalSeconds;
|
||||
//apr_thread_mutex_unlock(sGlobalMutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Return current frame number (the number of frames since application start).
|
||||
static U32 getFrameCount(void)
|
||||
{
|
||||
// sFrameCount is only accessed by the main thread, so no locking is necessary.
|
||||
llassert(is_main_thread());
|
||||
//apr_thread_mutex_lock(sGlobalMutex);
|
||||
U32 res = sFrameCount;
|
||||
//apr_thread_mutex_unlock(sGlobalMutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Call this method once per frame to update the current frame time.
|
||||
// This is actually called at some other times as well.
|
||||
static void updateFrameTime();
|
||||
static void updateFrameTime(void);
|
||||
|
||||
// Call this method once, and only once, per frame to update the current frame count and sFrameDeltaTime.
|
||||
static void updateFrameTimeAndCount();
|
||||
|
||||
// Return current frame number (the number of frames since application start).
|
||||
static U32 getFrameCount() { return sFrameCount; }
|
||||
static void updateFrameTimeAndCount(void);
|
||||
|
||||
// Return duration of last frame in seconds.
|
||||
static F32 getFrameDeltaTimeF32();
|
||||
static F32 getFrameDeltaTimeF32(void);
|
||||
|
||||
// Return seconds since the current frame started
|
||||
static F32 getCurrentFrameTime();
|
||||
static F32 getCurrentFrameTime(void);
|
||||
|
||||
// MANIPULATORS
|
||||
|
||||
void reset(F32 expiration = 0.f); // Same as start() but leaves mRunning off when called after stop().
|
||||
void start(F32 expiration = 0.f); // Reset and (re)start with expiration.
|
||||
void stop(); // Stop running.
|
||||
void reset(F32 expiration = 0.f) // Same as start() but leaves mRunning off when called after stop().
|
||||
{
|
||||
llassert(!mPaused);
|
||||
mStartTime = getElapsedSeconds();
|
||||
mExpiry = mStartTime + expiration;
|
||||
}
|
||||
|
||||
void start(F32 expiration = 0.f) // Reset and (re)start with expiration.
|
||||
{
|
||||
reset(expiration);
|
||||
mRunning = true; // Start, if not already started.
|
||||
}
|
||||
|
||||
void stop(void) // Stop running.
|
||||
{
|
||||
llassert(!mPaused);
|
||||
mRunning = false;
|
||||
}
|
||||
|
||||
void pause(); // Mark elapsed time so far.
|
||||
void unpause(); // Move 'start' time in order to decrement time between pause and unpause from ElapsedTime.
|
||||
|
||||
void setTimerExpirySec(F32 expiration);
|
||||
void setTimerExpirySec(F32 expiration) { llassert(!mPaused); mExpiry = mStartTime + expiration; }
|
||||
|
||||
void setExpiryAt(F64 seconds_since_epoch);
|
||||
bool checkExpirationAndReset(F32 expiration); // Returns true when expired. Only resets if expired.
|
||||
F32 getElapsedTimeAndResetF32() { F32 t = getElapsedTimeF32(); reset(); return t; }
|
||||
void setAge(const F64 age) { llassert(!mPaused); mStartTime = sFrameTime - age; }
|
||||
F32 getElapsedTimeAndResetF32(void);
|
||||
void setAge(const F64 age) { llassert(!mPaused); mStartTime = getElapsedSeconds() - age; }
|
||||
|
||||
// ACCESSORS
|
||||
bool hasExpired() const { return sFrameTime >= mExpiry; }
|
||||
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(sFrameTime - mStartTime); }
|
||||
bool hasExpired() const { return getElapsedSeconds() >= mExpiry; }
|
||||
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(getElapsedSeconds() - mStartTime); }
|
||||
bool getStarted() const { return mRunning; }
|
||||
|
||||
// return the seconds since epoch when this timer will expire.
|
||||
F64 expiresAt() const;
|
||||
|
||||
protected:
|
||||
// A single, high resolution timer that drives all LLFrameTimers
|
||||
// *NOTE: no longer used.
|
||||
//static LLTimer sInternalTimer;
|
||||
public:
|
||||
// Do one-time initialization of the static members.
|
||||
static void global_initialization(void);
|
||||
|
||||
protected:
|
||||
//
|
||||
// Aplication constants
|
||||
// Application constants
|
||||
//
|
||||
|
||||
// Application start in microseconds since epoch.
|
||||
static U64 const sStartTotalTime;
|
||||
|
||||
//
|
||||
// Data updated per frame
|
||||
// Global data.
|
||||
//
|
||||
|
||||
// More than one thread are accessing (some of) these variables, therefore we need locking.
|
||||
static apr_thread_mutex_t* sGlobalMutex;
|
||||
|
||||
// Current time in seconds since application start, updated together with sTotalTime.
|
||||
static F64 sFrameTime;
|
||||
|
||||
|
||||
@@ -194,7 +194,12 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
LLInstanceTracker(KEY key) { add_(key); }
|
||||
LLInstanceTracker(KEY key)
|
||||
{
|
||||
// make sure static data outlives all instances
|
||||
getStatic();
|
||||
add_(key);
|
||||
}
|
||||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
@@ -282,7 +287,8 @@ public:
|
||||
protected:
|
||||
LLInstanceTracker()
|
||||
{
|
||||
// it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
|
||||
// make sure static data outlives all instances
|
||||
getStatic();
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
virtual ~LLInstanceTracker()
|
||||
|
||||
@@ -134,4 +134,7 @@ private:
|
||||
LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b);
|
||||
LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b);
|
||||
|
||||
LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b);
|
||||
LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b);
|
||||
|
||||
#endif // LL_LLMD5_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,9 +40,6 @@
|
||||
#endif
|
||||
|
||||
#include "llerror.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if LL_DEBUG
|
||||
inline void* ll_aligned_malloc( size_t size, int align )
|
||||
{
|
||||
@@ -120,6 +117,10 @@ inline void ll_aligned_free_32(void *p)
|
||||
#define ll_aligned_free_32 free
|
||||
#endif // LL_DEBUG
|
||||
|
||||
#ifndef __DEBUG_PRIVATE_MEM__
|
||||
#define __DEBUG_PRIVATE_MEM__ 0
|
||||
#endif
|
||||
|
||||
class LL_COMMON_API LLMemory
|
||||
{
|
||||
public:
|
||||
@@ -130,10 +131,395 @@ public:
|
||||
// Return value is zero if not known.
|
||||
static U64 getCurrentRSS();
|
||||
static U32 getWorkingSetSize();
|
||||
static void* tryToAlloc(void* address, U32 size);
|
||||
static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure);
|
||||
static void updateMemoryInfo() ;
|
||||
static void logMemoryInfo(BOOL update = FALSE);
|
||||
static bool isMemoryPoolLow();
|
||||
|
||||
static U32 getAvailableMemKB() ;
|
||||
static U32 getMaxMemKB() ;
|
||||
static U32 getAllocatedMemKB() ;
|
||||
private:
|
||||
static char* reserveMem;
|
||||
static U32 sAvailPhysicalMemInKB ;
|
||||
static U32 sMaxPhysicalMemInKB ;
|
||||
static U32 sAllocatedMemInKB;
|
||||
static U32 sAllocatedPageSizeInKB ;
|
||||
|
||||
static U32 sMaxHeapSizeInKB;
|
||||
static BOOL sEnableMemoryFailurePrevention;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class LLMutex ;
|
||||
#if MEM_TRACK_MEM
|
||||
class LL_COMMON_API LLMemTracker
|
||||
{
|
||||
private:
|
||||
LLMemTracker() ;
|
||||
~LLMemTracker() ;
|
||||
|
||||
public:
|
||||
static void release() ;
|
||||
static LLMemTracker* getInstance() ;
|
||||
|
||||
void track(const char* function, const int line) ;
|
||||
void preDraw(BOOL pause) ;
|
||||
void postDraw() ;
|
||||
const char* getNextLine() ;
|
||||
|
||||
private:
|
||||
static LLMemTracker* sInstance ;
|
||||
|
||||
char** mStringBuffer ;
|
||||
S32 mCapacity ;
|
||||
U32 mLastAllocatedMem ;
|
||||
S32 mCurIndex ;
|
||||
S32 mCounter;
|
||||
S32 mDrawnIndex;
|
||||
S32 mNumOfDrawn;
|
||||
BOOL mPaused;
|
||||
LLMutex* mMutexp ;
|
||||
};
|
||||
|
||||
#define MEM_TRACK_RELEASE LLMemTracker::release() ;
|
||||
#define MEM_TRACK LLMemTracker::getInstance()->track(__FUNCTION__, __LINE__) ;
|
||||
|
||||
#else // MEM_TRACK_MEM
|
||||
|
||||
#define MEM_TRACK_RELEASE
|
||||
#define MEM_TRACK
|
||||
|
||||
#endif // MEM_TRACK_MEM
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
//class LLPrivateMemoryPool defines a private memory pool for an application to use, so the application does not
|
||||
//need to access the heap directly fro each memory allocation. Throught this, the allocation speed is faster,
|
||||
//and reduces virtaul address space gragmentation problem.
|
||||
//Note: this class is thread-safe by passing true to the constructor function. However, you do not need to do this unless
|
||||
//you are sure the memory allocation and de-allocation will happen in different threads. To make the pool thread safe
|
||||
//increases allocation and deallocation cost.
|
||||
//
|
||||
class LL_COMMON_API LLPrivateMemoryPool
|
||||
{
|
||||
friend class LLPrivateMemoryPoolManager ;
|
||||
|
||||
public:
|
||||
class LL_COMMON_API LLMemoryBlock //each block is devided into slots uniformly
|
||||
{
|
||||
public:
|
||||
LLMemoryBlock() ;
|
||||
~LLMemoryBlock() ;
|
||||
|
||||
void init(char* buffer, U32 buffer_size, U32 slot_size) ;
|
||||
void setBuffer(char* buffer, U32 buffer_size) ;
|
||||
|
||||
char* allocate() ;
|
||||
void freeMem(void* addr) ;
|
||||
|
||||
bool empty() {return !mAllocatedSlots;}
|
||||
bool isFull() {return mAllocatedSlots == mTotalSlots;}
|
||||
bool isFree() {return !mTotalSlots;}
|
||||
|
||||
U32 getSlotSize()const {return mSlotSize;}
|
||||
U32 getTotalSlots()const {return mTotalSlots;}
|
||||
U32 getBufferSize()const {return mBufferSize;}
|
||||
char* getBuffer() const {return mBuffer;}
|
||||
|
||||
//debug use
|
||||
void resetBitMap() ;
|
||||
private:
|
||||
char* mBuffer;
|
||||
U32 mSlotSize ; //when the block is not initialized, it is the buffer size.
|
||||
U32 mBufferSize ;
|
||||
U32 mUsageBits ;
|
||||
U8 mTotalSlots ;
|
||||
U8 mAllocatedSlots ;
|
||||
U8 mDummySize ; //size of extra bytes reserved for mUsageBits.
|
||||
|
||||
public:
|
||||
LLMemoryBlock* mPrev ;
|
||||
LLMemoryBlock* mNext ;
|
||||
LLMemoryBlock* mSelf ;
|
||||
|
||||
struct CompareAddress
|
||||
{
|
||||
bool operator()(const LLMemoryBlock* const& lhs, const LLMemoryBlock* const& rhs)
|
||||
{
|
||||
return (size_t)lhs->getBuffer() < (size_t)rhs->getBuffer();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLMemoryChunk //is divided into memory blocks.
|
||||
{
|
||||
public:
|
||||
LLMemoryChunk() ;
|
||||
~LLMemoryChunk() ;
|
||||
|
||||
void init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) ;
|
||||
void setBuffer(char* buffer, U32 buffer_size) ;
|
||||
|
||||
bool empty() ;
|
||||
|
||||
char* allocate(U32 size) ;
|
||||
void freeMem(void* addr) ;
|
||||
|
||||
char* getBuffer() const {return mBuffer;}
|
||||
U32 getBufferSize() const {return mBufferSize;}
|
||||
U32 getAllocatedSize() const {return mAlloatedSize;}
|
||||
|
||||
bool containsAddress(const char* addr) const;
|
||||
|
||||
static U32 getMaxOverhead(U32 data_buffer_size, U32 min_slot_size,
|
||||
U32 max_slot_size, U32 min_block_size, U32 max_block_size) ;
|
||||
|
||||
void dump() ;
|
||||
|
||||
private:
|
||||
U32 getPageIndex(char const* addr) ;
|
||||
U32 getBlockLevel(U32 size) ;
|
||||
U16 getPageLevel(U32 size) ;
|
||||
LLMemoryBlock* addBlock(U32 blk_idx) ;
|
||||
void popAvailBlockList(U32 blk_idx) ;
|
||||
void addToFreeSpace(LLMemoryBlock* blk) ;
|
||||
void removeFromFreeSpace(LLMemoryBlock* blk) ;
|
||||
void removeBlock(LLMemoryBlock* blk) ;
|
||||
void addToAvailBlockList(LLMemoryBlock* blk) ;
|
||||
U32 calcBlockSize(U32 slot_size);
|
||||
LLMemoryBlock* createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) ;
|
||||
|
||||
private:
|
||||
LLMemoryBlock** mAvailBlockList ;//256 by mMinSlotSize
|
||||
LLMemoryBlock** mFreeSpaceList;
|
||||
LLMemoryBlock* mBlocks ; //index of blocks by address.
|
||||
|
||||
char* mBuffer ;
|
||||
U32 mBufferSize ;
|
||||
char* mDataBuffer ;
|
||||
char* mMetaBuffer ;
|
||||
U32 mMinBlockSize ;
|
||||
U32 mMinSlotSize ;
|
||||
U32 mMaxSlotSize ;
|
||||
U32 mAlloatedSize ;
|
||||
U16 mBlockLevels;
|
||||
U16 mPartitionLevels;
|
||||
|
||||
public:
|
||||
//form a linked list
|
||||
LLMemoryChunk* mNext ;
|
||||
LLMemoryChunk* mPrev ;
|
||||
} ;
|
||||
|
||||
private:
|
||||
LLPrivateMemoryPool(S32 type, U32 max_pool_size) ;
|
||||
~LLPrivateMemoryPool() ;
|
||||
|
||||
char *allocate(U32 size) ;
|
||||
void freeMem(void* addr) ;
|
||||
|
||||
void dump() ;
|
||||
U32 getTotalAllocatedSize() ;
|
||||
U32 getTotalReservedSize() {return mReservedPoolSize;}
|
||||
S32 getType() const {return mType; }
|
||||
bool isEmpty() const {return !mNumOfChunks; }
|
||||
|
||||
private:
|
||||
void lock() ;
|
||||
void unlock() ;
|
||||
S32 getChunkIndex(U32 size) ;
|
||||
LLMemoryChunk* addChunk(S32 chunk_index) ;
|
||||
bool checkSize(U32 asked_size) ;
|
||||
void removeChunk(LLMemoryChunk* chunk) ;
|
||||
U16 findHashKey(const char* addr);
|
||||
void addToHashTable(LLMemoryChunk* chunk) ;
|
||||
void removeFromHashTable(LLMemoryChunk* chunk) ;
|
||||
void rehash() ;
|
||||
bool fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) ;
|
||||
LLMemoryChunk* findChunk(const char* addr) ;
|
||||
|
||||
void destroyPool() ;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
SMALL_ALLOCATION = 0, //from 8 bytes to 2KB(exclusive), page size 2KB, max chunk size is 4MB.
|
||||
MEDIUM_ALLOCATION, //from 2KB to 512KB(exclusive), page size 32KB, max chunk size 4MB
|
||||
LARGE_ALLOCATION, //from 512KB to 4MB(inclusive), page size 64KB, max chunk size 16MB
|
||||
SUPER_ALLOCATION //allocation larger than 4MB.
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
STATIC = 0 , //static pool(each alllocation stays for a long time) without threading support
|
||||
VOLATILE, //Volatile pool(each allocation stays for a very short time) without threading support
|
||||
STATIC_THREADED, //static pool with threading support
|
||||
VOLATILE_THREADED, //volatile pool with threading support
|
||||
MAX_TYPES
|
||||
}; //pool types
|
||||
|
||||
private:
|
||||
LLMutex* mMutexp ;
|
||||
U32 mMaxPoolSize;
|
||||
U32 mReservedPoolSize ;
|
||||
|
||||
LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address
|
||||
U16 mNumOfChunks ;
|
||||
U16 mHashFactor ;
|
||||
|
||||
S32 mType ;
|
||||
|
||||
class LLChunkHashElement
|
||||
{
|
||||
public:
|
||||
LLChunkHashElement() {mFirst = NULL ; mSecond = NULL ;}
|
||||
|
||||
bool add(LLMemoryChunk* chunk) ;
|
||||
void remove(LLMemoryChunk* chunk) ;
|
||||
LLMemoryChunk* findChunk(const char* addr) ;
|
||||
|
||||
bool empty() {return !mFirst && !mSecond; }
|
||||
bool full() {return mFirst && mSecond; }
|
||||
bool hasElement(LLMemoryChunk* chunk) {return mFirst == chunk || mSecond == chunk;}
|
||||
|
||||
private:
|
||||
LLMemoryChunk* mFirst ;
|
||||
LLMemoryChunk* mSecond ;
|
||||
};
|
||||
std::vector<LLChunkHashElement> mChunkHashList ;
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLPrivateMemoryPoolManager
|
||||
{
|
||||
private:
|
||||
LLPrivateMemoryPoolManager(BOOL enabled, U32 max_pool_size) ;
|
||||
~LLPrivateMemoryPoolManager() ;
|
||||
|
||||
public:
|
||||
static LLPrivateMemoryPoolManager* getInstance() ;
|
||||
static void initClass(BOOL enabled, U32 pool_size) ;
|
||||
static void destroyClass() ;
|
||||
|
||||
LLPrivateMemoryPool* newPool(S32 type) ;
|
||||
void deletePool(LLPrivateMemoryPool* pool) ;
|
||||
|
||||
private:
|
||||
std::vector<LLPrivateMemoryPool*> mPoolList ;
|
||||
U32 mMaxPrivatePoolSize;
|
||||
|
||||
static LLPrivateMemoryPoolManager* sInstance ;
|
||||
static BOOL sPrivatePoolEnabled;
|
||||
static std::vector<LLPrivateMemoryPool*> sDanglingPoolList ;
|
||||
public:
|
||||
//debug and statistics info.
|
||||
void updateStatistics() ;
|
||||
|
||||
U32 mTotalReservedSize ;
|
||||
U32 mTotalAllocatedSize ;
|
||||
|
||||
public:
|
||||
#if __DEBUG_PRIVATE_MEM__
|
||||
static char* allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) ;
|
||||
|
||||
typedef std::map<char*, std::string> mem_allocation_info_t ;
|
||||
static mem_allocation_info_t sMemAllocationTracker;
|
||||
#else
|
||||
static char* allocate(LLPrivateMemoryPool* poolp, U32 size) ;
|
||||
#endif
|
||||
static void freeMem(LLPrivateMemoryPool* poolp, void* addr) ;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
#if __DEBUG_PRIVATE_MEM__
|
||||
#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size), __FUNCTION__, __LINE__)
|
||||
#else
|
||||
#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size))
|
||||
//#define ALLOCATE_MEM(poolp, size) new char[size]
|
||||
#endif
|
||||
#define FREE_MEM(poolp, addr) LLPrivateMemoryPoolManager::freeMem((poolp), (addr))
|
||||
//#define FREE_MEM(poolp, addr) delete[] addr;
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
//the below singleton is used to test the private memory pool.
|
||||
//
|
||||
#if 0
|
||||
class LL_COMMON_API LLPrivateMemoryPoolTester
|
||||
{
|
||||
private:
|
||||
LLPrivateMemoryPoolTester() ;
|
||||
~LLPrivateMemoryPoolTester() ;
|
||||
|
||||
public:
|
||||
static LLPrivateMemoryPoolTester* getInstance() ;
|
||||
static void destroy() ;
|
||||
|
||||
void run(S32 type) ;
|
||||
|
||||
private:
|
||||
void correctnessTest() ;
|
||||
void performanceTest() ;
|
||||
void fragmentationtest() ;
|
||||
|
||||
void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ;
|
||||
void testAndTime(U32 size, U32 times) ;
|
||||
|
||||
#if 0
|
||||
public:
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
void operator delete(void* addr)
|
||||
{
|
||||
sPool->freeMem(addr) ;
|
||||
}
|
||||
void* operator new[](size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
void operator delete[](void* addr)
|
||||
{
|
||||
sPool->freeMem(addr) ;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
static LLPrivateMemoryPoolTester* sInstance;
|
||||
static LLPrivateMemoryPool* sPool ;
|
||||
static LLPrivateMemoryPool* sThreadedPool ;
|
||||
};
|
||||
#if 0
|
||||
//static
|
||||
void* LLPrivateMemoryPoolTester::operator new(size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLPrivateMemoryPoolTester::operator delete(void* addr)
|
||||
{
|
||||
sPool->free(addr) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void* LLPrivateMemoryPoolTester::operator new[](size_t size)
|
||||
{
|
||||
return (void*)sPool->allocate(size) ;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLPrivateMemoryPoolTester::operator delete[](void* addr)
|
||||
{
|
||||
sPool->free(addr) ;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//EVENTUALLY REMOVE THESE:
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
|
||||
102
indra/llcommon/llptrto.cpp
Normal file
102
indra/llcommon/llptrto.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @file llptrto.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2008-08-20
|
||||
* @brief Test for llptrto.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "llptrto.h"
|
||||
// STL headers
|
||||
// std headers
|
||||
// external library headers
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
// other Linden headers
|
||||
#include "llmemory.h"
|
||||
|
||||
// a refcounted class
|
||||
class RCFoo: public LLRefCount
|
||||
{
|
||||
public:
|
||||
RCFoo() {}
|
||||
};
|
||||
|
||||
// a refcounted subclass
|
||||
class RCSubFoo: public RCFoo
|
||||
{
|
||||
public:
|
||||
RCSubFoo() {}
|
||||
};
|
||||
|
||||
// a refcounted class using the other refcount base class
|
||||
class TSRCFoo: public LLThreadSafeRefCount
|
||||
{
|
||||
public:
|
||||
TSRCFoo() {}
|
||||
};
|
||||
|
||||
// a non-refcounted class
|
||||
class Bar
|
||||
{
|
||||
public:
|
||||
Bar() {}
|
||||
};
|
||||
|
||||
// a non-refcounted subclass
|
||||
class SubBar: public Bar
|
||||
{
|
||||
public:
|
||||
SubBar() {}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// test LLPtrTo<>
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<RCFoo>::type, LLPointer<RCFoo> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<RCSubFoo>::type, LLPointer<RCSubFoo> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<TSRCFoo>::type, LLPointer<TSRCFoo> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<Bar>::type, Bar*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<SubBar>::type, SubBar*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<int>::type, int*>::value));
|
||||
|
||||
// Test LLRemovePointer<>. Note that we remove both pointer variants from
|
||||
// each kind of type, regardless of whether the variant makes sense.
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<RCFoo*>::type, RCFoo>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<RCFoo> >::type, RCFoo>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<RCSubFoo*>::type, RCSubFoo>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<RCSubFoo> >::type, RCSubFoo>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<TSRCFoo*>::type, TSRCFoo>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<TSRCFoo> >::type, TSRCFoo>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<Bar*>::type, Bar>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<Bar> >::type, Bar>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<SubBar*>::type, SubBar>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<SubBar> >::type, SubBar>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<int*>::type, int>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<int> >::type, int>::value));
|
||||
|
||||
return 0;
|
||||
}
|
||||
87
indra/llcommon/llptrto.h
Normal file
87
indra/llcommon/llptrto.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file llptrto.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2008-08-19
|
||||
* @brief LLPtrTo<TARGET> is a template helper to pick either TARGET* or -- when
|
||||
* TARGET is a subclass of LLRefCount or LLThreadSafeRefCount --
|
||||
* LLPointer<TARGET>. LLPtrTo<> chooses whichever pointer type is best.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_LLPTRTO_H)
|
||||
#define LL_LLPTRTO_H
|
||||
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h" // LLRefCount
|
||||
#include "llthread.h" // LLThreadSafeRefCount
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/type_traits/remove_pointer.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
/**
|
||||
* LLPtrTo<TARGET>::type is either of two things:
|
||||
*
|
||||
* * When TARGET is a subclass of either LLRefCount or LLThreadSafeRefCount,
|
||||
* LLPtrTo<TARGET>::type is LLPointer<TARGET>.
|
||||
* * Otherwise, LLPtrTo<TARGET>::type is TARGET*.
|
||||
*
|
||||
* This way, a class template can use LLPtrTo<TARGET>::type to select an
|
||||
* appropriate pointer type to store.
|
||||
*/
|
||||
template <class T, class ENABLE=void>
|
||||
struct LLPtrTo
|
||||
{
|
||||
typedef T* type;
|
||||
};
|
||||
|
||||
/// specialize for subclasses of LLRefCount
|
||||
template <class T>
|
||||
struct LLPtrTo<T, typename boost::enable_if< boost::is_base_of<LLRefCount, T> >::type>
|
||||
{
|
||||
typedef LLPointer<T> type;
|
||||
};
|
||||
|
||||
/// specialize for subclasses of LLThreadSafeRefCount
|
||||
template <class T>
|
||||
struct LLPtrTo<T, typename boost::enable_if< boost::is_base_of<LLThreadSafeRefCount, T> >::type>
|
||||
{
|
||||
typedef LLPointer<T> type;
|
||||
};
|
||||
|
||||
/**
|
||||
* LLRemovePointer<PTRTYPE>::type gets you the underlying (pointee) type.
|
||||
*/
|
||||
template <typename PTRTYPE>
|
||||
struct LLRemovePointer
|
||||
{
|
||||
typedef typename boost::remove_pointer<PTRTYPE>::type type;
|
||||
};
|
||||
|
||||
/// specialize for LLPointer<SOMECLASS>
|
||||
template <typename SOMECLASS>
|
||||
struct LLRemovePointer< LLPointer<SOMECLASS> >
|
||||
{
|
||||
typedef SOMECLASS type;
|
||||
};
|
||||
|
||||
#endif /* ! defined(LL_LLPTRTO_H) */
|
||||
@@ -38,7 +38,7 @@
|
||||
//============================================================================
|
||||
|
||||
// MAIN THREAD
|
||||
LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
||||
LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) :
|
||||
LLThread(name),
|
||||
mThreaded(threaded),
|
||||
mIdleThread(TRUE),
|
||||
@@ -47,6 +47,11 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
||||
{
|
||||
if (mThreaded)
|
||||
{
|
||||
if(should_pause)
|
||||
{
|
||||
pause() ; //call this before start the thread.
|
||||
}
|
||||
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
static handle_t nullHandle() { return handle_t(0); }
|
||||
|
||||
public:
|
||||
LLQueuedThread(const std::string& name, bool threaded = true);
|
||||
LLQueuedThread(const std::string& name, bool threaded = true, bool should_pause = false);
|
||||
virtual ~LLQueuedThread();
|
||||
virtual void shutdown();
|
||||
|
||||
|
||||
@@ -39,13 +39,11 @@
|
||||
|
||||
#include <iostream>
|
||||
#include "apr_base64.h"
|
||||
#if MESH_ENABLED
|
||||
#ifdef LL_STANDALONE
|
||||
# include <zlib.h>
|
||||
#else
|
||||
# include "zlib/zlib.h" // for davep's dirty little zip functions
|
||||
#endif
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
#if !LL_WINDOWS
|
||||
#include <netinet/in.h> // htonl & ntohl
|
||||
@@ -1454,9 +1452,12 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
|
||||
}
|
||||
|
||||
case LLSD::TypeUUID:
|
||||
{
|
||||
ostr.put('u');
|
||||
ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES);
|
||||
LLUUID value = data.asUUID();
|
||||
ostr.write((const char*)(&value.mData), UUID_BYTES);
|
||||
break;
|
||||
}
|
||||
|
||||
case LLSD::TypeString:
|
||||
ostr.put('s');
|
||||
@@ -1996,8 +1997,6 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
|
||||
return s;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
|
||||
//dirty little zippers -- yell at davep if these are horrid
|
||||
|
||||
//return a string containing gzipped bytes of binary serialized LLSD
|
||||
@@ -2173,4 +2172,3 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size)
|
||||
free(result);
|
||||
return true;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
@@ -788,9 +788,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if MESH_ENABLED
|
||||
//dirty little zip functions -- yell at davep
|
||||
LL_COMMON_API std::string zip_llsd(LLSD& data);
|
||||
LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
|
||||
#endif //MESH_ENABLED
|
||||
#endif // LL_LLSDSERIALIZE_H
|
||||
|
||||
@@ -42,17 +42,17 @@ template <class Object> class LLStrider
|
||||
U8* mBytep;
|
||||
};
|
||||
U32 mSkip;
|
||||
U32 mTypeSize;
|
||||
//U32 mTypeSize;
|
||||
public:
|
||||
|
||||
LLStrider() { mObjectp = NULL; mTypeSize = mSkip = sizeof(Object); }
|
||||
LLStrider() { mObjectp = NULL; /*mTypeSize = */mSkip = sizeof(Object); }
|
||||
~LLStrider() { }
|
||||
|
||||
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
||||
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
|
||||
void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
|
||||
//void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
|
||||
|
||||
bool isStrided() const { return mTypeSize != mSkip; }
|
||||
//bool isStrided() const { return mTypeSize != mSkip; }
|
||||
void skip(const U32 index) { mBytep += mSkip*index;}
|
||||
U32 getSkip() const { return mSkip; }
|
||||
Object* get() { return mObjectp; }
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
||||
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
||||
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
|
||||
void assignArray(U8* __restrict source, const size_t elem_size, const size_t elem_count)
|
||||
/*void assignArray(U8* __restrict source, const size_t elem_size, const size_t elem_count)
|
||||
{
|
||||
llassert_always(sizeof(Object) <= elem_size);
|
||||
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
source+=elem_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
};
|
||||
|
||||
#endif // LL_LLSTRIDER_H
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
#include <winnls.h> // for WideCharToMultiByte
|
||||
#endif
|
||||
|
||||
LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format");
|
||||
|
||||
|
||||
std::string ll_safe_string(const char* in)
|
||||
{
|
||||
if(in) return std::string(in);
|
||||
@@ -1196,7 +1199,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
|
||||
template<>
|
||||
S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
|
||||
{
|
||||
LLFastTimer ft(LLFastTimer::FT_STRING_FORMAT);
|
||||
LLFastTimer ft(FT_STRING_FORMAT);
|
||||
S32 res = 0;
|
||||
|
||||
std::string output;
|
||||
@@ -1269,7 +1272,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
|
||||
template<>
|
||||
S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
|
||||
{
|
||||
LLFastTimer ft(LLFastTimer::FT_STRING_FORMAT);
|
||||
LLFastTimer ft(FT_STRING_FORMAT);
|
||||
S32 res = 0;
|
||||
|
||||
if (!substitutions.isMap())
|
||||
|
||||
@@ -111,7 +111,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
|
||||
// after the LLCurl::Multi::run() function exits and we actually
|
||||
// change this variable (which really SHOULD have been inside
|
||||
// the critical area of the mSignal lock)].
|
||||
llinfos << "LLThread::staticRun() Exiting: " << name << llendl;
|
||||
lldebugs << "LLThread::staticRun() Exiting: " << name << llendl;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
const S32 LL_VERSION_MAJOR = 1;
|
||||
const S32 LL_VERSION_MINOR = 6;
|
||||
const S32 LL_VERSION_PATCH = 0;
|
||||
const S32 LL_VERSION_BUILD = 1;
|
||||
const S32 LL_VERSION_BUILD = 3;
|
||||
|
||||
const char * const LL_CHANNEL = "Singularity";
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
//============================================================================
|
||||
// Run on MAIN thread
|
||||
|
||||
LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) :
|
||||
LLQueuedThread(name, threaded)
|
||||
LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) :
|
||||
LLQueuedThread(name, threaded, should_pause)
|
||||
{
|
||||
mDeleteMutex = new LLMutex;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ private:
|
||||
LLMutex* mDeleteMutex;
|
||||
|
||||
public:
|
||||
LLWorkerThread(const std::string& name, bool threaded = true);
|
||||
LLWorkerThread(const std::string& name, bool threaded = true, bool should_pause = false);
|
||||
~LLWorkerThread();
|
||||
|
||||
/*virtual*/ S32 update(U32 max_time_ms);
|
||||
|
||||
@@ -347,7 +347,7 @@ bool LLCrashLogger::sendCrashLogs()
|
||||
|
||||
bool sent = false;
|
||||
|
||||
//*TODO: Translate
|
||||
// *TODO: Translate
|
||||
if(mCrashHost != "")
|
||||
{
|
||||
sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3, 5);
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "llimagepng.h"
|
||||
#include "llimagedxt.h"
|
||||
#include "llimageworker.h"
|
||||
#include "llmemory.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// LLImage
|
||||
@@ -53,12 +54,14 @@
|
||||
//static
|
||||
std::string LLImage::sLastErrorMessage;
|
||||
LLMutex* LLImage::sMutex = NULL;
|
||||
LLPrivateMemoryPool* LLImageBase::sPrivatePoolp = NULL ;
|
||||
|
||||
//static
|
||||
void LLImage::initClass()
|
||||
{
|
||||
sMutex = new LLMutex;
|
||||
LLImageJ2C::openDSO();
|
||||
LLImageBase::createPrivatePool() ;
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -67,6 +70,8 @@ void LLImage::cleanupClass()
|
||||
LLImageJ2C::closeDSO();
|
||||
delete sMutex;
|
||||
sMutex = NULL;
|
||||
|
||||
LLImageBase::destroyPrivatePool() ;
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -105,6 +110,25 @@ LLImageBase::~LLImageBase()
|
||||
deleteData(); // virtual
|
||||
}
|
||||
|
||||
//static
|
||||
void LLImageBase::createPrivatePool()
|
||||
{
|
||||
if(!sPrivatePoolp)
|
||||
{
|
||||
sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC_THREADED) ;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLImageBase::destroyPrivatePool()
|
||||
{
|
||||
if(sPrivatePoolp)
|
||||
{
|
||||
LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ;
|
||||
sPrivatePoolp = NULL ;
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLImageBase::dump()
|
||||
{
|
||||
@@ -138,7 +162,7 @@ void LLImageBase::sanityCheck()
|
||||
// virtual
|
||||
void LLImageBase::deleteData()
|
||||
{
|
||||
delete[] mData;
|
||||
FREE_MEM(sPrivatePoolp, mData) ;
|
||||
mData = NULL;
|
||||
mDataSize = 0;
|
||||
}
|
||||
@@ -164,14 +188,14 @@ U8* LLImageBase::allocateData(S32 size)
|
||||
if (!mData || size != mDataSize)
|
||||
{
|
||||
deleteData(); // virtual
|
||||
mBadBufferAllocation = FALSE ;
|
||||
mData = new (std::nothrow) U8[size];
|
||||
mBadBufferAllocation = false ;
|
||||
mData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
|
||||
if (!mData)
|
||||
{
|
||||
llwarns << "allocate image data: " << size << llendl;
|
||||
size = 0 ;
|
||||
mWidth = mHeight = 0 ;
|
||||
mBadBufferAllocation = TRUE ;
|
||||
mBadBufferAllocation = true ;
|
||||
}
|
||||
mDataSize = size;
|
||||
}
|
||||
@@ -186,7 +210,7 @@ U8* LLImageBase::reallocateData(S32 size)
|
||||
return mData;
|
||||
|
||||
LLMemType mt1((LLMemType::EMemType)mMemType);
|
||||
U8 *new_datap = new (std::nothrow) U8[size];
|
||||
U8 *new_datap = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
|
||||
if (!new_datap)
|
||||
{
|
||||
llwarns << "Out of memory in LLImageBase::reallocateData" << llendl;
|
||||
@@ -196,7 +220,7 @@ U8* LLImageBase::reallocateData(S32 size)
|
||||
{
|
||||
S32 bytes = llmin(mDataSize, size);
|
||||
memcpy(new_datap, mData, bytes); /* Flawfinder: ignore */
|
||||
delete[] mData;
|
||||
FREE_MEM(sPrivatePoolp, mData) ;
|
||||
}
|
||||
mData = new_datap;
|
||||
mDataSize = size;
|
||||
@@ -276,11 +300,11 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components)
|
||||
++sRawImageCount;
|
||||
}
|
||||
|
||||
LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
|
||||
/*LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
|
||||
: LLImageBase(), mCacheEntries(0)
|
||||
{
|
||||
createFromFile(filename, j2c_lowest_mip_only);
|
||||
}
|
||||
}*/
|
||||
|
||||
LLImageRaw::~LLImageRaw()
|
||||
{
|
||||
@@ -346,10 +370,11 @@ BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
|
||||
{
|
||||
LLMemType mt1((LLMemType::EMemType)mMemType);
|
||||
U8 *data = new (std::nothrow) U8[width*height*getComponents()];
|
||||
LLMemType mt1(mMemType);
|
||||
U8 *data = new U8[width*height*getComponents()];
|
||||
|
||||
// Should do some simple bounds checking
|
||||
if (!data)
|
||||
@@ -366,6 +391,7 @@ U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
|
||||
}
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
|
||||
const U8 *data, U32 stride, BOOL reverse_y)
|
||||
@@ -856,11 +882,11 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
|
||||
delete[] temp_buffer;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
//scale down image by not blending a pixel with its neighbors.
|
||||
BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
|
||||
{
|
||||
LLMemType mt1((LLMemType::EMemType)mMemType);
|
||||
LLMemType mt1(mMemType);
|
||||
|
||||
S8 c = getComponents() ;
|
||||
llassert((1 == c) || (3 == c) || (4 == c) );
|
||||
@@ -880,7 +906,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
|
||||
ratio_x -= 1.0f ;
|
||||
ratio_y -= 1.0f ;
|
||||
|
||||
U8* new_data = new (std::nothrow) U8[new_data_size] ;
|
||||
U8* new_data = allocateMemory(new_data_size) ;
|
||||
llassert_always(new_data != NULL) ;
|
||||
|
||||
U8* old_data = getData() ;
|
||||
@@ -902,6 +928,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
|
||||
|
||||
return TRUE ;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
|
||||
{
|
||||
@@ -1222,7 +1249,7 @@ file_extensions[] =
|
||||
{ "png", IMG_CODEC_PNG }
|
||||
};
|
||||
#define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions)
|
||||
|
||||
#if 0
|
||||
static std::string find_file(std::string &name, S8 *codec)
|
||||
{
|
||||
std::string tname;
|
||||
@@ -1240,7 +1267,7 @@ static std::string find_file(std::string &name, S8 *codec)
|
||||
}
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
#endif
|
||||
EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
|
||||
{
|
||||
for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
|
||||
@@ -1250,7 +1277,7 @@ EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
|
||||
}
|
||||
return IMG_CODEC_INVALID;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only)
|
||||
{
|
||||
std::string name = filename;
|
||||
@@ -1336,7 +1363,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
//---------------------------------------------------------------------------
|
||||
// LLImageFormatted
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -1568,7 +1595,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size)
|
||||
S32 newsize = cursize + size;
|
||||
reallocateData(newsize);
|
||||
memcpy(getData() + cursize, data, size);
|
||||
delete[] data; //Fixing leak from CommentCacheReadResponder
|
||||
FREE_MEM(LLImageBase::getPrivatePool(), data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ const S32 MAX_IMG_PACKET_SIZE = 1000;
|
||||
class LLImageFormatted;
|
||||
class LLImageRaw;
|
||||
class LLColor4U;
|
||||
class LLPrivateMemoryPool;
|
||||
|
||||
typedef enum e_image_codec
|
||||
{
|
||||
@@ -144,6 +145,9 @@ public:
|
||||
|
||||
static EImageCodec getCodecFromExtension(const std::string& exten);
|
||||
|
||||
static void createPrivatePool() ;
|
||||
static void destroyPrivatePool() ;
|
||||
static LLPrivateMemoryPool* getPrivatePool() {return sPrivatePoolp;}
|
||||
private:
|
||||
U8 *mData;
|
||||
S32 mDataSize;
|
||||
@@ -155,6 +159,8 @@ private:
|
||||
|
||||
bool mBadBufferAllocation ;
|
||||
bool mAllowOverSize ;
|
||||
|
||||
static LLPrivateMemoryPool* sPrivatePoolp ;
|
||||
public:
|
||||
S16 mMemType; // debug
|
||||
};
|
||||
@@ -170,7 +176,7 @@ public:
|
||||
LLImageRaw(U16 width, U16 height, S8 components);
|
||||
LLImageRaw(U8 *data, U16 width, U16 height, S8 components);
|
||||
// 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);
|
||||
|
||||
/*virtual*/ void deleteData();
|
||||
/*virtual*/ U8* allocateData(S32 size = -1);
|
||||
@@ -178,7 +184,7 @@ public:
|
||||
|
||||
BOOL resize(U16 width, U16 height, S8 components);
|
||||
|
||||
U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const;
|
||||
//U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const;
|
||||
BOOL setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
|
||||
const U8 *data, U32 stride = 0, BOOL reverse_y = FALSE);
|
||||
|
||||
@@ -190,7 +196,7 @@ public:
|
||||
void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
|
||||
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
|
||||
BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
|
||||
BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
|
||||
//BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
|
||||
|
||||
// Fill the buffer with a constant color
|
||||
void fill( const LLColor4U& color );
|
||||
@@ -232,7 +238,7 @@ public:
|
||||
|
||||
protected:
|
||||
// Create an image from a local file (generally used in tools)
|
||||
bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false);
|
||||
//bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false);
|
||||
|
||||
void copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step );
|
||||
void compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len );
|
||||
|
||||
@@ -435,7 +435,7 @@ bool LLImageDXT::convertToDXR()
|
||||
S32 nmips = calcNumMips(width,height);
|
||||
S32 total_bytes = getDataSize();
|
||||
U8* olddata = getData();
|
||||
U8* newdata = new (std::nothrow) U8[total_bytes];
|
||||
U8* newdata = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_bytes);
|
||||
if (!newdata)
|
||||
{
|
||||
llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl;
|
||||
|
||||
@@ -501,14 +501,14 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
|
||||
}
|
||||
else
|
||||
{
|
||||
U8 *data = new U8[file_size];
|
||||
U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size);
|
||||
apr_size_t bytes_read = file_size;
|
||||
apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read
|
||||
infile.close() ;
|
||||
|
||||
if (s != APR_SUCCESS || (S32)bytes_read != file_size)
|
||||
{
|
||||
delete[] data;
|
||||
FREE_MEM(LLImageBase::getPrivatePool(), data);
|
||||
setLastError("Unable to read entire file");
|
||||
res = FALSE;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "llinventory.h"
|
||||
|
||||
#include "lldbstrings.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llinventorydefines.h"
|
||||
#include "llxorcipher.h"
|
||||
#include "llsd.h"
|
||||
@@ -226,7 +227,7 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
|
||||
}
|
||||
|
||||
// exportFile should be replaced with exportLegacyStream
|
||||
// not sure whether exportLegacyStream(llofstream(fp)) would work, fp may need to get icramented...
|
||||
// not sure whether exportLegacyStream(llofstream(fp)) would work, fp may need to get incremented...
|
||||
BOOL LLInventoryObject::exportFile(LLFILE* fp, BOOL) const
|
||||
{
|
||||
std::string uuid_str;
|
||||
@@ -1055,8 +1056,11 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
|
||||
sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate;
|
||||
}
|
||||
|
||||
LLFastTimer::DeclareTimer FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize");
|
||||
|
||||
bool LLInventoryItem::fromLLSD(const LLSD& sd)
|
||||
{
|
||||
LLFastTimer _(FTM_INVENTORY_SD_DESERIALIZE);
|
||||
mInventoryType = LLInventoryType::IT_NONE;
|
||||
mAssetUUID.setNull();
|
||||
std::string w;
|
||||
|
||||
@@ -67,7 +67,6 @@ const F32 PARCEL_PASS_HOURS_DEFAULT = 1.f;
|
||||
|
||||
// Number of "chunks" in which parcel overlay data is sent
|
||||
// Chunk 0 = southern rows, entire width
|
||||
// NOTE: NOT USABLE FOR VAR SIZED REGIONS!
|
||||
const S32 PARCEL_OVERLAY_CHUNKS = 4;
|
||||
|
||||
// Bottom three bits are a color index for the land overlay
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "linden_common.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "llsaleinfo.h"
|
||||
|
||||
|
||||
@@ -75,10 +75,6 @@ set(llmath_HEADER_FILES
|
||||
llvector4a.h
|
||||
llvector4a.inl
|
||||
llvector4logical.h
|
||||
llv4math.h
|
||||
llv4matrix3.h
|
||||
llv4matrix4.h
|
||||
llv4vector3.h
|
||||
llvolume.h
|
||||
llvolumemgr.h
|
||||
llvolumeoctree.h
|
||||
|
||||
@@ -531,13 +531,13 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
|
||||
i++;
|
||||
}
|
||||
|
||||
S32 j = data.size()-1;
|
||||
S32 j = (S32)data.size()-1;
|
||||
while (j > 0 && data[j] > max)
|
||||
{
|
||||
j--;
|
||||
}
|
||||
|
||||
if (j < data.size()-1)
|
||||
if (j < (S32)data.size()-1)
|
||||
{
|
||||
data.erase(data.begin()+j, data.end());
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ inline void LLMatrix3a::setTranspose(const LLMatrix3a& src)
|
||||
const LLQuad srcCol1 = src.mColumns[1];
|
||||
const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 );
|
||||
mColumns[0] = _mm_movelh_ps( unpacklo, src.mColumns[2] );
|
||||
mColumns[1] = _mm_shuffle_ps( _mm_movehl_ps( srcCol0, unpacklo ), src.mColumns[2], _MM_SHUFFLE(0, 1, 1, 0) );
|
||||
mColumns[1] = _mm_shuffle_ps( unpacklo, src.mColumns[2], _MM_SHUFFLE(0, 1, 3, 2) );
|
||||
mColumns[2] = _mm_shuffle_ps( _mm_unpackhi_ps( srcCol0, srcCol1 ), src.mColumns[2], _MM_SHUFFLE(0, 2, 1, 0) );
|
||||
}
|
||||
|
||||
|
||||
@@ -104,25 +104,45 @@ public:
|
||||
mMatrix[2].setAdd(a.mMatrix[2],d2);
|
||||
mMatrix[3].setAdd(a.mMatrix[3],d3);
|
||||
}
|
||||
|
||||
inline void rotate(const LLVector4a& v, LLVector4a& res)
|
||||
|
||||
//Singu Note: Don't mess with this. It's intentionally different from LL's.
|
||||
// Note how res isn't manipulated until the very end.
|
||||
inline void rotate(const LLVector4a& v, LLVector4a& res) const
|
||||
{
|
||||
res = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
res.mul(mMatrix[0]);
|
||||
|
||||
LLVector4a y;
|
||||
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
y.mul(mMatrix[1]);
|
||||
LLVector4a x,y,z;
|
||||
|
||||
LLVector4a z;
|
||||
x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
x.mul(mMatrix[0]);
|
||||
y.mul(mMatrix[1]);
|
||||
z.mul(mMatrix[2]);
|
||||
|
||||
res.add(y);
|
||||
res.add(z);
|
||||
x.add(y);
|
||||
res.setAdd(x,z);
|
||||
}
|
||||
|
||||
inline void rotate4(const LLVector4a& v, LLVector4a& res) const
|
||||
{
|
||||
LLVector4a x,y,z,w;
|
||||
|
||||
x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
w = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
x.mul(mMatrix[0]);
|
||||
y.mul(mMatrix[1]);
|
||||
z.mul(mMatrix[2]);
|
||||
w.mul(mMatrix[3]);
|
||||
|
||||
x.add(y);
|
||||
z.add(w);
|
||||
res.setAdd(x,z);
|
||||
}
|
||||
|
||||
inline void affineTransform(const LLVector4a& v, LLVector4a& res)
|
||||
inline void affineTransform(const LLVector4a& v, LLVector4a& res) const
|
||||
{
|
||||
LLVector4a x,y,z;
|
||||
|
||||
|
||||
@@ -691,7 +691,7 @@ public:
|
||||
|
||||
if (lt != 0x7)
|
||||
{
|
||||
OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
|
||||
//OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
/**
|
||||
* @file llv4math.h
|
||||
* @brief LLV4* class header file - vector processor enabled math
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLV4MATH_H
|
||||
#define LL_LLV4MATH_H
|
||||
|
||||
// *NOTE: We do not support SSE acceleration on Windows builds.
|
||||
// Our minimum specification for the viewer includes 1 GHz Athlon processors,
|
||||
// which covers the Athlon Thunderbird series that does not support SSE.
|
||||
//
|
||||
// Our header files include statements like this
|
||||
// const F32 HAVOK_TIMESTEP = 1.f / 45.f;
|
||||
// This creates "globals" that are included in each .obj file. If a single
|
||||
// .cpp file has SSE code generation turned on (eg, llviewerjointmesh_sse.cpp)
|
||||
// these globals will be initialized using SSE instructions. This causes SL
|
||||
// to crash before main() on processors without SSE. Untangling all these
|
||||
// headers/variables is too much work for the small performance gains of
|
||||
// vectorization.
|
||||
//
|
||||
// Therefore we only support vectorization on builds where the everything is
|
||||
// built with SSE or Altivec. See https://jira.secondlife.com/browse/VWR-1610
|
||||
// and https://jira.lindenlab.com/browse/SL-47720 for details.
|
||||
//
|
||||
// Sorry the code is such a mess. JC
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4MATH - GNUC
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if LL_GNUC && __GNUC__ >= 4 && __SSE__
|
||||
|
||||
#define LL_VECTORIZE 1
|
||||
|
||||
#if LL_DARWIN
|
||||
|
||||
#include <Accelerate/Accelerate.h>
|
||||
#include <xmmintrin.h>
|
||||
typedef vFloat V4F32;
|
||||
|
||||
#else
|
||||
|
||||
#include <xmmintrin.h>
|
||||
typedef float V4F32 __attribute__((vector_size(16)));
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#if LL_GNUC
|
||||
|
||||
#define LL_LLV4MATH_ALIGN_PREFIX
|
||||
#define LL_LLV4MATH_ALIGN_POSTFIX __attribute__((aligned(16)))
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4MATH - MSVC
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Only vectorize if the entire Windows build uses SSE.
|
||||
// _M_IX86_FP is set when SSE code generation is turned on, and I have
|
||||
// confirmed this in VS2003, VS2003 SP1, and VS2005. JC
|
||||
#if LL_MSVC && _M_IX86_FP
|
||||
|
||||
#define LL_VECTORIZE 1
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
typedef __m128 V4F32;
|
||||
|
||||
#endif
|
||||
#if LL_MSVC
|
||||
|
||||
#define LL_LLV4MATH_ALIGN_PREFIX __declspec(align(16))
|
||||
#define LL_LLV4MATH_ALIGN_POSTFIX
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4MATH - default - no vectorization
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if !LL_VECTORIZE
|
||||
|
||||
#define LL_VECTORIZE 0
|
||||
|
||||
struct V4F32 { F32 __pad__[4]; };
|
||||
|
||||
inline F32 llv4lerp(F32 a, F32 b, F32 w) { return ( b - a ) * w + a; }
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef LL_LLV4MATH_ALIGN_PREFIX
|
||||
# define LL_LLV4MATH_ALIGN_PREFIX
|
||||
#endif
|
||||
#ifndef LL_LLV4MATH_ALIGN_POSTFIX
|
||||
# define LL_LLV4MATH_ALIGN_POSTFIX
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4MATH
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#define LLV4_NUM_AXIS 4
|
||||
|
||||
class LLV4Vector3;
|
||||
class LLV4Matrix3;
|
||||
class LLV4Matrix4;
|
||||
|
||||
#endif
|
||||
@@ -1,226 +0,0 @@
|
||||
/**
|
||||
* @file llviewerjointmesh.cpp
|
||||
* @brief LLV4* class header file - vector processor enabled math
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLV4MATRIX3_H
|
||||
#define LL_LLV4MATRIX3_H
|
||||
|
||||
#include "llv4math.h"
|
||||
#include "llv4vector3.h"
|
||||
#include "m3math.h" // for operator LLMatrix3()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix3
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LL_LLV4MATH_ALIGN_PREFIX
|
||||
|
||||
class LLV4Matrix3
|
||||
{
|
||||
public:
|
||||
union {
|
||||
F32 mMatrix[LLV4_NUM_AXIS][LLV4_NUM_AXIS];
|
||||
V4F32 mV[LLV4_NUM_AXIS];
|
||||
};
|
||||
|
||||
void lerp(const LLV4Matrix3 &a, const LLV4Matrix3 &b, const F32 &w);
|
||||
void multiply(const LLVector3 &a, LLVector3& out) const;
|
||||
void multiply(const LLVector4 &a, LLV4Vector3& out) const;
|
||||
void multiply(const LLVector3 &a, LLV4Vector3& out) const;
|
||||
|
||||
const LLV4Matrix3& transpose();
|
||||
const LLV4Matrix3& operator=(const LLMatrix3& a);
|
||||
|
||||
operator LLMatrix3() const { return (reinterpret_cast<const LLMatrix4*>(const_cast<const F32*>(&mMatrix[0][0])))->getMat3(); }
|
||||
|
||||
friend LLVector3 operator*(const LLVector3& a, const LLV4Matrix3& b);
|
||||
}
|
||||
|
||||
LL_LLV4MATH_ALIGN_POSTFIX;
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix3 - SSE
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if LL_VECTORIZE
|
||||
|
||||
inline void LLV4Matrix3::lerp(const LLV4Matrix3 &a, const LLV4Matrix3 &b, const F32 &w)
|
||||
{
|
||||
__m128 vw = _mm_set1_ps(w);
|
||||
mV[VX] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VX], a.mV[VX]), vw), a.mV[VX]); // ( b - a ) * w + a
|
||||
mV[VY] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VY], a.mV[VY]), vw), a.mV[VY]);
|
||||
mV[VZ] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VZ], a.mV[VZ]), vw), a.mV[VZ]);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector3 &a, LLVector3& o) const
|
||||
{
|
||||
LLV4Vector3 j;
|
||||
j.v = _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX]); // ( ax * vx ) + ...
|
||||
j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
|
||||
j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
|
||||
o.setVec(j.mV);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector4 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.v = _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX]); // ( ax * vx ) + ...
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector3 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.v = _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX]); // ( ax * vx ) + ...
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix3
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#else
|
||||
|
||||
inline void LLV4Matrix3::lerp(const LLV4Matrix3 &a, const LLV4Matrix3 &b, const F32 &w)
|
||||
{
|
||||
mMatrix[VX][VX] = llv4lerp(a.mMatrix[VX][VX], b.mMatrix[VX][VX], w);
|
||||
mMatrix[VX][VY] = llv4lerp(a.mMatrix[VX][VY], b.mMatrix[VX][VY], w);
|
||||
mMatrix[VX][VZ] = llv4lerp(a.mMatrix[VX][VZ], b.mMatrix[VX][VZ], w);
|
||||
|
||||
mMatrix[VY][VX] = llv4lerp(a.mMatrix[VY][VX], b.mMatrix[VY][VX], w);
|
||||
mMatrix[VY][VY] = llv4lerp(a.mMatrix[VY][VY], b.mMatrix[VY][VY], w);
|
||||
mMatrix[VY][VZ] = llv4lerp(a.mMatrix[VY][VZ], b.mMatrix[VY][VZ], w);
|
||||
|
||||
mMatrix[VZ][VX] = llv4lerp(a.mMatrix[VZ][VX], b.mMatrix[VZ][VX], w);
|
||||
mMatrix[VZ][VY] = llv4lerp(a.mMatrix[VZ][VY], b.mMatrix[VZ][VY], w);
|
||||
mMatrix[VZ][VZ] = llv4lerp(a.mMatrix[VZ][VZ], b.mMatrix[VZ][VZ], w);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector3 &a, LLVector3& o) const
|
||||
{
|
||||
o.setVec( a.mV[VX] * mMatrix[VX][VX] +
|
||||
a.mV[VY] * mMatrix[VY][VX] +
|
||||
a.mV[VZ] * mMatrix[VZ][VX],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VY] +
|
||||
a.mV[VY] * mMatrix[VY][VY] +
|
||||
a.mV[VZ] * mMatrix[VZ][VY],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VZ] +
|
||||
a.mV[VY] * mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * mMatrix[VZ][VZ]);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector4 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.setVec( a.mV[VX] * mMatrix[VX][VX] +
|
||||
a.mV[VY] * mMatrix[VY][VX] +
|
||||
a.mV[VZ] * mMatrix[VZ][VX],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VY] +
|
||||
a.mV[VY] * mMatrix[VY][VY] +
|
||||
a.mV[VZ] * mMatrix[VZ][VY],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VZ] +
|
||||
a.mV[VY] * mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * mMatrix[VZ][VZ]);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix3::multiply(const LLVector3 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.setVec( a.mV[VX] * mMatrix[VX][VX] +
|
||||
a.mV[VY] * mMatrix[VY][VX] +
|
||||
a.mV[VZ] * mMatrix[VZ][VX],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VY] +
|
||||
a.mV[VY] * mMatrix[VY][VY] +
|
||||
a.mV[VZ] * mMatrix[VZ][VY],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VZ] +
|
||||
a.mV[VY] * mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * mMatrix[VZ][VZ]);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix3
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
|
||||
inline const LLV4Matrix3& LLV4Matrix3::transpose()
|
||||
{
|
||||
#if LL_VECTORIZE && defined(_MM_TRANSPOSE4_PS)
|
||||
_MM_TRANSPOSE4_PS(mV[VX], mV[VY], mV[VZ], mV[VW]);
|
||||
return *this;
|
||||
#else
|
||||
F32 temp;
|
||||
temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp;
|
||||
temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp;
|
||||
temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const LLV4Matrix3& LLV4Matrix3::operator=(const LLMatrix3& a)
|
||||
{
|
||||
memcpy(mMatrix[VX], a.mMatrix[VX], sizeof(F32) * 3 );
|
||||
memcpy(mMatrix[VY], a.mMatrix[VY], sizeof(F32) * 3 );
|
||||
memcpy(mMatrix[VZ], a.mMatrix[VZ], sizeof(F32) * 3 );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline LLVector3 operator*(const LLVector3& a, const LLV4Matrix3& b)
|
||||
{
|
||||
return LLVector3(
|
||||
a.mV[VX] * b.mMatrix[VX][VX] +
|
||||
a.mV[VY] * b.mMatrix[VY][VX] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VX],
|
||||
|
||||
a.mV[VX] * b.mMatrix[VX][VY] +
|
||||
a.mV[VY] * b.mMatrix[VY][VY] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VY],
|
||||
|
||||
a.mV[VX] * b.mMatrix[VX][VZ] +
|
||||
a.mV[VY] * b.mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VZ] );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,255 +0,0 @@
|
||||
/**
|
||||
* @file llviewerjointmesh.cpp
|
||||
* @brief LLV4* class header file - vector processor enabled math
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLV4MATRIX4_H
|
||||
#define LL_LLV4MATRIX4_H
|
||||
|
||||
#include "llv4math.h"
|
||||
#include "llv4matrix3.h" // just for operator LLV4Matrix3()
|
||||
#include "llv4vector3.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix4
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LL_LLV4MATH_ALIGN_PREFIX
|
||||
|
||||
class LLV4Matrix4
|
||||
{
|
||||
public:
|
||||
union {
|
||||
F32 mMatrix[LLV4_NUM_AXIS][LLV4_NUM_AXIS];
|
||||
V4F32 mV[LLV4_NUM_AXIS];
|
||||
};
|
||||
|
||||
void lerp(const LLV4Matrix4 &a, const LLV4Matrix4 &b, const F32 &w);
|
||||
void multiply(const LLVector3 &a, LLVector3& o) const;
|
||||
void multiply(const LLVector3 &a, LLV4Vector3& o) const;
|
||||
|
||||
const LLV4Matrix4& transpose();
|
||||
const LLV4Matrix4& translate(const LLVector3 &vec);
|
||||
const LLV4Matrix4& translate(const LLV4Vector3 &vec);
|
||||
const LLV4Matrix4& operator=(const LLMatrix4& a);
|
||||
|
||||
operator LLMatrix4() const { return *(reinterpret_cast<const LLMatrix4*>(const_cast<const F32*>(&mMatrix[0][0]))); }
|
||||
operator LLV4Matrix3() const { return *(reinterpret_cast<const LLV4Matrix3*>(const_cast<const F32*>(&mMatrix[0][0]))); }
|
||||
|
||||
friend LLVector3 operator*(const LLVector3 &a, const LLV4Matrix4 &b);
|
||||
}
|
||||
|
||||
LL_LLV4MATH_ALIGN_POSTFIX;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix4 - SSE
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if LL_VECTORIZE
|
||||
|
||||
inline void LLV4Matrix4::lerp(const LLV4Matrix4 &a, const LLV4Matrix4 &b, const F32 &w)
|
||||
{
|
||||
__m128 vw = _mm_set1_ps(w);
|
||||
mV[VX] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VX], a.mV[VX]), vw), a.mV[VX]); // ( b - a ) * w + a
|
||||
mV[VY] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VY], a.mV[VY]), vw), a.mV[VY]);
|
||||
mV[VZ] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VZ], a.mV[VZ]), vw), a.mV[VZ]);
|
||||
mV[VW] = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(b.mV[VW], a.mV[VW]), vw), a.mV[VW]);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix4::multiply(const LLVector3 &a, LLVector3& o) const
|
||||
{
|
||||
LLV4Vector3 j;
|
||||
j.v = _mm_add_ps(mV[VW], _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX])); // ( ax * vx ) + vw
|
||||
j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
|
||||
j.v = _mm_add_ps(j.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
|
||||
o.setVec(j.mV);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix4::multiply(const LLVector3 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.v = _mm_add_ps(mV[VW], _mm_mul_ps(_mm_set1_ps(a.mV[VX]), mV[VX])); // ( ax * vx ) + vw
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VY]), mV[VY]));
|
||||
o.v = _mm_add_ps(o.v , _mm_mul_ps(_mm_set1_ps(a.mV[VZ]), mV[VZ]));
|
||||
}
|
||||
|
||||
inline const LLV4Matrix4& LLV4Matrix4::translate(const LLV4Vector3 &vec)
|
||||
{
|
||||
mV[VW] = _mm_add_ps(mV[VW], vec.v);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix4
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#else
|
||||
|
||||
inline void LLV4Matrix4::lerp(const LLV4Matrix4 &a, const LLV4Matrix4 &b, const F32 &w)
|
||||
{
|
||||
mMatrix[VX][VX] = llv4lerp(a.mMatrix[VX][VX], b.mMatrix[VX][VX], w);
|
||||
mMatrix[VX][VY] = llv4lerp(a.mMatrix[VX][VY], b.mMatrix[VX][VY], w);
|
||||
mMatrix[VX][VZ] = llv4lerp(a.mMatrix[VX][VZ], b.mMatrix[VX][VZ], w);
|
||||
|
||||
mMatrix[VY][VX] = llv4lerp(a.mMatrix[VY][VX], b.mMatrix[VY][VX], w);
|
||||
mMatrix[VY][VY] = llv4lerp(a.mMatrix[VY][VY], b.mMatrix[VY][VY], w);
|
||||
mMatrix[VY][VZ] = llv4lerp(a.mMatrix[VY][VZ], b.mMatrix[VY][VZ], w);
|
||||
|
||||
mMatrix[VZ][VX] = llv4lerp(a.mMatrix[VZ][VX], b.mMatrix[VZ][VX], w);
|
||||
mMatrix[VZ][VY] = llv4lerp(a.mMatrix[VZ][VY], b.mMatrix[VZ][VY], w);
|
||||
mMatrix[VZ][VZ] = llv4lerp(a.mMatrix[VZ][VZ], b.mMatrix[VZ][VZ], w);
|
||||
|
||||
mMatrix[VW][VX] = llv4lerp(a.mMatrix[VW][VX], b.mMatrix[VW][VX], w);
|
||||
mMatrix[VW][VY] = llv4lerp(a.mMatrix[VW][VY], b.mMatrix[VW][VY], w);
|
||||
mMatrix[VW][VZ] = llv4lerp(a.mMatrix[VW][VZ], b.mMatrix[VW][VZ], w);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix4::multiply(const LLVector3 &a, LLVector3& o) const
|
||||
{
|
||||
o.setVec( a.mV[VX] * mMatrix[VX][VX] +
|
||||
a.mV[VY] * mMatrix[VY][VX] +
|
||||
a.mV[VZ] * mMatrix[VZ][VX] +
|
||||
mMatrix[VW][VX],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VY] +
|
||||
a.mV[VY] * mMatrix[VY][VY] +
|
||||
a.mV[VZ] * mMatrix[VZ][VY] +
|
||||
mMatrix[VW][VY],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VZ] +
|
||||
a.mV[VY] * mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * mMatrix[VZ][VZ] +
|
||||
mMatrix[VW][VZ]);
|
||||
}
|
||||
|
||||
inline void LLV4Matrix4::multiply(const LLVector3 &a, LLV4Vector3& o) const
|
||||
{
|
||||
o.setVec( a.mV[VX] * mMatrix[VX][VX] +
|
||||
a.mV[VY] * mMatrix[VY][VX] +
|
||||
a.mV[VZ] * mMatrix[VZ][VX] +
|
||||
mMatrix[VW][VX],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VY] +
|
||||
a.mV[VY] * mMatrix[VY][VY] +
|
||||
a.mV[VZ] * mMatrix[VZ][VY] +
|
||||
mMatrix[VW][VY],
|
||||
|
||||
a.mV[VX] * mMatrix[VX][VZ] +
|
||||
a.mV[VY] * mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * mMatrix[VZ][VZ] +
|
||||
mMatrix[VW][VZ]);
|
||||
}
|
||||
|
||||
inline const LLV4Matrix4& LLV4Matrix4::translate(const LLV4Vector3 &vec)
|
||||
{
|
||||
mMatrix[3][0] += vec.mV[0];
|
||||
mMatrix[3][1] += vec.mV[1];
|
||||
mMatrix[3][2] += vec.mV[2];
|
||||
return (*this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Matrix4
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
|
||||
inline const LLV4Matrix4& LLV4Matrix4::operator=(const LLMatrix4& a)
|
||||
{
|
||||
memcpy(mMatrix, a.mMatrix, sizeof(F32) * 16 );
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const LLV4Matrix4& LLV4Matrix4::transpose()
|
||||
{
|
||||
#if LL_VECTORIZE && defined(_MM_TRANSPOSE4_PS)
|
||||
_MM_TRANSPOSE4_PS(mV[VX], mV[VY], mV[VZ], mV[VW]);
|
||||
#else
|
||||
LLV4Matrix4 mat;
|
||||
mat.mMatrix[0][0] = mMatrix[0][0];
|
||||
mat.mMatrix[1][0] = mMatrix[0][1];
|
||||
mat.mMatrix[2][0] = mMatrix[0][2];
|
||||
mat.mMatrix[3][0] = mMatrix[0][3];
|
||||
|
||||
mat.mMatrix[0][1] = mMatrix[1][0];
|
||||
mat.mMatrix[1][1] = mMatrix[1][1];
|
||||
mat.mMatrix[2][1] = mMatrix[1][2];
|
||||
mat.mMatrix[3][1] = mMatrix[1][3];
|
||||
|
||||
mat.mMatrix[0][2] = mMatrix[2][0];
|
||||
mat.mMatrix[1][2] = mMatrix[2][1];
|
||||
mat.mMatrix[2][2] = mMatrix[2][2];
|
||||
mat.mMatrix[3][2] = mMatrix[2][3];
|
||||
|
||||
mat.mMatrix[0][3] = mMatrix[3][0];
|
||||
mat.mMatrix[1][3] = mMatrix[3][1];
|
||||
mat.mMatrix[2][3] = mMatrix[3][2];
|
||||
mat.mMatrix[3][3] = mMatrix[3][3];
|
||||
|
||||
*this = mat;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const LLV4Matrix4& LLV4Matrix4::translate(const LLVector3 &vec)
|
||||
{
|
||||
mMatrix[3][0] += vec.mV[0];
|
||||
mMatrix[3][1] += vec.mV[1];
|
||||
mMatrix[3][2] += vec.mV[2];
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline LLVector3 operator*(const LLVector3 &a, const LLV4Matrix4 &b)
|
||||
{
|
||||
return LLVector3(a.mV[VX] * b.mMatrix[VX][VX] +
|
||||
a.mV[VY] * b.mMatrix[VY][VX] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VX] +
|
||||
b.mMatrix[VW][VX],
|
||||
|
||||
a.mV[VX] * b.mMatrix[VX][VY] +
|
||||
a.mV[VY] * b.mMatrix[VY][VY] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VY] +
|
||||
b.mMatrix[VW][VY],
|
||||
|
||||
a.mV[VX] * b.mMatrix[VX][VZ] +
|
||||
a.mV[VY] * b.mMatrix[VY][VZ] +
|
||||
a.mV[VZ] * b.mMatrix[VZ][VZ] +
|
||||
b.mMatrix[VW][VZ]);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* @file llviewerjointmesh.cpp
|
||||
* @brief LLV4* class header file - vector processor enabled math
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLV4VECTOR3_H
|
||||
#define LL_LLV4VECTOR3_H
|
||||
|
||||
#include "llv4math.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Vector3
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LL_LLV4MATH_ALIGN_PREFIX
|
||||
|
||||
class LLV4Vector3
|
||||
{
|
||||
public:
|
||||
union {
|
||||
F32 mV[LLV4_NUM_AXIS];
|
||||
V4F32 v;
|
||||
};
|
||||
|
||||
enum {
|
||||
ALIGNMENT = 16
|
||||
};
|
||||
|
||||
void setVec(F32 x, F32 y, F32 z);
|
||||
void setVec(F32 a);
|
||||
}
|
||||
|
||||
LL_LLV4MATH_ALIGN_POSTFIX;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLV4Vector3
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline void LLV4Vector3::setVec(F32 x, F32 y, F32 z)
|
||||
{
|
||||
mV[VX] = x;
|
||||
mV[VY] = y;
|
||||
mV[VZ] = z;
|
||||
}
|
||||
|
||||
inline void LLV4Vector3::setVec(F32 a)
|
||||
{
|
||||
#if LL_VECTORIZE
|
||||
v = _mm_set1_ps(a);
|
||||
#else
|
||||
setVec(a, a, a);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2079,15 +2079,14 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge
|
||||
mFaceMask = 0x0;
|
||||
mDetail = detail;
|
||||
mSculptLevel = -2;
|
||||
#if MESH_ENABLED
|
||||
mSurfaceArea = 1.f; //only calculated for sculpts, defaults to 1 for all other prims
|
||||
mIsMeshAssetLoaded = FALSE;
|
||||
mLODScaleBias.setVec(1,1,1);
|
||||
mHullPoints = NULL;
|
||||
mHullIndices = NULL;
|
||||
mNumHullPoints = 0;
|
||||
mNumHullIndices = 0;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
|
||||
// set defaults
|
||||
if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
|
||||
{
|
||||
@@ -2139,12 +2138,10 @@ LLVolume::~LLVolume()
|
||||
mProfilep = NULL;
|
||||
mVolumeFaces.clear();
|
||||
|
||||
#if MESH_ENABLED
|
||||
ll_aligned_free_16(mHullPoints);
|
||||
mHullPoints = NULL;
|
||||
ll_aligned_free_16(mHullIndices);
|
||||
mHullIndices = NULL;
|
||||
#endif //MESH_ENABLED
|
||||
}
|
||||
|
||||
BOOL LLVolume::generate()
|
||||
@@ -2186,7 +2183,7 @@ BOOL LLVolume::generate()
|
||||
mLODScaleBias.setVec(0.6f, 0.6f, 0.6f);
|
||||
}
|
||||
|
||||
//********************************************************************
|
||||
// ********************************************************************
|
||||
//debug info, to be removed
|
||||
if((U32)(mPathp->mPath.size() * mProfilep->mProfile.size()) > (1u << 20))
|
||||
{
|
||||
@@ -2198,7 +2195,7 @@ BOOL LLVolume::generate()
|
||||
|
||||
llerrs << "LLVolume corrupted!" << llendl ;
|
||||
}
|
||||
//********************************************************************
|
||||
// ********************************************************************
|
||||
|
||||
BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split);
|
||||
BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split);
|
||||
@@ -2208,7 +2205,7 @@ BOOL LLVolume::generate()
|
||||
S32 sizeS = mPathp->mPath.size();
|
||||
S32 sizeT = mProfilep->mProfile.size();
|
||||
|
||||
//********************************************************************
|
||||
// ********************************************************************
|
||||
//debug info, to be removed
|
||||
if((U32)(sizeS * sizeT) > (1u << 20))
|
||||
{
|
||||
@@ -2221,7 +2218,7 @@ BOOL LLVolume::generate()
|
||||
|
||||
llerrs << "LLVolume corrupted!" << llendl ;
|
||||
}
|
||||
//********************************************************************
|
||||
// ********************************************************************
|
||||
|
||||
sNumMeshPoints -= mMesh.size();
|
||||
mMesh.resize(sizeT * sizeS);
|
||||
@@ -2406,7 +2403,6 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
|
||||
{
|
||||
//input stream is now pointing at a zlib compressed block of LLSD
|
||||
@@ -2736,7 +2732,7 @@ void LLVolume::cacheOptimize()
|
||||
mVolumeFaces[i].cacheOptimize();
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
|
||||
S32 LLVolume::getNumFaces() const
|
||||
{
|
||||
@@ -3157,6 +3153,8 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components,
|
||||
{
|
||||
F32 area = sculptGetSurfaceArea();
|
||||
|
||||
mSurfaceArea = area;
|
||||
|
||||
const F32 SCULPT_MAX_AREA = 384.f;
|
||||
|
||||
if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA)
|
||||
@@ -3205,12 +3203,10 @@ bool LLVolumeParams::isSculpt() const
|
||||
return mSculptID.notNull();
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
bool LLVolumeParams::isMeshSculpt() const
|
||||
{
|
||||
return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const
|
||||
{
|
||||
@@ -4320,15 +4316,25 @@ S32 LLVolume::getNumTriangleIndices() const
|
||||
}
|
||||
|
||||
|
||||
S32 LLVolume::getNumTriangles() const
|
||||
S32 LLVolume::getNumTriangles(S32* vcount) const
|
||||
{
|
||||
U32 triangle_count = 0;
|
||||
U32 vertex_count = 0;
|
||||
|
||||
for (S32 i = 0; i < getNumVolumeFaces(); ++i)
|
||||
{
|
||||
triangle_count += getVolumeFace(i).mNumIndices/3;
|
||||
const LLVolumeFace& face = getVolumeFace(i);
|
||||
triangle_count += face.mNumIndices/3;
|
||||
|
||||
vertex_count += face.mNumVertices;
|
||||
}
|
||||
|
||||
|
||||
if (vcount)
|
||||
{
|
||||
*vcount = vertex_count;
|
||||
}
|
||||
|
||||
return triangle_count;
|
||||
}
|
||||
|
||||
@@ -4357,13 +4363,11 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
||||
vertices.clear();
|
||||
normals.clear();
|
||||
|
||||
#if MESH_ENABLED
|
||||
if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
|
||||
S32 cur_index = 0;
|
||||
//for each face
|
||||
for (face_list_t::iterator iter = mVolumeFaces.begin();
|
||||
@@ -4622,18 +4626,83 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
|
||||
genBinormals(i);
|
||||
}
|
||||
|
||||
if (!face.mOctree)
|
||||
{
|
||||
face.createOctree();
|
||||
}
|
||||
|
||||
//LLVector4a* p = (LLVector4a*) face.mPositions;
|
||||
if (isUnique())
|
||||
{ //don't bother with an octree for flexi volumes
|
||||
U32 tri_count = face.mNumIndices/3;
|
||||
|
||||
LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
|
||||
intersect.traverse(face.mOctree);
|
||||
if (intersect.mHitFace)
|
||||
for (U32 j = 0; j < tri_count; ++j)
|
||||
{
|
||||
U16 idx0 = face.mIndices[j*3+0];
|
||||
U16 idx1 = face.mIndices[j*3+1];
|
||||
U16 idx2 = face.mIndices[j*3+2];
|
||||
|
||||
const LLVector4a& v0 = face.mPositions[idx0];
|
||||
const LLVector4a& v1 = face.mPositions[idx1];
|
||||
const LLVector4a& v2 = face.mPositions[idx2];
|
||||
|
||||
F32 a,b,t;
|
||||
|
||||
if (LLTriangleRayIntersect(v0, v1, v2,
|
||||
start, dir, a, b, t))
|
||||
{
|
||||
if ((t >= 0.f) && // if hit is after start
|
||||
(t <= 1.f) && // and before end
|
||||
(t < closest_t)) // and this hit is closer
|
||||
{
|
||||
closest_t = t;
|
||||
hit_face = i;
|
||||
|
||||
if (intersection != NULL)
|
||||
{
|
||||
LLVector4a intersect = dir;
|
||||
intersect.mul(closest_t);
|
||||
intersect.add(start);
|
||||
intersection->set(intersect.getF32ptr());
|
||||
}
|
||||
|
||||
|
||||
if (tex_coord != NULL)
|
||||
{
|
||||
LLVector2* tc = (LLVector2*) face.mTexCoords;
|
||||
*tex_coord = ((1.f - a - b) * tc[idx0] +
|
||||
a * tc[idx1] +
|
||||
b * tc[idx2]);
|
||||
|
||||
}
|
||||
|
||||
if (normal!= NULL)
|
||||
{
|
||||
LLVector4* norm = (LLVector4*) face.mNormals;
|
||||
|
||||
*normal = ((1.f - a - b) * LLVector3(norm[idx0]) +
|
||||
a * LLVector3(norm[idx1]) +
|
||||
b * LLVector3(norm[idx2]));
|
||||
}
|
||||
|
||||
if (bi_normal != NULL)
|
||||
{
|
||||
LLVector4* binormal = (LLVector4*) face.mBinormals;
|
||||
*bi_normal = ((1.f - a - b) * LLVector3(binormal[idx0]) +
|
||||
a * LLVector3(binormal[idx1]) +
|
||||
b * LLVector3(binormal[idx2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hit_face = i;
|
||||
if (!face.mOctree)
|
||||
{
|
||||
face.createOctree();
|
||||
}
|
||||
|
||||
LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
|
||||
intersect.traverse(face.mOctree);
|
||||
if (intersect.mHitFace)
|
||||
{
|
||||
hit_face = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5414,9 +5483,7 @@ LLVolumeFace::LLVolumeFace() :
|
||||
mBinormals(NULL),
|
||||
mTexCoords(NULL),
|
||||
mIndices(NULL),
|
||||
#if MESH_ENABLED
|
||||
mWeights(NULL),
|
||||
#endif //MESH_ENABLED
|
||||
mOctree(NULL)
|
||||
{
|
||||
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
||||
@@ -5439,9 +5506,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
|
||||
mBinormals(NULL),
|
||||
mTexCoords(NULL),
|
||||
mIndices(NULL),
|
||||
#if MESH_ENABLED
|
||||
mWeights(NULL),
|
||||
#endif //MESH_ENABLED
|
||||
mOctree(NULL)
|
||||
{
|
||||
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
||||
@@ -5507,7 +5572,6 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
||||
mBinormals = NULL;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (src.mWeights)
|
||||
{
|
||||
allocateWeights(src.mNumVertices);
|
||||
@@ -5518,8 +5582,8 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = NULL;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
}
|
||||
|
||||
if (mNumIndices)
|
||||
{
|
||||
S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF;
|
||||
@@ -5551,10 +5615,8 @@ void LLVolumeFace::freeData()
|
||||
mIndices = NULL;
|
||||
ll_aligned_free_16(mBinormals);
|
||||
mBinormals = NULL;
|
||||
#if MESH_ENABLED
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = NULL;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
delete mOctree;
|
||||
mOctree = NULL;
|
||||
@@ -6125,13 +6187,11 @@ void LLVolumeFace::cacheOptimize()
|
||||
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
LLVector2* tc = (LLVector2*) ll_aligned_malloc_16(size);
|
||||
|
||||
#if MESH_ENABLED
|
||||
LLVector4a* wght = NULL;
|
||||
if (mWeights)
|
||||
{
|
||||
wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLVector4a* binorm = NULL;
|
||||
if (mBinormals)
|
||||
@@ -6155,12 +6215,10 @@ void LLVolumeFace::cacheOptimize()
|
||||
pos[cur_idx] = mPositions[idx];
|
||||
norm[cur_idx] = mNormals[idx];
|
||||
tc[cur_idx] = mTexCoords[idx];
|
||||
#if MESH_ENABLED
|
||||
if (mWeights)
|
||||
{
|
||||
wght[cur_idx] = mWeights[idx];
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
if (mBinormals)
|
||||
{
|
||||
binorm[cur_idx] = mBinormals[idx];
|
||||
@@ -6178,17 +6236,13 @@ void LLVolumeFace::cacheOptimize()
|
||||
ll_aligned_free_16(mPositions);
|
||||
ll_aligned_free_16(mNormals);
|
||||
ll_aligned_free_16(mTexCoords);
|
||||
#if MESH_ENABLED
|
||||
ll_aligned_free_16(mWeights);
|
||||
#endif //MESH_ENABLED
|
||||
ll_aligned_free_16(mBinormals);
|
||||
|
||||
mPositions = pos;
|
||||
mNormals = norm;
|
||||
mTexCoords = tc;
|
||||
#if MESH_ENABLED
|
||||
mWeights = wght;
|
||||
#endif //MESH_ENABLED
|
||||
mBinormals = binorm;
|
||||
|
||||
//std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
|
||||
@@ -6276,6 +6330,7 @@ void LLVolumeFace::swapData(LLVolumeFace& rhs)
|
||||
llswap(rhs.mNumVertices, mNumVertices);
|
||||
llswap(rhs.mNumIndices, mNumIndices);
|
||||
}
|
||||
|
||||
void LerpPlanarVertex(LLVolumeFace::VertexData& v0,
|
||||
LLVolumeFace::VertexData& v1,
|
||||
LLVolumeFace::VertexData& v2,
|
||||
@@ -6971,14 +7026,11 @@ void LLVolumeFace::allocateBinormals(S32 num_verts)
|
||||
mBinormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
void LLVolumeFace::allocateWeights(S32 num_verts)
|
||||
{
|
||||
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
void LLVolumeFace::resizeIndices(S32 num_indices)
|
||||
{
|
||||
@@ -7141,9 +7193,8 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
|
||||
{
|
||||
resizeVertices(num_vertices);
|
||||
resizeIndices(num_indices);
|
||||
#if MESH_ENABLED
|
||||
|
||||
if (!volume->isMeshAssetLoaded())
|
||||
#endif //MESH_ENABLED
|
||||
{
|
||||
mEdge.resize(num_indices);
|
||||
}
|
||||
|
||||
@@ -191,21 +191,14 @@ const U8 LL_SCULPT_TYPE_SPHERE = 1;
|
||||
const U8 LL_SCULPT_TYPE_TORUS = 2;
|
||||
const U8 LL_SCULPT_TYPE_PLANE = 3;
|
||||
const U8 LL_SCULPT_TYPE_CYLINDER = 4;
|
||||
#if MESH_ENABLED
|
||||
const U8 LL_SCULPT_TYPE_MESH = 5;
|
||||
const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
|
||||
LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
|
||||
#endif //MESH_ENABLED
|
||||
#if !MESH_ENABLED
|
||||
const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER;
|
||||
#endif //!MESH_ENABLED
|
||||
|
||||
const U8 LL_SCULPT_FLAG_INVERT = 64;
|
||||
const U8 LL_SCULPT_FLAG_MIRROR = 128;
|
||||
|
||||
#if MESH_ENABLED
|
||||
const S32 LL_SCULPT_MESH_MAX_FACES = 8;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
class LLProfileParams
|
||||
{
|
||||
@@ -655,9 +648,7 @@ public:
|
||||
const LLUUID& getSculptID() const { return mSculptID; }
|
||||
const U8& getSculptType() const { return mSculptType; }
|
||||
bool isSculpt() const;
|
||||
#if MESH_ENABLED
|
||||
bool isMeshSculpt() const;
|
||||
#endif //MESH_ENABLED
|
||||
bool isMeshSculpt() const;
|
||||
BOOL isConvex() const;
|
||||
|
||||
// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
|
||||
@@ -865,9 +856,7 @@ public:
|
||||
|
||||
void resizeVertices(S32 num_verts);
|
||||
void allocateBinormals(S32 num_verts);
|
||||
#if MESH_ENABLED
|
||||
void allocateWeights(S32 num_verts);
|
||||
#endif //MESH_ENABLED
|
||||
void resizeIndices(S32 num_indices);
|
||||
void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
|
||||
|
||||
@@ -939,12 +928,10 @@ public:
|
||||
|
||||
std::vector<S32> mEdge;
|
||||
|
||||
#if MESH_ENABLED
|
||||
//list of skin weights for rigged volumes
|
||||
// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
|
||||
// mWeights.size() should be empty or match mVertices.size()
|
||||
LLVector4a* mWeights;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLOctreeNode<LLVolumeTriangle>* mOctree;
|
||||
|
||||
@@ -958,12 +945,7 @@ class LLVolume : public LLRefCount
|
||||
{
|
||||
friend class LLVolumeLODGroup;
|
||||
|
||||
#if MESH_ENABLED
|
||||
protected:
|
||||
#endif //MESH_ENABLED
|
||||
#if !MESH_ENABLED
|
||||
private:
|
||||
#endif //!MESH_ENABLED
|
||||
LLVolume(const LLVolume&); // Don't implement
|
||||
~LLVolume(); // use unref
|
||||
|
||||
@@ -989,6 +971,7 @@ public:
|
||||
S32 getNumFaces() const;
|
||||
S32 getNumVolumeFaces() const { return mVolumeFaces.size(); }
|
||||
F32 getDetail() const { return mDetail; }
|
||||
F32 getSurfaceArea() const { return mSurfaceArea; }
|
||||
const LLVolumeParams& getParams() const { return mParams; }
|
||||
LLVolumeParams getCopyOfParams() const { return mParams; }
|
||||
const LLProfile& getProfile() const { return *mProfilep; }
|
||||
@@ -1016,7 +999,7 @@ public:
|
||||
S32 getNumTriangleIndices() const;
|
||||
static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts);
|
||||
|
||||
S32 getNumTriangles() const;
|
||||
S32 getNumTriangles(S32* vcount = NULL) const;
|
||||
|
||||
void generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
||||
std::vector<LLVector3> &normals,
|
||||
@@ -1081,37 +1064,33 @@ private:
|
||||
protected:
|
||||
BOOL generate();
|
||||
void createVolumeFaces();
|
||||
#if MESH_ENABLED
|
||||
public:
|
||||
virtual bool unpackVolumeFaces(std::istream& is, S32 size);
|
||||
|
||||
virtual void setMeshAssetLoaded(BOOL loaded);
|
||||
virtual BOOL isMeshAssetLoaded();
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
protected:
|
||||
BOOL mUnique;
|
||||
F32 mDetail;
|
||||
S32 mSculptLevel;
|
||||
#if MESH_ENABLED
|
||||
F32 mSurfaceArea; //unscaled surface area
|
||||
BOOL mIsMeshAssetLoaded;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLVolumeParams mParams;
|
||||
LLPath *mPathp;
|
||||
LLProfile *mProfilep;
|
||||
std::vector<Point> mMesh;
|
||||
|
||||
|
||||
BOOL mGenerateSingleFace;
|
||||
typedef std::vector<LLVolumeFace> face_list_t;
|
||||
face_list_t mVolumeFaces;
|
||||
|
||||
#if MESH_ENABLED
|
||||
|
||||
public:
|
||||
LLVector4a* mHullPoints;
|
||||
U16* mHullIndices;
|
||||
S32 mNumHullPoints;
|
||||
S32 mNumHullIndices;
|
||||
#endif //MESH_ENABLED
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
|
||||
|
||||
@@ -154,7 +154,7 @@ void LLVolumeMgr::unrefVolume(LLVolume *volumep)
|
||||
volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
|
||||
if( iter == mVolumeLODGroups.end() )
|
||||
{
|
||||
llwarns << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
|
||||
llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
|
||||
if (mDataMutex)
|
||||
{
|
||||
mDataMutex->unlock();
|
||||
|
||||
@@ -74,6 +74,7 @@ BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, c
|
||||
return (grt & 0x7) ? false : true;
|
||||
}
|
||||
|
||||
|
||||
LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node)
|
||||
{
|
||||
node->addListener(this);
|
||||
|
||||
@@ -57,8 +57,8 @@ public:
|
||||
{
|
||||
U8 mV[LENGTHOFCOLOR4U];
|
||||
U32 mAll;
|
||||
LLColor4* mSources;
|
||||
LLColor4U* mSourcesU;
|
||||
//LLColor4* mSources;
|
||||
//LLColor4U* mSourcesU;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -39,13 +39,10 @@
|
||||
const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f
|
||||
const F32 MIN_OBJECT_Z = -256.f;
|
||||
const F32 DEFAULT_MAX_PRIM_SCALE = 256.f;
|
||||
#if MESH_ENABLED
|
||||
const F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = DEFAULT_MAX_PRIM_SCALE;
|
||||
#endif //MESH_ENABLED
|
||||
const F32 MIN_PRIM_SCALE = 0.01f;
|
||||
const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX
|
||||
|
||||
|
||||
class LLXform
|
||||
{
|
||||
protected:
|
||||
|
||||
@@ -30,13 +30,13 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
//*****************************************************************************
|
||||
// *****************************************************************************
|
||||
// llclassifiedflags.cpp
|
||||
//
|
||||
// Some exported symbols and functions for dealing with classified flags.
|
||||
//
|
||||
// Copyright 2005, Linden Research, Inc
|
||||
//*****************************************************************************
|
||||
// *****************************************************************************
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
|
||||
@@ -395,7 +395,7 @@ U32 LLCurl::Easy::report(CURLcode code)
|
||||
if (code == CURLE_OK)
|
||||
{
|
||||
check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode));
|
||||
//*TODO: get reason from first line of mHeaderOutput
|
||||
// *TODO: get reason from first line of mHeaderOutput
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -715,7 +715,7 @@ S32 LLCurl::Multi::process()
|
||||
else
|
||||
{
|
||||
response = 499;
|
||||
//*TODO: change to llwarns
|
||||
// *TODO: change to llwarns
|
||||
llerrs << "cleaned up curl request completed!" << llendl;
|
||||
}
|
||||
if (response >= 400)
|
||||
|
||||
@@ -91,6 +91,8 @@
|
||||
#include "llsdserialize.h"
|
||||
#include "lluuid.h"
|
||||
|
||||
#include "llfasttimer.h"
|
||||
|
||||
// spammy mode
|
||||
//#define LL_SPEW_STREAM_OUT_DEBUGGING 1
|
||||
|
||||
@@ -314,6 +316,7 @@ LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse()
|
||||
}
|
||||
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_RESPONSE("SD2XMLRPC Response");
|
||||
// virtual
|
||||
LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
@@ -322,6 +325,8 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_SD2XMLRPC_RESPONSE);
|
||||
|
||||
PUMP_DEBUG;
|
||||
// This pipe does not work if it does not have everyting. This
|
||||
// could be addressed by making a stream parser for llsd which
|
||||
@@ -388,6 +393,8 @@ LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest()
|
||||
{
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_REQUEST("S22XMLRPC Request");
|
||||
|
||||
// virtual
|
||||
LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
@@ -396,6 +403,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_SD2XMLRPC_REQUEST);
|
||||
// This pipe does not work if it does not have everyting. This
|
||||
// could be addressed by making a stream parser for llsd which
|
||||
// handled partial information.
|
||||
@@ -592,6 +600,8 @@ LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD()
|
||||
{
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_RESPONSE("XMLRPC2LLSD Response");
|
||||
|
||||
LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
@@ -599,6 +609,8 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_RESPONSE);
|
||||
|
||||
PUMP_DEBUG;
|
||||
if(!eos) return STATUS_BREAK;
|
||||
if(!buffer) return STATUS_ERROR;
|
||||
@@ -674,6 +686,7 @@ LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD()
|
||||
{
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_REQUEST("XMLRPC2LLSD Request");
|
||||
LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
@@ -681,6 +694,7 @@ LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_REQUEST);
|
||||
PUMP_DEBUG;
|
||||
if(!eos) return STATUS_BREAK;
|
||||
if(!buffer) return STATUS_ERROR;
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "llstat.h"
|
||||
#include "llstl.h"
|
||||
#include "lltimer.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
@@ -146,6 +147,7 @@ private:
|
||||
LLSD mHeaders;
|
||||
};
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_PIPE("HTTP Pipe");
|
||||
LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
@@ -153,6 +155,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_HTTP_PIPE);
|
||||
PUMP_DEBUG;
|
||||
lldebugs << "LLSDHTTPServer::process_impl" << llendl;
|
||||
|
||||
@@ -434,6 +437,9 @@ protected:
|
||||
/**
|
||||
* LLHTTPResponseHeader
|
||||
*/
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_HEADER("HTTP Header");
|
||||
|
||||
// virtual
|
||||
LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
@@ -442,6 +448,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_HTTP_HEADER);
|
||||
PUMP_DEBUG;
|
||||
LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
|
||||
if(eos)
|
||||
@@ -636,6 +643,8 @@ void LLHTTPResponder::markBad(
|
||||
<< "</body>\n</html>\n";
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_RESPONDER("HTTP Responder");
|
||||
|
||||
// virtual
|
||||
LLIOPipe::EStatus LLHTTPResponder::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
@@ -644,6 +653,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_HTTP_RESPONDER);
|
||||
PUMP_DEBUG;
|
||||
LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
|
||||
LLIOPipe::EStatus status = STATUS_OK;
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "llmemtype.h"
|
||||
#include "llpumpio.h"
|
||||
#include "llthread.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
//
|
||||
// constants
|
||||
@@ -290,6 +291,8 @@ LLIOSocketReader::~LLIOSocketReader()
|
||||
//lldebugs << "Destroying LLIOSocketReader" << llendl;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_SOCKET_READER("Socket Reader");
|
||||
|
||||
// virtual
|
||||
LLIOPipe::EStatus LLIOSocketReader::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
@@ -298,6 +301,7 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_SOCKET_READER);
|
||||
PUMP_DEBUG;
|
||||
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
||||
if(!mSource) return STATUS_PRECONDITION_NOT_MET;
|
||||
@@ -390,6 +394,7 @@ LLIOSocketWriter::~LLIOSocketWriter()
|
||||
//lldebugs << "Destroying LLIOSocketWriter" << llendl;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_SOCKET_WRITER("Socket Writer");
|
||||
// virtual
|
||||
LLIOPipe::EStatus LLIOSocketWriter::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
@@ -398,6 +403,7 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_SOCKET_WRITER);
|
||||
PUMP_DEBUG;
|
||||
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
||||
if(!mDestination) return STATUS_PRECONDITION_NOT_MET;
|
||||
@@ -542,6 +548,7 @@ void LLIOServerSocket::setResponseTimeout(F32 timeout_secs)
|
||||
mResponseTimeout = timeout_secs;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_SERVER_SOCKET("Server Socket");
|
||||
// virtual
|
||||
LLIOPipe::EStatus LLIOServerSocket::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
@@ -550,6 +557,7 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_SERVER_SOCKET);
|
||||
PUMP_DEBUG;
|
||||
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
||||
if(!pump)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llioutil.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
/**
|
||||
* LLIOFlush
|
||||
@@ -49,6 +50,8 @@ LLIOPipe::EStatus LLIOFlush::process_impl(
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_SLEEP("IO Sleep");
|
||||
/**
|
||||
* @class LLIOSleep
|
||||
*/
|
||||
@@ -59,6 +62,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_SLEEP);
|
||||
if(mSeconds > 0.0)
|
||||
{
|
||||
if(pump) pump->sleepChain(mSeconds);
|
||||
@@ -68,6 +72,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl(
|
||||
return STATUS_DONE;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_ADD_CHAIN("Add Chain");
|
||||
/**
|
||||
* @class LLIOAddChain
|
||||
*/
|
||||
@@ -78,6 +83,7 @@ LLIOPipe::EStatus LLIOAddChain::process_impl(
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LLFastTimer t(FTM_PROCESS_ADD_CHAIN);
|
||||
pump->addChain(mChain, mTimeout);
|
||||
return STATUS_DONE;
|
||||
}
|
||||
|
||||
@@ -191,18 +191,7 @@ LLPumpIO::LLPumpIO(void) :
|
||||
LLPumpIO::~LLPumpIO()
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||
#if LL_THREADS_APR
|
||||
if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
|
||||
if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
|
||||
#endif
|
||||
mChainsMutex = NULL;
|
||||
mCallbackMutex = NULL;
|
||||
if(mPollset)
|
||||
{
|
||||
// lldebugs << "cleaning up pollset" << llendl;
|
||||
apr_pollset_destroy(mPollset);
|
||||
mPollset = NULL;
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)
|
||||
@@ -447,11 +436,13 @@ void LLPumpIO::pump()
|
||||
pump(DEFAULT_POLL_TIMEOUT);
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO");
|
||||
|
||||
//timeout is in microseconds
|
||||
void LLPumpIO::pump(const S32& poll_timeout)
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||
LLFastTimer t1(LLFastTimer::FTM_PUMPIO);
|
||||
LLFastTimer t1(FTM_PUMP_IO);
|
||||
//llinfos << "LLPumpIO::pump()" << llendl;
|
||||
|
||||
// Run any pending runners.
|
||||
@@ -779,6 +770,8 @@ bool LLPumpIO::respond(
|
||||
return true;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PUMP_CALLBACK_CHAIN("Chain");
|
||||
|
||||
void LLPumpIO::callback()
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||
@@ -800,6 +793,7 @@ void LLPumpIO::callback()
|
||||
callbacks_t::iterator end = mCallbacks.end();
|
||||
for(; it != end; ++it)
|
||||
{
|
||||
LLFastTimer t(FTM_PUMP_CALLBACK_CHAIN);
|
||||
// it's always the first and last time for respone chains
|
||||
(*it).mHead = (*it).mChainLinks.begin();
|
||||
(*it).mInit = true;
|
||||
@@ -839,6 +833,22 @@ void LLPumpIO::initialize(void)
|
||||
apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
|
||||
#endif
|
||||
}
|
||||
void LLPumpIO::cleanup()
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||
#if LL_THREADS_APR
|
||||
if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
|
||||
if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
|
||||
#endif
|
||||
mChainsMutex = NULL;
|
||||
mCallbackMutex = NULL;
|
||||
if(mPollset)
|
||||
{
|
||||
// lldebugs << "cleaning up pollset" << llendl;
|
||||
apr_pollset_destroy(mPollset);
|
||||
mPollset = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLPumpIO::rebuildPollset()
|
||||
{
|
||||
|
||||
@@ -397,6 +397,7 @@ protected:
|
||||
|
||||
protected:
|
||||
void initialize();
|
||||
void cleanup();
|
||||
|
||||
/**
|
||||
* @brief Given the internal state of the chains, rebuild the pollset
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user