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>
|
<key>EstateChangeInfo</key>
|
||||||
<boolean>true</boolean>
|
<boolean>true</boolean>
|
||||||
|
|
||||||
<key>FetchInventoryDescendents</key>
|
<key>FetchInventoryDescendents2</key>
|
||||||
<boolean>false</boolean>
|
<boolean>false</boolean>
|
||||||
|
|
||||||
<key>WebFetchInventoryDescendents</key>
|
<key>WebFetchInventoryDescendents</key>
|
||||||
<boolean>false</boolean>
|
<boolean>false</boolean>
|
||||||
|
|
||||||
<key>FetchInventory</key>
|
<key>FetchInventory2</key>
|
||||||
<boolean>true</boolean>
|
<boolean>true</boolean>
|
||||||
|
|
||||||
<key>FetchLibDescendents</key>
|
<key>FetchLibDescendents2</key>
|
||||||
<boolean>true</boolean>
|
<boolean>true</boolean>
|
||||||
|
|
||||||
<key>FetchLib</key>
|
<key>FetchLib2</key>
|
||||||
<boolean>true</boolean>
|
<boolean>true</boolean>
|
||||||
</map>
|
</map>
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ if (WINDOWS)
|
|||||||
|
|
||||||
endif (WINDOWS)
|
endif (WINDOWS)
|
||||||
|
|
||||||
set (GCC_EXTRA_OPTIMIZATION "-ffast-math -frounding-math")
|
set (GCC_EXTRA_OPTIMIZATIONS "-ffast-math -frounding-math")
|
||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
set(CMAKE_SKIP_RPATH TRUE)
|
set(CMAKE_SKIP_RPATH TRUE)
|
||||||
@@ -182,53 +182,29 @@ if (LINUX)
|
|||||||
-pthread
|
-pthread
|
||||||
)
|
)
|
||||||
|
|
||||||
if (SERVER)
|
add_definitions(-DAPPID=secondlife)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-60")
|
add_definitions(-fvisibility=hidden)
|
||||||
if (EXISTS /etc/debian_version)
|
# 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.
|
||||||
FILE(READ /etc/debian_version DEBIAN_VERSION)
|
add_definitions(-DLL_IGNORE_SIGCHLD)
|
||||||
else (EXISTS /etc/debian_version)
|
if (NOT STANDALONE)
|
||||||
set(DEBIAN_VERSION "")
|
# this stops us requiring a really recent glibc at runtime
|
||||||
endif (EXISTS /etc/debian_version)
|
add_definitions(-fno-stack-protector)
|
||||||
|
endif (NOT STANDALONE)
|
||||||
if (NOT DEBIAN_VERSION STREQUAL "3.1")
|
if (${ARCH} STREQUAL "x86_64")
|
||||||
add_definitions(-DCTYPE_WORKAROUND)
|
add_definitions(-DLINUX64=1 -pipe)
|
||||||
endif (NOT DEBIAN_VERSION STREQUAL "3.1")
|
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")
|
||||||
if (EXISTS /usr/lib/mysql4/mysql)
|
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")
|
||||||
link_directories(/usr/lib/mysql4/mysql)
|
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")
|
||||||
endif (EXISTS /usr/lib/mysql4/mysql)
|
else (${ARCH} STREQUAL "x86_64")
|
||||||
|
|
||||||
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)
|
|
||||||
if (NOT STANDALONE)
|
if (NOT STANDALONE)
|
||||||
# this stops us requiring a really recent glibc at runtime
|
set(MARCH_FLAG " -march=pentium4")
|
||||||
add_definitions(-fno-stack-protector)
|
|
||||||
endif (NOT STANDALONE)
|
endif (NOT STANDALONE)
|
||||||
if (${ARCH} STREQUAL "x86_64")
|
set(CMAKE_CXX_FLAGS_RELEASESSE2 "${CMAKE_CXX_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||||
add_definitions(-DLINUX64=1 -pipe)
|
set(CMAKE_C_FLAGS_RELEASESSE2 "${CMAKE_C_FLAGS_RELEASESSE2}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||||
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_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||||
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_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse -msse2 ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||||
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")
|
endif (${ARCH} STREQUAL "x86_64")
|
||||||
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_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG} -msse2")
|
set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG} -msse2")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 ${CMAKE_CXX_FLAGS_RELEASE}")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
@@ -258,13 +234,13 @@ endif (DARWIN)
|
|||||||
|
|
||||||
|
|
||||||
if (LINUX OR 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)
|
if (NOT GCC_DISABLE_FATAL_WARNINGS)
|
||||||
set(GCC_WARNINGS "${GCC_WARNINGS} -Werror")
|
set(GCC_WARNINGS "${GCC_WARNINGS} -Werror")
|
||||||
endif (NOT GCC_DISABLE_FATAL_WARNINGS)
|
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_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}")
|
||||||
set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}")
|
set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}")
|
||||||
@@ -298,10 +274,6 @@ if(1 EQUAL 1)
|
|||||||
add_definitions(-DMESH_ENABLED=1)
|
add_definitions(-DMESH_ENABLED=1)
|
||||||
endif(1 EQUAL 1)
|
endif(1 EQUAL 1)
|
||||||
|
|
||||||
if(SERVER)
|
|
||||||
include_directories(${LIBS_PREBUILT_DIR}/include/havok)
|
|
||||||
endif(SERVER)
|
|
||||||
|
|
||||||
SET( CMAKE_EXE_LINKER_FLAGS_RELEASESSE2
|
SET( CMAKE_EXE_LINKER_FLAGS_RELEASESSE2
|
||||||
"${CMAKE_EXE_LINKER_FLAGS_RELEASE}" CACHE STRING
|
"${CMAKE_EXE_LINKER_FLAGS_RELEASE}" CACHE STRING
|
||||||
"Flags used for linking binaries under SSE2 build."
|
"Flags used for linking binaries under SSE2 build."
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ set(DB_FIND_REQUIRED ON)
|
|||||||
if (STANDALONE)
|
if (STANDALONE)
|
||||||
include(FindBerkeleyDB)
|
include(FindBerkeleyDB)
|
||||||
else (STANDALONE)
|
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)
|
set(DB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
|
||||||
endif (STANDALONE)
|
endif (STANDALONE)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ set(cmake_SOURCE_FILES
|
|||||||
FindNDOF.cmake
|
FindNDOF.cmake
|
||||||
FindOpenJPEG.cmake
|
FindOpenJPEG.cmake
|
||||||
FindXmlRpcEpi.cmake
|
FindXmlRpcEpi.cmake
|
||||||
FMOD.cmake
|
FMOD.cmake
|
||||||
FreeType.cmake
|
FreeType.cmake
|
||||||
GStreamer010Plugin.cmake
|
GStreamer010Plugin.cmake
|
||||||
GooglePerfTools.cmake
|
GooglePerfTools.cmake
|
||||||
@@ -84,6 +84,10 @@ set(cmake_SOURCE_FILES
|
|||||||
ZLIB.cmake
|
ZLIB.cmake
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(FMODEX)
|
||||||
|
list(APPEND cmake_SOURCE_FILES FMODEX.cmake)
|
||||||
|
endif(FMODEX)
|
||||||
|
|
||||||
source_group("Shared Rules" FILES ${cmake_SOURCE_FILES})
|
source_group("Shared Rules" FILES ${cmake_SOURCE_FILES})
|
||||||
|
|
||||||
set(master_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_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
|
||||||
set(release_files
|
set(release_files
|
||||||
libtcmalloc_minimal.dll
|
libtcmalloc_minimal.dll
|
||||||
fmod.dll
|
|
||||||
libhunspell.dll
|
libhunspell.dll
|
||||||
libapr-1.dll
|
libapr-1.dll
|
||||||
libaprutil-1.dll
|
libaprutil-1.dll
|
||||||
libapriconv-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(
|
copy_if_different(
|
||||||
${release_src_dir}
|
${release_src_dir}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ set(install_dir "@CMAKE_SOURCE_DIR@/..")
|
|||||||
set(scp "@SCP_EXECUTABLE@")
|
set(scp "@SCP_EXECUTABLE@")
|
||||||
set(scripts_dir "@SCRIPTS_DIR@")
|
set(scripts_dir "@SCRIPTS_DIR@")
|
||||||
set(sentinel_dir "@CMAKE_BINARY_DIR@/prepare")
|
set(sentinel_dir "@CMAKE_BINARY_DIR@/prepare")
|
||||||
|
set(prebuilt_type "@PREBUILT_TYPE@")
|
||||||
|
|
||||||
# In proprietary mode we use scp for download.
|
# In proprietary mode we use scp for download.
|
||||||
set(proprietary "@INSTALL_PROPRIETARY@")
|
set(proprietary "@INSTALL_PROPRIETARY@")
|
||||||
@@ -19,7 +20,7 @@ foreach(package ${packages})
|
|||||||
# This package is missing or out of date.
|
# This package is missing or out of date.
|
||||||
message(STATUS "Obtaining${proprietary_message} prebuilt '${package}'")
|
message(STATUS "Obtaining${proprietary_message} prebuilt '${package}'")
|
||||||
execute_process(
|
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}
|
WORKING_DIRECTORY ${scripts_dir}
|
||||||
RESULT_VARIABLE result
|
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}
|
${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.")
|
set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.")
|
||||||
if(LLCOMMON_LINK_SHARED)
|
if(LLCOMMON_LINK_SHARED)
|
||||||
|
|||||||
@@ -5,4 +5,10 @@ set(LLPLUGIN_INCLUDE_DIRS
|
|||||||
${LIBS_OPEN_DIR}/llplugin
|
${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 -*-
|
# -*- cmake -*-
|
||||||
include(Prebuilt)
|
include(Prebuilt)
|
||||||
|
|
||||||
if (NOT STANDALONE)
|
if (NOT (STANDALONE OR DARWIN))
|
||||||
use_prebuilt_binary(glext)
|
use_prebuilt_binary(glext)
|
||||||
# possible glh_linear should have its own .cmake file instead
|
# possible glh_linear should have its own .cmake file instead
|
||||||
#use_prebuilt_binary(glh_linear)
|
#use_prebuilt_binary(glh_linear)
|
||||||
# actually... not any longer, it's now in git -SG
|
# actually... not any longer, it's now in git -SG
|
||||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
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")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
set(DARWIN 1)
|
set(DARWIN 1)
|
||||||
|
|
||||||
# NOTE: If specifying a different SDK with CMAKE_OSX_SYSROOT at configure
|
#SDK Compiler and Deployment targets for XCode
|
||||||
# time you should also specify CMAKE_OSX_DEPLOYMENT_TARGET explicitly,
|
if (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||||
# 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
|
|
||||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
|
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
|
set(CMAKE_XCODE_ATTIBUTE_GCC_VERSION "4.2")
|
||||||
endif (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
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
|
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
|
||||||
if (${CMAKE_OSX_SYSROOT} MATCHES "10.5")
|
|
||||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "4.2")
|
|
||||||
endif (${CMAKE_OSX_SYSROOT} MATCHES "10.5")
|
|
||||||
|
|
||||||
# NOTE: To attempt an i386/PPC Universal build, add this on the configure line:
|
# NOTE: To attempt an i386/PPC Universal build, add this on the configure line:
|
||||||
# -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'
|
# -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'
|
||||||
@@ -118,6 +110,17 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|||||||
endif (${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
|
# Default deploy grid
|
||||||
set(GRID agni CACHE STRING "Target 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)
|
-p | --project=NAME set the root project name. (Doesn't effect makefiles)
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
build configure and build default target
|
build configure and build default target
|
||||||
clean delete all build directories, does not affect sources
|
clean delete all build directories, does not affect sources
|
||||||
configure configure project by running cmake (default command if none given)
|
|
||||||
configure configure project by running cmake (default if none given)
|
configure configure project by running cmake (default if none given)
|
||||||
printbuilddirs print the build directory that will be used
|
printbuilddirs print the build directory that will be used
|
||||||
|
|
||||||
|
|||||||
@@ -168,7 +168,10 @@ ARGUMENTS=[
|
|||||||
dict(name='version',
|
dict(name='version',
|
||||||
description="""This specifies the version of Second Life that is
|
description="""This specifies the version of Second Life that is
|
||||||
being packaged up.""",
|
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=""):
|
def usage(srctree=""):
|
||||||
|
|||||||
@@ -1,105 +1,84 @@
|
|||||||
# Main CMakeLists.txt to build the OpenJPEG project using CMake (www.cmake.org)
|
# -*- cmake -*-
|
||||||
# Written by Mathieu Malaterre
|
|
||||||
|
|
||||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
project(openjpeg)
|
||||||
|
|
||||||
IF(COMMAND CMAKE_POLICY)
|
include(00-Common)
|
||||||
CMAKE_POLICY(SET CMP0003 NEW)
|
|
||||||
ENDIF(COMMAND CMAKE_POLICY)
|
|
||||||
|
|
||||||
PROJECT(openjpeg)
|
|
||||||
|
|
||||||
# Do full dependency headers.
|
|
||||||
INCLUDE_REGULAR_EXPRESSION("^.*$")
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
# OPENJPEG version number, useful for packaging and doxygen doc:
|
# OPENJPEG version number, useful for packaging and doxygen doc:
|
||||||
SET(OPENJPEG_VERSION_MAJOR 1)
|
set(OPENJPEG_VERSION_MAJOR 1)
|
||||||
SET(OPENJPEG_VERSION_MINOR 4)
|
set(OPENJPEG_VERSION_MINOR 4)
|
||||||
SET(OPENJPEG_VERSION_BUILD 0)
|
set(OPENJPEG_VERSION_BUILD 0)
|
||||||
SET(OPENJPEG_VERSION
|
set(OPENJPEG_VERSION
|
||||||
"${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}")
|
"${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
|
# This setting of SOVERSION assumes that any API change
|
||||||
# will increment either the minor or major version number of openjpeg
|
# 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}"
|
VERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}"
|
||||||
SOVERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}"
|
SOVERSION "${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# On Visual Studio 8 MS deprecated C. This removes all 1.276E1265 security
|
set_target_properties(openjpeg PROPERTIES
|
||||||
# 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
|
|
||||||
${OPENJPEG_LIBRARY_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;
|
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;
|
v.mem = h.mem;
|
||||||
|
|
||||||
while( --numres) {
|
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 count = w->sn;
|
||||||
int i, k;
|
int i, k;
|
||||||
for(k = 0; k < 2; ++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 */
|
/* Fast code path */
|
||||||
for(i = 0; i < count; ++i){
|
for(i = 0; i < count; ++i){
|
||||||
int j = 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.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -26,41 +26,6 @@
|
|||||||
|
|
||||||
#include "opj_includes.h"
|
#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) {
|
opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context) {
|
||||||
if(cinfo) {
|
if(cinfo) {
|
||||||
opj_event_mgr_t *previous = cinfo->event_mgr;
|
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{
|
typedef struct j2k_prog_order{
|
||||||
OPJ_PROG_ORDER enum_prog;
|
OPJ_PROG_ORDER enum_prog;
|
||||||
char str_prog[4];
|
char str_prog[5];
|
||||||
}j2k_prog_order_t;
|
}j2k_prog_order_t;
|
||||||
|
|
||||||
j2k_prog_order_t j2k_prog_order_list[] = {
|
j2k_prog_order_t j2k_prog_order_list[] = {
|
||||||
|
|||||||
@@ -1,163 +1,163 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, Herv<72> Drolon, FreeImage Team
|
* Copyright (c) 2005, Herv<72> Drolon, FreeImage Team
|
||||||
* Copyright (c) 2007, Callum Lerwick <seg@haxxed.com>
|
* Copyright (c) 2007, Callum Lerwick <seg@haxxed.com>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
* 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
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#ifndef __OPJ_MALLOC_H
|
#ifndef __OPJ_MALLOC_H
|
||||||
#define __OPJ_MALLOC_H
|
#define __OPJ_MALLOC_H
|
||||||
/**
|
/**
|
||||||
@file opj_malloc.h
|
@file opj_malloc.h
|
||||||
@brief Internal functions
|
@brief Internal functions
|
||||||
|
|
||||||
The functions in opj_malloc.h are internal utilities used for memory management.
|
The functions in opj_malloc.h are internal utilities used for memory management.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @defgroup MISC MISC - Miscellaneous internal functions */
|
/** @defgroup MISC MISC - Miscellaneous internal functions */
|
||||||
/*@{*/
|
/*@{*/
|
||||||
|
|
||||||
/** @name Exported functions */
|
/** @name Exported functions */
|
||||||
/*@{*/
|
/*@{*/
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Allocate an uninitialized memory block
|
Allocate an uninitialized memory block
|
||||||
@param size Bytes to allocate
|
@param size Bytes to allocate
|
||||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||||
*/
|
*/
|
||||||
#ifdef ALLOC_PERF_OPT
|
#ifdef ALLOC_PERF_OPT
|
||||||
void * OPJ_CALLCONV opj_malloc(size_t size);
|
void * OPJ_CALLCONV opj_malloc(size_t size);
|
||||||
#else
|
#else
|
||||||
#define opj_malloc(size) malloc(size)
|
#define opj_malloc(size) malloc(size)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Allocate a memory block with elements initialized to 0
|
Allocate a memory block with elements initialized to 0
|
||||||
@param num Blocks to allocate
|
@param num Blocks to allocate
|
||||||
@param size Bytes per block 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
|
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
||||||
*/
|
*/
|
||||||
#ifdef ALLOC_PERF_OPT
|
#ifdef ALLOC_PERF_OPT
|
||||||
void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements);
|
void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements);
|
||||||
#else
|
#else
|
||||||
#define opj_calloc(num, size) calloc(num, size)
|
#define opj_calloc(num, size) calloc(num, size)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Allocate memory aligned to a 16 byte boundry
|
Allocate memory aligned to a 16 byte boundry
|
||||||
@param size Bytes to allocate
|
@param size Bytes to allocate
|
||||||
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
|
@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 */
|
/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
/* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */
|
/* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#include <mm_malloc.h>
|
#include <mm_malloc.h>
|
||||||
#define HAVE_MM_MALLOC
|
#define HAVE_MM_MALLOC
|
||||||
#else /* MSVC, Intel C++ */
|
#else /* MSVC, Intel C++ */
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#ifdef _mm_malloc
|
#ifdef _mm_malloc
|
||||||
#define HAVE_MM_MALLOC
|
#define HAVE_MM_MALLOC
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#else /* Not WIN32 */
|
#else /* Not WIN32 */
|
||||||
#if defined(__sun)
|
#if defined(__sun)
|
||||||
#define HAVE_MEMALIGN
|
#define HAVE_MEMALIGN
|
||||||
/* Linux x86_64 and OSX always align allocations to 16 bytes */
|
/* Linux x86_64 and OSX always align allocations to 16 bytes */
|
||||||
#elif !defined(__amd64__) && !defined(__APPLE__)
|
#elif !defined(__amd64__) && !defined(__APPLE__)
|
||||||
#define HAVE_MEMALIGN
|
#define HAVE_MEMALIGN
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define opj_aligned_malloc(size) malloc(size)
|
#define opj_aligned_malloc(size) malloc(size)
|
||||||
#define opj_aligned_free(m) free(m)
|
#define opj_aligned_free(m) free(m)
|
||||||
|
|
||||||
#ifdef HAVE_MM_MALLOC
|
#ifdef HAVE_MM_MALLOC
|
||||||
#undef opj_aligned_malloc
|
#undef opj_aligned_malloc
|
||||||
#define opj_aligned_malloc(size) _mm_malloc(size, 16)
|
#define opj_aligned_malloc(size) _mm_malloc(size, 16)
|
||||||
#undef opj_aligned_free
|
#undef opj_aligned_free
|
||||||
#define opj_aligned_free(m) _mm_free(m)
|
#define opj_aligned_free(m) _mm_free(m)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_MEMALIGN
|
#ifdef HAVE_MEMALIGN
|
||||||
extern void* memalign(size_t, size_t);
|
extern void* memalign(size_t, size_t);
|
||||||
#undef opj_aligned_malloc
|
#undef opj_aligned_malloc
|
||||||
#define opj_aligned_malloc(size) memalign(16, (size))
|
#define opj_aligned_malloc(size) memalign(16, (size))
|
||||||
#undef opj_aligned_free
|
#undef opj_aligned_free
|
||||||
#define opj_aligned_free(m) free(m)
|
#define opj_aligned_free(m) free(m)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_MEMALIGN
|
#ifdef HAVE_POSIX_MEMALIGN
|
||||||
#undef opj_aligned_malloc
|
#undef opj_aligned_malloc
|
||||||
extern int posix_memalign(void**, size_t, size_t);
|
extern int posix_memalign(void**, size_t, size_t);
|
||||||
|
|
||||||
static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){
|
static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){
|
||||||
void* mem = NULL;
|
void* mem = NULL;
|
||||||
posix_memalign(&mem, 16, size);
|
posix_memalign(&mem, 16, size);
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
#undef opj_aligned_free
|
#undef opj_aligned_free
|
||||||
#define opj_aligned_free(m) free(m)
|
#define opj_aligned_free(m) free(m)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ALLOC_PERF_OPT
|
#ifdef ALLOC_PERF_OPT
|
||||||
#undef opj_aligned_malloc
|
#undef opj_aligned_malloc
|
||||||
#define opj_aligned_malloc(size) opj_malloc(size)
|
#define opj_aligned_malloc(size) opj_malloc(size)
|
||||||
#undef opj_aligned_free
|
#undef opj_aligned_free
|
||||||
#define opj_aligned_free(m) opj_free(m)
|
#define opj_aligned_free(m) opj_free(m)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reallocate memory blocks.
|
Reallocate memory blocks.
|
||||||
@param memblock Pointer to previously allocated memory block
|
@param memblock Pointer to previously allocated memory block
|
||||||
@param size New size in bytes
|
@param size New size in bytes
|
||||||
@return Returns a void pointer to the reallocated (and possibly moved) memory block
|
@return Returns a void pointer to the reallocated (and possibly moved) memory block
|
||||||
*/
|
*/
|
||||||
#ifdef ALLOC_PERF_OPT
|
#ifdef ALLOC_PERF_OPT
|
||||||
void * OPJ_CALLCONV opj_realloc(void * _Memory, size_t NewSize);
|
void * OPJ_CALLCONV opj_realloc(void * _Memory, size_t NewSize);
|
||||||
#else
|
#else
|
||||||
#define opj_realloc(m, s) realloc(m, s)
|
#define opj_realloc(m, s) realloc(m, s)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Deallocates or frees a memory block.
|
Deallocates or frees a memory block.
|
||||||
@param memblock Previously allocated memory block to be freed
|
@param memblock Previously allocated memory block to be freed
|
||||||
*/
|
*/
|
||||||
#ifdef ALLOC_PERF_OPT
|
#ifdef ALLOC_PERF_OPT
|
||||||
void OPJ_CALLCONV opj_free(void * _Memory);
|
void OPJ_CALLCONV opj_free(void * _Memory);
|
||||||
#else
|
#else
|
||||||
#define opj_free(m) free(m)
|
#define opj_free(m) free(m)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#pragma GCC poison malloc calloc realloc free
|
#pragma GCC poison malloc calloc realloc free
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
#endif /* __OPJ_MALLOC_H */
|
#endif /* __OPJ_MALLOC_H */
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ list(APPEND linux_crash_logger_SOURCE_FILES
|
|||||||
${linux_crash_logger_HEADER_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})
|
add_executable(linux-crash-logger ${linux_crash_logger_SOURCE_FILES})
|
||||||
|
|
||||||
@@ -47,11 +47,18 @@ target_link_libraries(linux-crash-logger
|
|||||||
${LLVFS_LIBRARIES}
|
${LLVFS_LIBRARIES}
|
||||||
${LLXML_LIBRARIES}
|
${LLXML_LIBRARIES}
|
||||||
${LLMESSAGE_LIBRARIES}
|
${LLMESSAGE_LIBRARIES}
|
||||||
|
${LLUI_LIBRARIES}
|
||||||
${LLVFS_LIBRARIES}
|
${LLVFS_LIBRARIES}
|
||||||
${LLMATH_LIBRARIES}
|
${LLMATH_LIBRARIES}
|
||||||
${LLCOMMON_LIBRARIES}
|
${LLCOMMON_LIBRARIES}
|
||||||
${UI_LIBRARIES}
|
${UI_LIBRARIES}
|
||||||
${DB_LIBRARIES}
|
${DB_LIBRARIES}
|
||||||
|
${XMLRPCEPI_LIBRARIES}
|
||||||
|
${CURL_LIBRARIES}
|
||||||
|
${APR_LIBRARIES}
|
||||||
|
${APRUTIL_LIBRARIES}
|
||||||
|
${CRYPTO_LIBRARIES}
|
||||||
|
rt
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
|
|||||||
@@ -5,16 +5,30 @@ project(llaudio)
|
|||||||
include(00-Common)
|
include(00-Common)
|
||||||
include(Audio)
|
include(Audio)
|
||||||
include(LLAudio)
|
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(OPENAL)
|
||||||
include(LLCommon)
|
include(LLCommon)
|
||||||
include(LLMath)
|
include(LLMath)
|
||||||
include(LLMessage)
|
include(LLMessage)
|
||||||
include(LLVFS)
|
include(LLVFS)
|
||||||
|
|
||||||
|
if(FMODEX)
|
||||||
|
include_directories(${FMODEX_INCLUDE_DIR})
|
||||||
|
endif(FMODEX)
|
||||||
|
if(FMOD)
|
||||||
|
include_directories(${FMOD_INCLUDE_DIR})
|
||||||
|
endif(FMOD)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${LLAUDIO_INCLUDE_DIRS}
|
${LLAUDIO_INCLUDE_DIRS}
|
||||||
${FMOD_INCLUDE_DIR}
|
|
||||||
${LLCOMMON_INCLUDE_DIRS}
|
${LLCOMMON_INCLUDE_DIRS}
|
||||||
${LLMATH_INCLUDE_DIRS}
|
${LLMATH_INCLUDE_DIRS}
|
||||||
${LLMESSAGE_INCLUDE_DIRS}
|
${LLMESSAGE_INCLUDE_DIRS}
|
||||||
@@ -46,6 +60,19 @@ set(llaudio_HEADER_FILES
|
|||||||
llwindgen.h
|
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)
|
if (FMOD)
|
||||||
list(APPEND llaudio_SOURCE_FILES
|
list(APPEND llaudio_SOURCE_FILES
|
||||||
llaudioengine_fmod.cpp
|
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
|
#include "stdtypes.h" // from llcommon
|
||||||
|
|
||||||
|
class LLSD;
|
||||||
|
|
||||||
// Entirely abstract. Based exactly on the historic API.
|
// Entirely abstract. Based exactly on the historic API.
|
||||||
class LLStreamingAudioInterface
|
class LLStreamingAudioInterface
|
||||||
{
|
{
|
||||||
@@ -51,6 +53,11 @@ class LLStreamingAudioInterface
|
|||||||
virtual void setGain(F32 vol) = 0;
|
virtual void setGain(F32 vol) = 0;
|
||||||
virtual F32 getGain() = 0;
|
virtual F32 getGain() = 0;
|
||||||
virtual std::string getURL() = 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
|
#endif // LL_STREAMINGAUDIO_H
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ public:
|
|||||||
const std::string& getURL() { return mInternetStreamURL; }
|
const std::string& getURL() { return mInternetStreamURL; }
|
||||||
|
|
||||||
int getOpenState();
|
int getOpenState();
|
||||||
|
|
||||||
|
FSOUND_STREAM* getStream() { return mInternetStream; }
|
||||||
protected:
|
protected:
|
||||||
FSOUND_STREAM* mInternetStream;
|
FSOUND_STREAM* mInternetStream;
|
||||||
bool mReady;
|
bool mReady;
|
||||||
@@ -66,7 +68,8 @@ protected:
|
|||||||
LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() :
|
LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() :
|
||||||
mCurrentInternetStreamp(NULL),
|
mCurrentInternetStreamp(NULL),
|
||||||
mFMODInternetStreamChannel(-1),
|
mFMODInternetStreamChannel(-1),
|
||||||
mGain(1.0f)
|
mGain(1.0f),
|
||||||
|
mMetaData(NULL)
|
||||||
{
|
{
|
||||||
// Number of milliseconds of audio to buffer for the audio card.
|
// Number of milliseconds of audio to buffer for the audio card.
|
||||||
// Must be larger than the usual Second Life frame stutter time.
|
// Must be larger than the usual Second Life frame stutter time.
|
||||||
@@ -87,6 +90,17 @@ LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD()
|
|||||||
// nothing interesting/safe to do.
|
// 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)
|
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;
|
llinfos << "Starting internet stream: " << url << llendl;
|
||||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url);
|
mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url);
|
||||||
mURL = url;
|
mURL = url;
|
||||||
|
if(mCurrentInternetStreamp->getStream())
|
||||||
|
{
|
||||||
|
mMetaData = new LLSD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -154,6 +172,10 @@ void LLStreamingAudio_FMOD::update()
|
|||||||
// Reset volume to previously set volume
|
// Reset volume to previously set volume
|
||||||
setGain(getGain());
|
setGain(getGain());
|
||||||
FSOUND_SetPaused(mFMODInternetStreamChannel, false);
|
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
|
// buffering
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLStreamingAudio_FMOD::stop()
|
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)
|
if (mFMODInternetStreamChannel != -1)
|
||||||
{
|
{
|
||||||
FSOUND_SetPaused(mFMODInternetStreamChannel, true);
|
FSOUND_SetPaused(mFMODInternetStreamChannel, true);
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ class LLStreamingAudio_FMOD : public LLStreamingAudioInterface
|
|||||||
/*virtual*/ F32 getGain();
|
/*virtual*/ F32 getGain();
|
||||||
/*virtual*/ std::string getURL();
|
/*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:
|
private:
|
||||||
LLAudioStreamManagerFMOD *mCurrentInternetStreamp;
|
LLAudioStreamManagerFMOD *mCurrentInternetStreamp;
|
||||||
int mFMODInternetStreamChannel;
|
int mFMODInternetStreamChannel;
|
||||||
@@ -62,6 +66,8 @@ private:
|
|||||||
|
|
||||||
std::string mURL;
|
std::string mURL;
|
||||||
F32 mGain;
|
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);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
//**********************************
|
// **********************************
|
||||||
LLAPRFile outfile ;
|
LLAPRFile outfile ;
|
||||||
outfile.open(out_fname,LL_APR_WPB);
|
outfile.open(out_fname,LL_APR_WPB);
|
||||||
//**********************************
|
// **********************************
|
||||||
if (!outfile.getFileHandle())
|
if (!outfile.getFileHandle())
|
||||||
{
|
{
|
||||||
llwarning("unable to open vorbis destination file for writing",0);
|
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.seek(SEEK_END,-fade_length*2);
|
||||||
outfile.write(pcmout,2*fade_length); //write back xfaded last 16 samples
|
outfile.write(pcmout,2*fade_length); //write back xfaded last 16 samples
|
||||||
//*******************
|
// *******************
|
||||||
outfile.close();
|
outfile.close();
|
||||||
//*******************
|
// *******************
|
||||||
|
|
||||||
if ((36 == data_length) || (!(eof)))
|
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();
|
error_msg.clear();
|
||||||
|
|
||||||
//********************************
|
// ********************************
|
||||||
LLAPRFile infile ;
|
LLAPRFile infile ;
|
||||||
infile.open(in_fname,LL_APR_RB);
|
infile.open(in_fname,LL_APR_RB);
|
||||||
//********************************
|
// ********************************
|
||||||
if (!infile.getFileHandle())
|
if (!infile.getFileHandle())
|
||||||
{
|
{
|
||||||
error_msg = "CannotUploadSoundFile";
|
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);
|
file_pos += (chunk_length + 8);
|
||||||
chunk_length = 0;
|
chunk_length = 0;
|
||||||
}
|
}
|
||||||
//****************
|
// ****************
|
||||||
infile.close();
|
infile.close();
|
||||||
//****************
|
// ****************
|
||||||
|
|
||||||
if (!uncompressed_pcm)
|
if (!uncompressed_pcm)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#define WINDGEN_H
|
#define WINDGEN_H
|
||||||
|
|
||||||
#include "llcommon.h"
|
#include "llcommon.h"
|
||||||
|
#include "llrand.h"
|
||||||
|
|
||||||
template <class MIXBUFFERFORMAT_T>
|
template <class MIXBUFFERFORMAT_T>
|
||||||
class LLWindGen
|
class LLWindGen
|
||||||
@@ -60,7 +61,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const U32 getInputSamplingRate() { return mInputSamplingRate; }
|
const U32 getInputSamplingRate() { return mInputSamplingRate; }
|
||||||
|
const F32 getNextSample();
|
||||||
|
const F32 getClampedSample(bool clamp, F32 sample);
|
||||||
|
|
||||||
// newbuffer = the buffer passed from the previous DSP unit.
|
// newbuffer = the buffer passed from the previous DSP unit.
|
||||||
// numsamples = length in samples-per-channel at this mix time.
|
// numsamples = length in samples-per-channel at this mix time.
|
||||||
// NOTE: generates L/R interleaved stereo
|
// NOTE: generates L/R interleaved stereo
|
||||||
@@ -95,7 +98,7 @@ public:
|
|||||||
|
|
||||||
// Start with white noise
|
// Start with white noise
|
||||||
// This expression is fragile, rearrange it and it will break!
|
// 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
|
// Apply a pinking filter
|
||||||
// Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
|
// 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)
|
for (U8 i=mSubSamples; i && numsamples; --i, --numsamples)
|
||||||
{
|
{
|
||||||
mLastSample = mLastSample + delta;
|
mLastSample = mLastSample + delta;
|
||||||
S32 sample_right = (S32)(mLastSample * mCurrentPanGainR);
|
MIXBUFFERFORMAT_T sample_right = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample * mCurrentPanGainR);
|
||||||
S32 sample_left = (S32)mLastSample - sample_right;
|
MIXBUFFERFORMAT_T sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right);
|
||||||
|
|
||||||
if (!clip)
|
*cursamplep = sample_left;
|
||||||
{
|
++cursamplep;
|
||||||
*cursamplep = (MIXBUFFERFORMAT_T)sample_left;
|
*cursamplep = sample_right;
|
||||||
++cursamplep;
|
++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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,4 +172,9 @@ private:
|
|||||||
F32 mLastSample;
|
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
|
#endif
|
||||||
|
|||||||
@@ -195,15 +195,19 @@ void LLCharacter::requestStopMotion( LLMotion* motion)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// updateMotions()
|
// 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)
|
void LLCharacter::updateMotions(e_update_t update_type)
|
||||||
{
|
{
|
||||||
LLFastTimer t(LLFastTimer::FTM_UPDATE_ANIMATION);
|
|
||||||
if (update_type == HIDDEN_UPDATE)
|
if (update_type == HIDDEN_UPDATE)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION);
|
||||||
mMotionController.updateMotionsMinimal();
|
mMotionController.updateMotionsMinimal();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_UPDATE_ANIMATION);
|
||||||
// unpause if the number of outstanding pause requests has dropped to the initial one
|
// unpause if the number of outstanding pause requests has dropped to the initial one
|
||||||
if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
|
if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ LLJoint::LLJoint()
|
|||||||
mUpdateXform = TRUE;
|
mUpdateXform = TRUE;
|
||||||
mJointNum = -1;
|
mJointNum = -1;
|
||||||
touch();
|
touch();
|
||||||
#if MESH_ENABLED
|
|
||||||
mResetAfterRestoreOldXform = false;
|
mResetAfterRestoreOldXform = false;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -242,7 +240,6 @@ void LLJoint::setPosition( const LLVector3& pos )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// setPosition()
|
// setPosition()
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
@@ -278,7 +275,6 @@ void LLJoint::restoreToDefaultXform( void )
|
|||||||
mXform = mDefaultXform;
|
mXform = mDefaultXform;
|
||||||
setPosition( mXform.getPosition() );
|
setPosition( mXform.getPosition() );
|
||||||
}
|
}
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// getWorldPosition()
|
// getWorldPosition()
|
||||||
|
|||||||
@@ -86,19 +86,14 @@ protected:
|
|||||||
|
|
||||||
// explicit transformation members
|
// explicit transformation members
|
||||||
LLXformMatrix mXform;
|
LLXformMatrix mXform;
|
||||||
#if MESH_ENABLED
|
|
||||||
LLXformMatrix mOldXform;
|
LLXformMatrix mOldXform;
|
||||||
LLXformMatrix mDefaultXform;
|
LLXformMatrix mDefaultXform;
|
||||||
|
|
||||||
LLUUID mId;
|
LLUUID mId;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
public:
|
public:
|
||||||
U32 mDirtyFlags;
|
U32 mDirtyFlags;
|
||||||
BOOL mUpdateXform;
|
BOOL mUpdateXform;
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
BOOL mResetAfterRestoreOldXform;
|
BOOL mResetAfterRestoreOldXform;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
// describes the skin binding pose
|
// describes the skin binding pose
|
||||||
LLVector3 mSkinOffset;
|
LLVector3 mSkinOffset;
|
||||||
@@ -188,8 +183,6 @@ public:
|
|||||||
S32 getJointNum() const { return mJointNum; }
|
S32 getJointNum() const { return mJointNum; }
|
||||||
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
|
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
|
|
||||||
void restoreOldXform( void );
|
void restoreOldXform( void );
|
||||||
void restoreToDefaultXform( void );
|
void restoreToDefaultXform( void );
|
||||||
void setDefaultFromCurrentXform( void );
|
void setDefaultFromCurrentXform( void );
|
||||||
@@ -204,7 +197,6 @@ public:
|
|||||||
const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
|
const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
|
||||||
//Setter for joint reset flag
|
//Setter for joint reset flag
|
||||||
void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
|
void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
// <edit>
|
// <edit>
|
||||||
std::string exportString(U32 tabs = 0);
|
std::string exportString(U32 tabs = 0);
|
||||||
|
|||||||
@@ -637,9 +637,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
|||||||
motionp->fadeIn();
|
motionp->fadeIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
//**********************
|
// **********************
|
||||||
// MOTION INACTIVE
|
// MOTION INACTIVE
|
||||||
//**********************
|
// **********************
|
||||||
if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
|
if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
|
||||||
{
|
{
|
||||||
// this motion has gone on too long, deactivate it
|
// this motion has gone on too long, deactivate it
|
||||||
@@ -659,9 +659,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//**********************
|
// **********************
|
||||||
// MOTION EASE OUT
|
// MOTION EASE OUT
|
||||||
//**********************
|
// **********************
|
||||||
else if (motionp->isStopped() && mAnimTime > motionp->getStopTime())
|
else if (motionp->isStopped() && mAnimTime > motionp->getStopTime())
|
||||||
{
|
{
|
||||||
// is this the first iteration in the ease out phase?
|
// 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);
|
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
//**********************
|
// **********************
|
||||||
// MOTION ACTIVE
|
// MOTION ACTIVE
|
||||||
//**********************
|
// **********************
|
||||||
else if (mAnimTime > motionp->mActivationTimestamp + motionp->getEaseInDuration())
|
else if (mAnimTime > motionp->mActivationTimestamp + motionp->getEaseInDuration())
|
||||||
{
|
{
|
||||||
posep->setWeight(motionp->getFadeWeight());
|
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);
|
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
//**********************
|
// **********************
|
||||||
// MOTION EASE IN
|
// MOTION EASE IN
|
||||||
//**********************
|
// **********************
|
||||||
else if (mAnimTime >= motionp->mActivationTimestamp)
|
else if (mAnimTime >= motionp->mActivationTimestamp)
|
||||||
{
|
{
|
||||||
if (mLastTime < motionp->mActivationTimestamp)
|
if (mLastTime < motionp->mActivationTimestamp)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ include_directories(
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(llcommon_SOURCE_FILES
|
set(llcommon_SOURCE_FILES
|
||||||
|
aiframetimer.cpp
|
||||||
imageids.cpp
|
imageids.cpp
|
||||||
indra_constants.cpp
|
indra_constants.cpp
|
||||||
llapp.cpp
|
llapp.cpp
|
||||||
@@ -35,7 +36,7 @@ set(llcommon_SOURCE_FILES
|
|||||||
llerrorthread.cpp
|
llerrorthread.cpp
|
||||||
llevent.cpp
|
llevent.cpp
|
||||||
lleventtimer.cpp
|
lleventtimer.cpp
|
||||||
llfasttimer.cpp
|
llfasttimer_class.cpp
|
||||||
llfile.cpp
|
llfile.cpp
|
||||||
llfindlocale.cpp
|
llfindlocale.cpp
|
||||||
llfixedbuffer.cpp
|
llfixedbuffer.cpp
|
||||||
@@ -54,6 +55,7 @@ set(llcommon_SOURCE_FILES
|
|||||||
llmetrics.cpp
|
llmetrics.cpp
|
||||||
llmortician.cpp
|
llmortician.cpp
|
||||||
lloptioninterface.cpp
|
lloptioninterface.cpp
|
||||||
|
llptrto.cpp
|
||||||
llprocesslauncher.cpp
|
llprocesslauncher.cpp
|
||||||
llprocessor.cpp
|
llprocessor.cpp
|
||||||
llqueuedthread.cpp
|
llqueuedthread.cpp
|
||||||
@@ -89,6 +91,7 @@ set(llcommon_SOURCE_FILES
|
|||||||
set(llcommon_HEADER_FILES
|
set(llcommon_HEADER_FILES
|
||||||
CMakeLists.txt
|
CMakeLists.txt
|
||||||
|
|
||||||
|
aiframetimer.h
|
||||||
aithreadsafe.h
|
aithreadsafe.h
|
||||||
bitpack.h
|
bitpack.h
|
||||||
ctype_workaround.h
|
ctype_workaround.h
|
||||||
@@ -136,6 +139,7 @@ set(llcommon_HEADER_FILES
|
|||||||
llextendedstatus.h
|
llextendedstatus.h
|
||||||
lleventtimer.h
|
lleventtimer.h
|
||||||
llfasttimer.h
|
llfasttimer.h
|
||||||
|
llfasttimer_class.h
|
||||||
llfile.h
|
llfile.h
|
||||||
llfindlocale.h
|
llfindlocale.h
|
||||||
llfixedbuffer.h
|
llfixedbuffer.h
|
||||||
@@ -171,6 +175,7 @@ set(llcommon_HEADER_FILES
|
|||||||
llprocessor.h
|
llprocessor.h
|
||||||
llptrskiplist.h
|
llptrskiplist.h
|
||||||
llptrskipmap.h
|
llptrskipmap.h
|
||||||
|
llptrto.h
|
||||||
llqueuedthread.h
|
llqueuedthread.h
|
||||||
llrand.h
|
llrand.h
|
||||||
llrefcount.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
|
// NOTE: This next two funtions are only included here
|
||||||
// for those too familiar with the LLLinkedList template class.
|
// 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
|
// getCurrentData() is identical to getNextData() and has
|
||||||
// a misleading name.
|
// 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
|
// NOTE: This next two funtions are only included here
|
||||||
// for those too familiar with the LLLinkedList template class.
|
// 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
|
// getCurrentData() is identical to getNextData() and has
|
||||||
// a misleading name.
|
// a misleading name.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -153,11 +153,6 @@ const char LAND_LAYER_CODE = 'L';
|
|||||||
const char WATER_LAYER_CODE = 'W';
|
const char WATER_LAYER_CODE = 'W';
|
||||||
const char WIND_LAYER_CODE = '7';
|
const char WIND_LAYER_CODE = '7';
|
||||||
const char CLOUD_LAYER_CODE = '8';
|
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
|
// keys
|
||||||
// Bit masks for various keyboard modifier 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
|
//static components of LLAPRFile
|
||||||
//
|
//
|
||||||
|
|
||||||
@@ -504,5 +504,5 @@ bool LLAPRFile::removeDir(const std::string& dirname)
|
|||||||
}
|
}
|
||||||
//
|
//
|
||||||
//end of static components of LLAPRFile
|
//end of static components of LLAPRFile
|
||||||
//*******************************************************************************************************************************
|
// *******************************************************************************************************************************
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ public:
|
|||||||
apr_file_t* getFileHandle() {return mFile;}
|
apr_file_t* getFileHandle() {return mFile;}
|
||||||
|
|
||||||
//
|
//
|
||||||
//*******************************************************************************************************************************
|
// *******************************************************************************************************************************
|
||||||
//static components
|
//static components
|
||||||
//
|
//
|
||||||
private:
|
private:
|
||||||
@@ -185,7 +185,7 @@ public:
|
|||||||
// Returns bytes read/written, 0 if read/write fails:
|
// Returns bytes read/written, 0 if read/write fails:
|
||||||
static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes);
|
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);
|
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)
|
bool LLAssetType::lookupCanLink(EType asset_type)
|
||||||
{
|
{
|
||||||
//Check that enabling all these other types as linkable doesn't break things.
|
//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);
|
const AssetEntry *entry = dict->lookup(asset_type);
|
||||||
if (entry)
|
if (entry)
|
||||||
{
|
{
|
||||||
return entry->mCanLink;
|
return entry->mCanLink;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
*/
|
|
||||||
|
|
||||||
return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY ||
|
/*return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY ||
|
||||||
asset_type == AT_BODYPART || asset_type == AT_GESTURE);
|
asset_type == AT_BODYPART || asset_type == AT_GESTURE);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "llfasttimer.h"
|
||||||
#include "lltimer.h"
|
#include "lltimer.h"
|
||||||
#include "llstring.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"));
|
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
|
std::string LLDate::toHTTPDateString (std::string fmt) const
|
||||||
{
|
{
|
||||||
|
LLFastTimer ft1(FT_DATE_FORMAT);
|
||||||
|
|
||||||
time_t locSeconds = (time_t) mSecondsSinceEpoch;
|
time_t locSeconds = (time_t) mSecondsSinceEpoch;
|
||||||
struct tm * gmt = gmtime (&locSeconds);
|
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)
|
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.
|
// avoid calling setlocale() unnecessarily - it's expensive.
|
||||||
static std::string prev_locale = "";
|
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 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
|
#ifdef SHOW_ASSERT
|
||||||
#define llassert(func) llassert_always(func)
|
#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
|
* @file llfasttimer.h
|
||||||
* @brief Declaration of a fast timer.
|
* @brief Inline implementations of fast timers.
|
||||||
*
|
*
|
||||||
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||||
*
|
|
||||||
* Copyright (c) 2004-2009, Linden Research, Inc.
|
|
||||||
*
|
|
||||||
* Second Life Viewer Source Code
|
* Second Life Viewer Source Code
|
||||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* it is applied to this Source Code. View the full text of the exception
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
* License as published by the Free Software Foundation;
|
||||||
* online at
|
* version 2.1 of the License only.
|
||||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
||||||
*
|
*
|
||||||
* By copying, modifying or distributing this software, you acknowledge
|
* This library is distributed in the hope that it will be useful,
|
||||||
* that you have read and understood your obligations described above,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* and agree to abide by those obligations.
|
* 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
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
* License along with this library; if not, write to the Free Software
|
||||||
* COMPLETENESS OR PERFORMANCE.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LL_LLFASTTIMER_H
|
#ifndef LL_FASTTIMER_H
|
||||||
#define LL_LLFASTTIMER_H
|
#define LL_FASTTIMER_H
|
||||||
|
|
||||||
#define FAST_TIMER_ON 1
|
// Implementation of getCPUClockCount32() and getCPUClockCount64 are now in llfastertimer_class.cpp.
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// pull in the actual class definition
|
||||||
|
#include "llfasttimer_class.h"
|
||||||
|
|
||||||
#endif // LL_LLFASTTIMER_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 "u64.h"
|
||||||
|
|
||||||
#include "llframetimer.h"
|
#include "llframetimer.h"
|
||||||
|
#include "aiframetimer.h"
|
||||||
|
#include "llaprpool.h"
|
||||||
|
|
||||||
// Local constants.
|
// Local constants.
|
||||||
static F64 const USEC_PER_SECOND = 1000000.0;
|
static F64 const USEC_PER_SECOND = 1000000.0;
|
||||||
static F64 const USEC_TO_SEC_F64 = 0.000001;
|
static F64 const USEC_TO_SEC_F64 = 0.000001;
|
||||||
|
static F64 const NEVER = 1e16;
|
||||||
|
|
||||||
// Static members
|
// Static members
|
||||||
U64 const LLFrameTimer::sStartTotalTime = totalTime(); // Application start in microseconds since epoch.
|
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.
|
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.
|
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.
|
F64 LLFrameTimer::sFrameTime = 0.0; // Current time in seconds since application start, updated together with LLFrameTimer::sTotalTime.
|
||||||
// Updated exactly once per frame:
|
// Updated exactly once per frame:
|
||||||
S32 LLFrameTimer::sFrameCount = 0; // Current frame number (number of frames since application start).
|
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::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.
|
U64 LLFrameTimer::sFrameDeltaTime = 0; // Microseconds between last two calls to LLFrameTimer::updateFrameTimeAndCount.
|
||||||
|
// Mutex for the above.
|
||||||
|
apr_thread_mutex_t* LLFrameTimer::sGlobalMutex;
|
||||||
|
|
||||||
// static
|
// 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();
|
sTotalTime = totalTime();
|
||||||
sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64;
|
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
|
// static
|
||||||
void LLFrameTimer::updateFrameTimeAndCount()
|
void LLFrameTimer::updateFrameTimeAndCount(void)
|
||||||
{
|
{
|
||||||
updateFrameTime();
|
updateFrameTime();
|
||||||
sFrameDeltaTime = sTotalTime - sPrevTotalTime;
|
sFrameDeltaTime = sTotalTime - sPrevTotalTime;
|
||||||
sPrevTotalTime = sTotalTime;
|
sPrevTotalTime = sTotalTime;
|
||||||
++sFrameCount;
|
++sFrameCount;
|
||||||
}
|
|
||||||
|
|
||||||
void LLFrameTimer::reset(F32 expiration)
|
// Handle AIFrameTimer expiration and callbacks.
|
||||||
{
|
if (AIFrameTimer::sNextExpiration <= sFrameTime)
|
||||||
llassert(!mPaused);
|
{
|
||||||
mStartTime = sFrameTime;
|
AIFrameTimer::handleExpiration(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't combine pause/unpause with start/stop
|
// Don't combine pause/unpause with start/stop
|
||||||
@@ -95,38 +98,38 @@ void LLFrameTimer::stop()
|
|||||||
// foo.unpause() // unpauses
|
// foo.unpause() // unpauses
|
||||||
// F32 elapsed = foo.getElapsedTimeF32() // does not include time between pause() and unpause()
|
// 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)
|
// 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)
|
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.
|
mStartTime = sFrameTime - mStartTime; // Abuse mStartTime to store the elapsed time so far.
|
||||||
}
|
}
|
||||||
mPaused = true;
|
mPaused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFrameTimer::unpause()
|
void LLFrameTimer::unpause(void)
|
||||||
{
|
{
|
||||||
|
llassert(is_main_thread());
|
||||||
if (mPaused)
|
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.
|
mStartTime = sFrameTime - mStartTime; // Set mStartTime consistent with the elapsed time so far.
|
||||||
}
|
}
|
||||||
mPaused = false;
|
mPaused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFrameTimer::setTimerExpirySec(F32 expiration)
|
|
||||||
{
|
|
||||||
llassert(!mPaused);
|
|
||||||
mExpiry = mStartTime + expiration;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLFrameTimer::setExpiryAt(F64 seconds_since_epoch)
|
void LLFrameTimer::setExpiryAt(F64 seconds_since_epoch)
|
||||||
{
|
{
|
||||||
|
llassert(is_main_thread());
|
||||||
llassert(!mPaused);
|
llassert(!mPaused);
|
||||||
|
// Only the main thread writes to sFrameTime, so there is no need for locking.
|
||||||
mStartTime = sFrameTime;
|
mStartTime = sFrameTime;
|
||||||
mExpiry = seconds_since_epoch - (USEC_TO_SEC_F64 * sStartTotalTime);
|
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;
|
F64 expires_at = U64_to_F64(sStartTotalTime) * USEC_TO_SEC_F64;
|
||||||
expires_at += mExpiry;
|
expires_at += mExpiry;
|
||||||
@@ -135,31 +138,47 @@ F64 LLFrameTimer::expiresAt() const
|
|||||||
|
|
||||||
bool LLFrameTimer::checkExpirationAndReset(F32 expiration)
|
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 true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
F32 LLFrameTimer::getElapsedTimeAndResetF32(void)
|
||||||
F32 LLFrameTimer::getFrameDeltaTimeF32()
|
|
||||||
{
|
{
|
||||||
|
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);
|
return (F32)(U64_to_F64(sFrameDeltaTime) * USEC_TO_SEC_F64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
// static
|
|
||||||
// Return seconds since the current frame started
|
// 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;
|
U64 frame_time = totalTime() - sTotalTime;
|
||||||
return (F32)(U64_to_F64(frame_time) * USEC_TO_SEC_F64);
|
return (F32)(U64_to_F64(frame_time) * USEC_TO_SEC_F64);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Glue code to avoid full class .h file #includes
|
// Glue code to avoid full class .h file #includes
|
||||||
F32 getCurrentFrameTime()
|
F32 getCurrentFrameTime(void)
|
||||||
{
|
{
|
||||||
return (F32)(LLFrameTimer::getCurrentFrameTime());
|
return (F32)(LLFrameTimer::getCurrentFrameTime());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,88 +43,131 @@
|
|||||||
|
|
||||||
#include "lltimer.h"
|
#include "lltimer.h"
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
|
#include <apr_thread_mutex.h>
|
||||||
|
|
||||||
class LL_COMMON_API LLFrameTimer
|
class LL_COMMON_API LLFrameTimer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Create an LLFrameTimer and start it. After creation it is running and in the state expired (hasExpired will return true).
|
// 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.
|
// 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...
|
// 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.
|
// Return a low precision usec since epoch.
|
||||||
static U64 getTotalTime()
|
static U64 getTotalTime(void)
|
||||||
{
|
{
|
||||||
llassert(sTotalTime);
|
// sTotalTime is only accessed by the main thread, so no locking is necessary.
|
||||||
return sTotalTime;
|
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.
|
// 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.
|
// Call this method once per frame to update the current frame time.
|
||||||
// This is actually called at some other times as well.
|
// 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.
|
// Call this method once, and only once, per frame to update the current frame count and sFrameDeltaTime.
|
||||||
static void updateFrameTimeAndCount();
|
static void updateFrameTimeAndCount(void);
|
||||||
|
|
||||||
// Return current frame number (the number of frames since application start).
|
|
||||||
static U32 getFrameCount() { return sFrameCount; }
|
|
||||||
|
|
||||||
// Return duration of last frame in seconds.
|
// Return duration of last frame in seconds.
|
||||||
static F32 getFrameDeltaTimeF32();
|
static F32 getFrameDeltaTimeF32(void);
|
||||||
|
|
||||||
// Return seconds since the current frame started
|
// Return seconds since the current frame started
|
||||||
static F32 getCurrentFrameTime();
|
static F32 getCurrentFrameTime(void);
|
||||||
|
|
||||||
// MANIPULATORS
|
// MANIPULATORS
|
||||||
|
|
||||||
void reset(F32 expiration = 0.f); // Same as start() but leaves mRunning off when called after stop().
|
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.
|
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 pause(); // Mark elapsed time so far.
|
||||||
void unpause(); // Move 'start' time in order to decrement time between pause and unpause from ElapsedTime.
|
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);
|
void setExpiryAt(F64 seconds_since_epoch);
|
||||||
bool checkExpirationAndReset(F32 expiration); // Returns true when expired. Only resets if expired.
|
bool checkExpirationAndReset(F32 expiration); // Returns true when expired. Only resets if expired.
|
||||||
F32 getElapsedTimeAndResetF32() { F32 t = getElapsedTimeF32(); reset(); return t; }
|
F32 getElapsedTimeAndResetF32(void);
|
||||||
void setAge(const F64 age) { llassert(!mPaused); mStartTime = sFrameTime - age; }
|
void setAge(const F64 age) { llassert(!mPaused); mStartTime = getElapsedSeconds() - age; }
|
||||||
|
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
bool hasExpired() const { return sFrameTime >= mExpiry; }
|
bool hasExpired() const { return getElapsedSeconds() >= mExpiry; }
|
||||||
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(sFrameTime - mStartTime); }
|
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(getElapsedSeconds() - mStartTime); }
|
||||||
bool getStarted() const { return mRunning; }
|
bool getStarted() const { return mRunning; }
|
||||||
|
|
||||||
// return the seconds since epoch when this timer will expire.
|
// return the seconds since epoch when this timer will expire.
|
||||||
F64 expiresAt() const;
|
F64 expiresAt() const;
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
// A single, high resolution timer that drives all LLFrameTimers
|
// Do one-time initialization of the static members.
|
||||||
// *NOTE: no longer used.
|
static void global_initialization(void);
|
||||||
//static LLTimer sInternalTimer;
|
|
||||||
|
|
||||||
|
protected:
|
||||||
//
|
//
|
||||||
// Aplication constants
|
// Application constants
|
||||||
//
|
//
|
||||||
|
|
||||||
// Application start in microseconds since epoch.
|
// Application start in microseconds since epoch.
|
||||||
static U64 const sStartTotalTime;
|
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.
|
// Current time in seconds since application start, updated together with sTotalTime.
|
||||||
static F64 sFrameTime;
|
static F64 sFrameTime;
|
||||||
|
|
||||||
|
|||||||
@@ -194,7 +194,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LLInstanceTracker(KEY key) { add_(key); }
|
LLInstanceTracker(KEY key)
|
||||||
|
{
|
||||||
|
// make sure static data outlives all instances
|
||||||
|
getStatic();
|
||||||
|
add_(key);
|
||||||
|
}
|
||||||
virtual ~LLInstanceTracker()
|
virtual ~LLInstanceTracker()
|
||||||
{
|
{
|
||||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||||
@@ -282,7 +287,8 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
LLInstanceTracker()
|
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));
|
getSet_().insert(static_cast<T*>(this));
|
||||||
}
|
}
|
||||||
virtual ~LLInstanceTracker()
|
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);
|
||||||
|
|
||||||
|
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
|
#endif // LL_LLMD5_H
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -40,9 +40,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "llerror.h"
|
#include "llerror.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#if LL_DEBUG
|
#if LL_DEBUG
|
||||||
inline void* ll_aligned_malloc( size_t size, int align )
|
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
|
#define ll_aligned_free_32 free
|
||||||
#endif // LL_DEBUG
|
#endif // LL_DEBUG
|
||||||
|
|
||||||
|
#ifndef __DEBUG_PRIVATE_MEM__
|
||||||
|
#define __DEBUG_PRIVATE_MEM__ 0
|
||||||
|
#endif
|
||||||
|
|
||||||
class LL_COMMON_API LLMemory
|
class LL_COMMON_API LLMemory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -130,10 +131,395 @@ public:
|
|||||||
// Return value is zero if not known.
|
// Return value is zero if not known.
|
||||||
static U64 getCurrentRSS();
|
static U64 getCurrentRSS();
|
||||||
static U32 getWorkingSetSize();
|
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:
|
private:
|
||||||
static char* reserveMem;
|
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:
|
//EVENTUALLY REMOVE THESE:
|
||||||
#include "llpointer.h"
|
#include "llpointer.h"
|
||||||
#include "llrefcount.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
|
// MAIN THREAD
|
||||||
LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) :
|
||||||
LLThread(name),
|
LLThread(name),
|
||||||
mThreaded(threaded),
|
mThreaded(threaded),
|
||||||
mIdleThread(TRUE),
|
mIdleThread(TRUE),
|
||||||
@@ -47,6 +47,11 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
|||||||
{
|
{
|
||||||
if (mThreaded)
|
if (mThreaded)
|
||||||
{
|
{
|
||||||
|
if(should_pause)
|
||||||
|
{
|
||||||
|
pause() ; //call this before start the thread.
|
||||||
|
}
|
||||||
|
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ public:
|
|||||||
static handle_t nullHandle() { return handle_t(0); }
|
static handle_t nullHandle() { return handle_t(0); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LLQueuedThread(const std::string& name, bool threaded = true);
|
LLQueuedThread(const std::string& name, bool threaded = true, bool should_pause = false);
|
||||||
virtual ~LLQueuedThread();
|
virtual ~LLQueuedThread();
|
||||||
virtual void shutdown();
|
virtual void shutdown();
|
||||||
|
|
||||||
|
|||||||
@@ -39,13 +39,11 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "apr_base64.h"
|
#include "apr_base64.h"
|
||||||
#if MESH_ENABLED
|
|
||||||
#ifdef LL_STANDALONE
|
#ifdef LL_STANDALONE
|
||||||
# include <zlib.h>
|
# include <zlib.h>
|
||||||
#else
|
#else
|
||||||
# include "zlib/zlib.h" // for davep's dirty little zip functions
|
# include "zlib/zlib.h" // for davep's dirty little zip functions
|
||||||
#endif
|
#endif
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
#if !LL_WINDOWS
|
#if !LL_WINDOWS
|
||||||
#include <netinet/in.h> // htonl & ntohl
|
#include <netinet/in.h> // htonl & ntohl
|
||||||
@@ -1454,9 +1452,12 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
|
|||||||
}
|
}
|
||||||
|
|
||||||
case LLSD::TypeUUID:
|
case LLSD::TypeUUID:
|
||||||
|
{
|
||||||
ostr.put('u');
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case LLSD::TypeString:
|
case LLSD::TypeString:
|
||||||
ostr.put('s');
|
ostr.put('s');
|
||||||
@@ -1996,8 +1997,6 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
|
|
||||||
//dirty little zippers -- yell at davep if these are horrid
|
//dirty little zippers -- yell at davep if these are horrid
|
||||||
|
|
||||||
//return a string containing gzipped bytes of binary serialized LLSD
|
//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);
|
free(result);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif //MESH_ENABLED
|
|
||||||
@@ -788,9 +788,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
//dirty little zip functions -- yell at davep
|
//dirty little zip functions -- yell at davep
|
||||||
LL_COMMON_API std::string zip_llsd(LLSD& data);
|
LL_COMMON_API std::string zip_llsd(LLSD& data);
|
||||||
LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
|
LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
|
||||||
#endif //MESH_ENABLED
|
|
||||||
#endif // LL_LLSDSERIALIZE_H
|
#endif // LL_LLSDSERIALIZE_H
|
||||||
|
|||||||
@@ -42,17 +42,17 @@ template <class Object> class LLStrider
|
|||||||
U8* mBytep;
|
U8* mBytep;
|
||||||
};
|
};
|
||||||
U32 mSkip;
|
U32 mSkip;
|
||||||
U32 mTypeSize;
|
//U32 mTypeSize;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LLStrider() { mObjectp = NULL; mTypeSize = mSkip = sizeof(Object); }
|
LLStrider() { mObjectp = NULL; /*mTypeSize = */mSkip = sizeof(Object); }
|
||||||
~LLStrider() { }
|
~LLStrider() { }
|
||||||
|
|
||||||
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
||||||
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
|
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;}
|
void skip(const U32 index) { mBytep += mSkip*index;}
|
||||||
U32 getSkip() const { return mSkip; }
|
U32 getSkip() const { return mSkip; }
|
||||||
Object* get() { return mObjectp; }
|
Object* get() { return mObjectp; }
|
||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
||||||
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
||||||
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
|
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);
|
llassert_always(sizeof(Object) <= elem_size);
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ public:
|
|||||||
source+=elem_size;
|
source+=elem_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LL_LLSTRIDER_H
|
#endif // LL_LLSTRIDER_H
|
||||||
|
|||||||
@@ -43,6 +43,9 @@
|
|||||||
#include <winnls.h> // for WideCharToMultiByte
|
#include <winnls.h> // for WideCharToMultiByte
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format");
|
||||||
|
|
||||||
|
|
||||||
std::string ll_safe_string(const char* in)
|
std::string ll_safe_string(const char* in)
|
||||||
{
|
{
|
||||||
if(in) return std::string(in);
|
if(in) return std::string(in);
|
||||||
@@ -1196,7 +1199,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
|
|||||||
template<>
|
template<>
|
||||||
S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
|
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;
|
S32 res = 0;
|
||||||
|
|
||||||
std::string output;
|
std::string output;
|
||||||
@@ -1269,7 +1272,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
|
|||||||
template<>
|
template<>
|
||||||
S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
|
S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
|
||||||
{
|
{
|
||||||
LLFastTimer ft(LLFastTimer::FT_STRING_FORMAT);
|
LLFastTimer ft(FT_STRING_FORMAT);
|
||||||
S32 res = 0;
|
S32 res = 0;
|
||||||
|
|
||||||
if (!substitutions.isMap())
|
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
|
// after the LLCurl::Multi::run() function exits and we actually
|
||||||
// change this variable (which really SHOULD have been inside
|
// change this variable (which really SHOULD have been inside
|
||||||
// the critical area of the mSignal lock)].
|
// the critical area of the mSignal lock)].
|
||||||
llinfos << "LLThread::staticRun() Exiting: " << name << llendl;
|
lldebugs << "LLThread::staticRun() Exiting: " << name << llendl;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
const S32 LL_VERSION_MAJOR = 1;
|
const S32 LL_VERSION_MAJOR = 1;
|
||||||
const S32 LL_VERSION_MINOR = 6;
|
const S32 LL_VERSION_MINOR = 6;
|
||||||
const S32 LL_VERSION_PATCH = 0;
|
const S32 LL_VERSION_PATCH = 0;
|
||||||
const S32 LL_VERSION_BUILD = 1;
|
const S32 LL_VERSION_BUILD = 3;
|
||||||
|
|
||||||
const char * const LL_CHANNEL = "Singularity";
|
const char * const LL_CHANNEL = "Singularity";
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,8 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// Run on MAIN thread
|
// Run on MAIN thread
|
||||||
|
|
||||||
LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) :
|
LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) :
|
||||||
LLQueuedThread(name, threaded)
|
LLQueuedThread(name, threaded, should_pause)
|
||||||
{
|
{
|
||||||
mDeleteMutex = new LLMutex;
|
mDeleteMutex = new LLMutex;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ private:
|
|||||||
LLMutex* mDeleteMutex;
|
LLMutex* mDeleteMutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LLWorkerThread(const std::string& name, bool threaded = true);
|
LLWorkerThread(const std::string& name, bool threaded = true, bool should_pause = false);
|
||||||
~LLWorkerThread();
|
~LLWorkerThread();
|
||||||
|
|
||||||
/*virtual*/ S32 update(U32 max_time_ms);
|
/*virtual*/ S32 update(U32 max_time_ms);
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ bool LLCrashLogger::sendCrashLogs()
|
|||||||
|
|
||||||
bool sent = false;
|
bool sent = false;
|
||||||
|
|
||||||
//*TODO: Translate
|
// *TODO: Translate
|
||||||
if(mCrashHost != "")
|
if(mCrashHost != "")
|
||||||
{
|
{
|
||||||
sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3, 5);
|
sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3, 5);
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
#include "llimagepng.h"
|
#include "llimagepng.h"
|
||||||
#include "llimagedxt.h"
|
#include "llimagedxt.h"
|
||||||
#include "llimageworker.h"
|
#include "llimageworker.h"
|
||||||
|
#include "llmemory.h"
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// LLImage
|
// LLImage
|
||||||
@@ -53,12 +54,14 @@
|
|||||||
//static
|
//static
|
||||||
std::string LLImage::sLastErrorMessage;
|
std::string LLImage::sLastErrorMessage;
|
||||||
LLMutex* LLImage::sMutex = NULL;
|
LLMutex* LLImage::sMutex = NULL;
|
||||||
|
LLPrivateMemoryPool* LLImageBase::sPrivatePoolp = NULL ;
|
||||||
|
|
||||||
//static
|
//static
|
||||||
void LLImage::initClass()
|
void LLImage::initClass()
|
||||||
{
|
{
|
||||||
sMutex = new LLMutex;
|
sMutex = new LLMutex;
|
||||||
LLImageJ2C::openDSO();
|
LLImageJ2C::openDSO();
|
||||||
|
LLImageBase::createPrivatePool() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
@@ -67,6 +70,8 @@ void LLImage::cleanupClass()
|
|||||||
LLImageJ2C::closeDSO();
|
LLImageJ2C::closeDSO();
|
||||||
delete sMutex;
|
delete sMutex;
|
||||||
sMutex = NULL;
|
sMutex = NULL;
|
||||||
|
|
||||||
|
LLImageBase::destroyPrivatePool() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
@@ -105,6 +110,25 @@ LLImageBase::~LLImageBase()
|
|||||||
deleteData(); // virtual
|
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
|
// virtual
|
||||||
void LLImageBase::dump()
|
void LLImageBase::dump()
|
||||||
{
|
{
|
||||||
@@ -138,7 +162,7 @@ void LLImageBase::sanityCheck()
|
|||||||
// virtual
|
// virtual
|
||||||
void LLImageBase::deleteData()
|
void LLImageBase::deleteData()
|
||||||
{
|
{
|
||||||
delete[] mData;
|
FREE_MEM(sPrivatePoolp, mData) ;
|
||||||
mData = NULL;
|
mData = NULL;
|
||||||
mDataSize = 0;
|
mDataSize = 0;
|
||||||
}
|
}
|
||||||
@@ -164,14 +188,14 @@ U8* LLImageBase::allocateData(S32 size)
|
|||||||
if (!mData || size != mDataSize)
|
if (!mData || size != mDataSize)
|
||||||
{
|
{
|
||||||
deleteData(); // virtual
|
deleteData(); // virtual
|
||||||
mBadBufferAllocation = FALSE ;
|
mBadBufferAllocation = false ;
|
||||||
mData = new (std::nothrow) U8[size];
|
mData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
|
||||||
if (!mData)
|
if (!mData)
|
||||||
{
|
{
|
||||||
llwarns << "allocate image data: " << size << llendl;
|
llwarns << "allocate image data: " << size << llendl;
|
||||||
size = 0 ;
|
size = 0 ;
|
||||||
mWidth = mHeight = 0 ;
|
mWidth = mHeight = 0 ;
|
||||||
mBadBufferAllocation = TRUE ;
|
mBadBufferAllocation = true ;
|
||||||
}
|
}
|
||||||
mDataSize = size;
|
mDataSize = size;
|
||||||
}
|
}
|
||||||
@@ -186,7 +210,7 @@ U8* LLImageBase::reallocateData(S32 size)
|
|||||||
return mData;
|
return mData;
|
||||||
|
|
||||||
LLMemType mt1((LLMemType::EMemType)mMemType);
|
LLMemType mt1((LLMemType::EMemType)mMemType);
|
||||||
U8 *new_datap = new (std::nothrow) U8[size];
|
U8 *new_datap = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
|
||||||
if (!new_datap)
|
if (!new_datap)
|
||||||
{
|
{
|
||||||
llwarns << "Out of memory in LLImageBase::reallocateData" << llendl;
|
llwarns << "Out of memory in LLImageBase::reallocateData" << llendl;
|
||||||
@@ -196,7 +220,7 @@ U8* LLImageBase::reallocateData(S32 size)
|
|||||||
{
|
{
|
||||||
S32 bytes = llmin(mDataSize, size);
|
S32 bytes = llmin(mDataSize, size);
|
||||||
memcpy(new_datap, mData, bytes); /* Flawfinder: ignore */
|
memcpy(new_datap, mData, bytes); /* Flawfinder: ignore */
|
||||||
delete[] mData;
|
FREE_MEM(sPrivatePoolp, mData) ;
|
||||||
}
|
}
|
||||||
mData = new_datap;
|
mData = new_datap;
|
||||||
mDataSize = size;
|
mDataSize = size;
|
||||||
@@ -276,11 +300,11 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components)
|
|||||||
++sRawImageCount;
|
++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)
|
: LLImageBase(), mCacheEntries(0)
|
||||||
{
|
{
|
||||||
createFromFile(filename, j2c_lowest_mip_only);
|
createFromFile(filename, j2c_lowest_mip_only);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
LLImageRaw::~LLImageRaw()
|
LLImageRaw::~LLImageRaw()
|
||||||
{
|
{
|
||||||
@@ -346,10 +370,11 @@ BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
|
U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
|
||||||
{
|
{
|
||||||
LLMemType mt1((LLMemType::EMemType)mMemType);
|
LLMemType mt1(mMemType);
|
||||||
U8 *data = new (std::nothrow) U8[width*height*getComponents()];
|
U8 *data = new U8[width*height*getComponents()];
|
||||||
|
|
||||||
// Should do some simple bounds checking
|
// Should do some simple bounds checking
|
||||||
if (!data)
|
if (!data)
|
||||||
@@ -366,6 +391,7 @@ U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
|
|||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
|
BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
|
||||||
const U8 *data, U32 stride, BOOL reverse_y)
|
const U8 *data, U32 stride, BOOL reverse_y)
|
||||||
@@ -856,11 +882,11 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
|
|||||||
delete[] temp_buffer;
|
delete[] temp_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
//scale down image by not blending a pixel with its neighbors.
|
//scale down image by not blending a pixel with its neighbors.
|
||||||
BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
|
BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
|
||||||
{
|
{
|
||||||
LLMemType mt1((LLMemType::EMemType)mMemType);
|
LLMemType mt1(mMemType);
|
||||||
|
|
||||||
S8 c = getComponents() ;
|
S8 c = getComponents() ;
|
||||||
llassert((1 == c) || (3 == c) || (4 == c) );
|
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_x -= 1.0f ;
|
||||||
ratio_y -= 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) ;
|
llassert_always(new_data != NULL) ;
|
||||||
|
|
||||||
U8* old_data = getData() ;
|
U8* old_data = getData() ;
|
||||||
@@ -902,6 +928,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
|
|||||||
|
|
||||||
return TRUE ;
|
return TRUE ;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
|
BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
|
||||||
{
|
{
|
||||||
@@ -1222,7 +1249,7 @@ file_extensions[] =
|
|||||||
{ "png", IMG_CODEC_PNG }
|
{ "png", IMG_CODEC_PNG }
|
||||||
};
|
};
|
||||||
#define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions)
|
#define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions)
|
||||||
|
#if 0
|
||||||
static std::string find_file(std::string &name, S8 *codec)
|
static std::string find_file(std::string &name, S8 *codec)
|
||||||
{
|
{
|
||||||
std::string tname;
|
std::string tname;
|
||||||
@@ -1240,7 +1267,7 @@ static std::string find_file(std::string &name, S8 *codec)
|
|||||||
}
|
}
|
||||||
return std::string("");
|
return std::string("");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
|
EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
|
||||||
{
|
{
|
||||||
for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
|
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;
|
return IMG_CODEC_INVALID;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only)
|
bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only)
|
||||||
{
|
{
|
||||||
std::string name = filename;
|
std::string name = filename;
|
||||||
@@ -1336,7 +1363,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// LLImageFormatted
|
// LLImageFormatted
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@@ -1568,7 +1595,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size)
|
|||||||
S32 newsize = cursize + size;
|
S32 newsize = cursize + size;
|
||||||
reallocateData(newsize);
|
reallocateData(newsize);
|
||||||
memcpy(getData() + cursize, data, size);
|
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 LLImageFormatted;
|
||||||
class LLImageRaw;
|
class LLImageRaw;
|
||||||
class LLColor4U;
|
class LLColor4U;
|
||||||
|
class LLPrivateMemoryPool;
|
||||||
|
|
||||||
typedef enum e_image_codec
|
typedef enum e_image_codec
|
||||||
{
|
{
|
||||||
@@ -144,6 +145,9 @@ public:
|
|||||||
|
|
||||||
static EImageCodec getCodecFromExtension(const std::string& exten);
|
static EImageCodec getCodecFromExtension(const std::string& exten);
|
||||||
|
|
||||||
|
static void createPrivatePool() ;
|
||||||
|
static void destroyPrivatePool() ;
|
||||||
|
static LLPrivateMemoryPool* getPrivatePool() {return sPrivatePoolp;}
|
||||||
private:
|
private:
|
||||||
U8 *mData;
|
U8 *mData;
|
||||||
S32 mDataSize;
|
S32 mDataSize;
|
||||||
@@ -155,6 +159,8 @@ private:
|
|||||||
|
|
||||||
bool mBadBufferAllocation ;
|
bool mBadBufferAllocation ;
|
||||||
bool mAllowOverSize ;
|
bool mAllowOverSize ;
|
||||||
|
|
||||||
|
static LLPrivateMemoryPool* sPrivatePoolp ;
|
||||||
public:
|
public:
|
||||||
S16 mMemType; // debug
|
S16 mMemType; // debug
|
||||||
};
|
};
|
||||||
@@ -170,7 +176,7 @@ public:
|
|||||||
LLImageRaw(U16 width, U16 height, S8 components);
|
LLImageRaw(U16 width, U16 height, S8 components);
|
||||||
LLImageRaw(U8 *data, U16 width, U16 height, S8 components);
|
LLImageRaw(U8 *data, U16 width, U16 height, S8 components);
|
||||||
// Construct using createFromFile (used by tools)
|
// Construct using createFromFile (used by tools)
|
||||||
LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
|
//LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
|
||||||
|
|
||||||
/*virtual*/ void deleteData();
|
/*virtual*/ void deleteData();
|
||||||
/*virtual*/ U8* allocateData(S32 size = -1);
|
/*virtual*/ U8* allocateData(S32 size = -1);
|
||||||
@@ -178,7 +184,7 @@ public:
|
|||||||
|
|
||||||
BOOL resize(U16 width, U16 height, S8 components);
|
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,
|
BOOL setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
|
||||||
const U8 *data, U32 stride = 0, BOOL reverse_y = FALSE);
|
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 contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
|
||||||
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
|
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
|
||||||
BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
|
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
|
// Fill the buffer with a constant color
|
||||||
void fill( const LLColor4U& color );
|
void fill( const LLColor4U& color );
|
||||||
@@ -232,7 +238,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Create an image from a local file (generally used in tools)
|
// 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 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 );
|
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 nmips = calcNumMips(width,height);
|
||||||
S32 total_bytes = getDataSize();
|
S32 total_bytes = getDataSize();
|
||||||
U8* olddata = getData();
|
U8* olddata = getData();
|
||||||
U8* newdata = new (std::nothrow) U8[total_bytes];
|
U8* newdata = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_bytes);
|
||||||
if (!newdata)
|
if (!newdata)
|
||||||
{
|
{
|
||||||
llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl;
|
llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl;
|
||||||
|
|||||||
@@ -501,14 +501,14 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
U8 *data = new U8[file_size];
|
U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size);
|
||||||
apr_size_t bytes_read = file_size;
|
apr_size_t bytes_read = file_size;
|
||||||
apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read
|
apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read
|
||||||
infile.close() ;
|
infile.close() ;
|
||||||
|
|
||||||
if (s != APR_SUCCESS || (S32)bytes_read != file_size)
|
if (s != APR_SUCCESS || (S32)bytes_read != file_size)
|
||||||
{
|
{
|
||||||
delete[] data;
|
FREE_MEM(LLImageBase::getPrivatePool(), data);
|
||||||
setLastError("Unable to read entire file");
|
setLastError("Unable to read entire file");
|
||||||
res = FALSE;
|
res = FALSE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "llinventory.h"
|
#include "llinventory.h"
|
||||||
|
|
||||||
#include "lldbstrings.h"
|
#include "lldbstrings.h"
|
||||||
|
#include "llfasttimer.h"
|
||||||
#include "llinventorydefines.h"
|
#include "llinventorydefines.h"
|
||||||
#include "llxorcipher.h"
|
#include "llxorcipher.h"
|
||||||
#include "llsd.h"
|
#include "llsd.h"
|
||||||
@@ -226,7 +227,7 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// exportFile should be replaced with exportLegacyStream
|
// 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
|
BOOL LLInventoryObject::exportFile(LLFILE* fp, BOOL) const
|
||||||
{
|
{
|
||||||
std::string uuid_str;
|
std::string uuid_str;
|
||||||
@@ -1055,8 +1056,11 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
|
|||||||
sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate;
|
sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLFastTimer::DeclareTimer FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize");
|
||||||
|
|
||||||
bool LLInventoryItem::fromLLSD(const LLSD& sd)
|
bool LLInventoryItem::fromLLSD(const LLSD& sd)
|
||||||
{
|
{
|
||||||
|
LLFastTimer _(FTM_INVENTORY_SD_DESERIALIZE);
|
||||||
mInventoryType = LLInventoryType::IT_NONE;
|
mInventoryType = LLInventoryType::IT_NONE;
|
||||||
mAssetUUID.setNull();
|
mAssetUUID.setNull();
|
||||||
std::string w;
|
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
|
// Number of "chunks" in which parcel overlay data is sent
|
||||||
// Chunk 0 = southern rows, entire width
|
// Chunk 0 = southern rows, entire width
|
||||||
// NOTE: NOT USABLE FOR VAR SIZED REGIONS!
|
|
||||||
const S32 PARCEL_OVERLAY_CHUNKS = 4;
|
const S32 PARCEL_OVERLAY_CHUNKS = 4;
|
||||||
|
|
||||||
// Bottom three bits are a color index for the land overlay
|
// Bottom three bits are a color index for the land overlay
|
||||||
|
|||||||
@@ -30,8 +30,8 @@
|
|||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "llsaleinfo.h"
|
#include "llsaleinfo.h"
|
||||||
|
|
||||||
|
|||||||
@@ -75,10 +75,6 @@ set(llmath_HEADER_FILES
|
|||||||
llvector4a.h
|
llvector4a.h
|
||||||
llvector4a.inl
|
llvector4a.inl
|
||||||
llvector4logical.h
|
llvector4logical.h
|
||||||
llv4math.h
|
|
||||||
llv4matrix3.h
|
|
||||||
llv4matrix4.h
|
|
||||||
llv4vector3.h
|
|
||||||
llvolume.h
|
llvolume.h
|
||||||
llvolumemgr.h
|
llvolumemgr.h
|
||||||
llvolumeoctree.h
|
llvolumeoctree.h
|
||||||
|
|||||||
@@ -531,13 +531,13 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
S32 j = data.size()-1;
|
S32 j = (S32)data.size()-1;
|
||||||
while (j > 0 && data[j] > max)
|
while (j > 0 && data[j] > max)
|
||||||
{
|
{
|
||||||
j--;
|
j--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j < data.size()-1)
|
if (j < (S32)data.size()-1)
|
||||||
{
|
{
|
||||||
data.erase(data.begin()+j, data.end());
|
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 srcCol1 = src.mColumns[1];
|
||||||
const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 );
|
const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 );
|
||||||
mColumns[0] = _mm_movelh_ps( unpacklo, src.mColumns[2] );
|
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) );
|
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[2].setAdd(a.mMatrix[2],d2);
|
||||||
mMatrix[3].setAdd(a.mMatrix[3],d3);
|
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));
|
LLVector4a x,y,z;
|
||||||
res.mul(mMatrix[0]);
|
|
||||||
|
|
||||||
LLVector4a y;
|
|
||||||
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
|
|
||||||
y.mul(mMatrix[1]);
|
|
||||||
|
|
||||||
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));
|
z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
|
||||||
|
|
||||||
|
x.mul(mMatrix[0]);
|
||||||
|
y.mul(mMatrix[1]);
|
||||||
z.mul(mMatrix[2]);
|
z.mul(mMatrix[2]);
|
||||||
|
|
||||||
res.add(y);
|
x.add(y);
|
||||||
res.add(z);
|
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;
|
LLVector4a x,y,z;
|
||||||
|
|
||||||
|
|||||||
@@ -691,7 +691,7 @@ public:
|
|||||||
|
|
||||||
if (lt != 0x7)
|
if (lt != 0x7)
|
||||||
{
|
{
|
||||||
OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
|
//OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
|
||||||
return false;
|
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;
|
mFaceMask = 0x0;
|
||||||
mDetail = detail;
|
mDetail = detail;
|
||||||
mSculptLevel = -2;
|
mSculptLevel = -2;
|
||||||
#if MESH_ENABLED
|
mSurfaceArea = 1.f; //only calculated for sculpts, defaults to 1 for all other prims
|
||||||
mIsMeshAssetLoaded = FALSE;
|
mIsMeshAssetLoaded = FALSE;
|
||||||
mLODScaleBias.setVec(1,1,1);
|
mLODScaleBias.setVec(1,1,1);
|
||||||
mHullPoints = NULL;
|
mHullPoints = NULL;
|
||||||
mHullIndices = NULL;
|
mHullIndices = NULL;
|
||||||
mNumHullPoints = 0;
|
mNumHullPoints = 0;
|
||||||
mNumHullIndices = 0;
|
mNumHullIndices = 0;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
|
if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
|
||||||
{
|
{
|
||||||
@@ -2139,12 +2138,10 @@ LLVolume::~LLVolume()
|
|||||||
mProfilep = NULL;
|
mProfilep = NULL;
|
||||||
mVolumeFaces.clear();
|
mVolumeFaces.clear();
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
ll_aligned_free_16(mHullPoints);
|
ll_aligned_free_16(mHullPoints);
|
||||||
mHullPoints = NULL;
|
mHullPoints = NULL;
|
||||||
ll_aligned_free_16(mHullIndices);
|
ll_aligned_free_16(mHullIndices);
|
||||||
mHullIndices = NULL;
|
mHullIndices = NULL;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL LLVolume::generate()
|
BOOL LLVolume::generate()
|
||||||
@@ -2186,7 +2183,7 @@ BOOL LLVolume::generate()
|
|||||||
mLODScaleBias.setVec(0.6f, 0.6f, 0.6f);
|
mLODScaleBias.setVec(0.6f, 0.6f, 0.6f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//********************************************************************
|
// ********************************************************************
|
||||||
//debug info, to be removed
|
//debug info, to be removed
|
||||||
if((U32)(mPathp->mPath.size() * mProfilep->mProfile.size()) > (1u << 20))
|
if((U32)(mPathp->mPath.size() * mProfilep->mProfile.size()) > (1u << 20))
|
||||||
{
|
{
|
||||||
@@ -2198,7 +2195,7 @@ BOOL LLVolume::generate()
|
|||||||
|
|
||||||
llerrs << "LLVolume corrupted!" << llendl ;
|
llerrs << "LLVolume corrupted!" << llendl ;
|
||||||
}
|
}
|
||||||
//********************************************************************
|
// ********************************************************************
|
||||||
|
|
||||||
BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split);
|
BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split);
|
||||||
BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_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 sizeS = mPathp->mPath.size();
|
||||||
S32 sizeT = mProfilep->mProfile.size();
|
S32 sizeT = mProfilep->mProfile.size();
|
||||||
|
|
||||||
//********************************************************************
|
// ********************************************************************
|
||||||
//debug info, to be removed
|
//debug info, to be removed
|
||||||
if((U32)(sizeS * sizeT) > (1u << 20))
|
if((U32)(sizeS * sizeT) > (1u << 20))
|
||||||
{
|
{
|
||||||
@@ -2221,7 +2218,7 @@ BOOL LLVolume::generate()
|
|||||||
|
|
||||||
llerrs << "LLVolume corrupted!" << llendl ;
|
llerrs << "LLVolume corrupted!" << llendl ;
|
||||||
}
|
}
|
||||||
//********************************************************************
|
// ********************************************************************
|
||||||
|
|
||||||
sNumMeshPoints -= mMesh.size();
|
sNumMeshPoints -= mMesh.size();
|
||||||
mMesh.resize(sizeT * sizeS);
|
mMesh.resize(sizeT * sizeS);
|
||||||
@@ -2406,7 +2403,6 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
|
bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
|
||||||
{
|
{
|
||||||
//input stream is now pointing at a zlib compressed block of LLSD
|
//input stream is now pointing at a zlib compressed block of LLSD
|
||||||
@@ -2736,7 +2732,7 @@ void LLVolume::cacheOptimize()
|
|||||||
mVolumeFaces[i].cacheOptimize();
|
mVolumeFaces[i].cacheOptimize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
S32 LLVolume::getNumFaces() const
|
S32 LLVolume::getNumFaces() const
|
||||||
{
|
{
|
||||||
@@ -3157,6 +3153,8 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components,
|
|||||||
{
|
{
|
||||||
F32 area = sculptGetSurfaceArea();
|
F32 area = sculptGetSurfaceArea();
|
||||||
|
|
||||||
|
mSurfaceArea = area;
|
||||||
|
|
||||||
const F32 SCULPT_MAX_AREA = 384.f;
|
const F32 SCULPT_MAX_AREA = 384.f;
|
||||||
|
|
||||||
if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA)
|
if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA)
|
||||||
@@ -3205,12 +3203,10 @@ bool LLVolumeParams::isSculpt() const
|
|||||||
return mSculptID.notNull();
|
return mSculptID.notNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
bool LLVolumeParams::isMeshSculpt() const
|
bool LLVolumeParams::isMeshSculpt() const
|
||||||
{
|
{
|
||||||
return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
|
return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
|
||||||
}
|
}
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const
|
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 triangle_count = 0;
|
||||||
|
U32 vertex_count = 0;
|
||||||
|
|
||||||
for (S32 i = 0; i < getNumVolumeFaces(); ++i)
|
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;
|
return triangle_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4357,13 +4363,11 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
|||||||
vertices.clear();
|
vertices.clear();
|
||||||
normals.clear();
|
normals.clear();
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
|
if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
S32 cur_index = 0;
|
S32 cur_index = 0;
|
||||||
//for each face
|
//for each face
|
||||||
for (face_list_t::iterator iter = mVolumeFaces.begin();
|
for (face_list_t::iterator iter = mVolumeFaces.begin();
|
||||||
@@ -4622,18 +4626,83 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
|
|||||||
genBinormals(i);
|
genBinormals(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!face.mOctree)
|
if (isUnique())
|
||||||
{
|
{ //don't bother with an octree for flexi volumes
|
||||||
face.createOctree();
|
U32 tri_count = face.mNumIndices/3;
|
||||||
}
|
|
||||||
|
|
||||||
//LLVector4a* p = (LLVector4a*) face.mPositions;
|
|
||||||
|
|
||||||
LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
|
for (U32 j = 0; j < tri_count; ++j)
|
||||||
intersect.traverse(face.mOctree);
|
{
|
||||||
if (intersect.mHitFace)
|
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),
|
mBinormals(NULL),
|
||||||
mTexCoords(NULL),
|
mTexCoords(NULL),
|
||||||
mIndices(NULL),
|
mIndices(NULL),
|
||||||
#if MESH_ENABLED
|
|
||||||
mWeights(NULL),
|
mWeights(NULL),
|
||||||
#endif //MESH_ENABLED
|
|
||||||
mOctree(NULL)
|
mOctree(NULL)
|
||||||
{
|
{
|
||||||
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
||||||
@@ -5439,9 +5506,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
|
|||||||
mBinormals(NULL),
|
mBinormals(NULL),
|
||||||
mTexCoords(NULL),
|
mTexCoords(NULL),
|
||||||
mIndices(NULL),
|
mIndices(NULL),
|
||||||
#if MESH_ENABLED
|
|
||||||
mWeights(NULL),
|
mWeights(NULL),
|
||||||
#endif //MESH_ENABLED
|
|
||||||
mOctree(NULL)
|
mOctree(NULL)
|
||||||
{
|
{
|
||||||
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
||||||
@@ -5507,7 +5572,6 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
|||||||
mBinormals = NULL;
|
mBinormals = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
if (src.mWeights)
|
if (src.mWeights)
|
||||||
{
|
{
|
||||||
allocateWeights(src.mNumVertices);
|
allocateWeights(src.mNumVertices);
|
||||||
@@ -5518,8 +5582,8 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
|||||||
ll_aligned_free_16(mWeights);
|
ll_aligned_free_16(mWeights);
|
||||||
mWeights = NULL;
|
mWeights = NULL;
|
||||||
}
|
}
|
||||||
#endif //MESH_ENABLED
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNumIndices)
|
if (mNumIndices)
|
||||||
{
|
{
|
||||||
S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF;
|
S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF;
|
||||||
@@ -5551,10 +5615,8 @@ void LLVolumeFace::freeData()
|
|||||||
mIndices = NULL;
|
mIndices = NULL;
|
||||||
ll_aligned_free_16(mBinormals);
|
ll_aligned_free_16(mBinormals);
|
||||||
mBinormals = NULL;
|
mBinormals = NULL;
|
||||||
#if MESH_ENABLED
|
|
||||||
ll_aligned_free_16(mWeights);
|
ll_aligned_free_16(mWeights);
|
||||||
mWeights = NULL;
|
mWeights = NULL;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
delete mOctree;
|
delete mOctree;
|
||||||
mOctree = NULL;
|
mOctree = NULL;
|
||||||
@@ -6125,13 +6187,11 @@ void LLVolumeFace::cacheOptimize()
|
|||||||
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||||
LLVector2* tc = (LLVector2*) ll_aligned_malloc_16(size);
|
LLVector2* tc = (LLVector2*) ll_aligned_malloc_16(size);
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
LLVector4a* wght = NULL;
|
LLVector4a* wght = NULL;
|
||||||
if (mWeights)
|
if (mWeights)
|
||||||
{
|
{
|
||||||
wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||||
}
|
}
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
LLVector4a* binorm = NULL;
|
LLVector4a* binorm = NULL;
|
||||||
if (mBinormals)
|
if (mBinormals)
|
||||||
@@ -6155,12 +6215,10 @@ void LLVolumeFace::cacheOptimize()
|
|||||||
pos[cur_idx] = mPositions[idx];
|
pos[cur_idx] = mPositions[idx];
|
||||||
norm[cur_idx] = mNormals[idx];
|
norm[cur_idx] = mNormals[idx];
|
||||||
tc[cur_idx] = mTexCoords[idx];
|
tc[cur_idx] = mTexCoords[idx];
|
||||||
#if MESH_ENABLED
|
|
||||||
if (mWeights)
|
if (mWeights)
|
||||||
{
|
{
|
||||||
wght[cur_idx] = mWeights[idx];
|
wght[cur_idx] = mWeights[idx];
|
||||||
}
|
}
|
||||||
#endif //MESH_ENABLED
|
|
||||||
if (mBinormals)
|
if (mBinormals)
|
||||||
{
|
{
|
||||||
binorm[cur_idx] = mBinormals[idx];
|
binorm[cur_idx] = mBinormals[idx];
|
||||||
@@ -6178,17 +6236,13 @@ void LLVolumeFace::cacheOptimize()
|
|||||||
ll_aligned_free_16(mPositions);
|
ll_aligned_free_16(mPositions);
|
||||||
ll_aligned_free_16(mNormals);
|
ll_aligned_free_16(mNormals);
|
||||||
ll_aligned_free_16(mTexCoords);
|
ll_aligned_free_16(mTexCoords);
|
||||||
#if MESH_ENABLED
|
|
||||||
ll_aligned_free_16(mWeights);
|
ll_aligned_free_16(mWeights);
|
||||||
#endif //MESH_ENABLED
|
|
||||||
ll_aligned_free_16(mBinormals);
|
ll_aligned_free_16(mBinormals);
|
||||||
|
|
||||||
mPositions = pos;
|
mPositions = pos;
|
||||||
mNormals = norm;
|
mNormals = norm;
|
||||||
mTexCoords = tc;
|
mTexCoords = tc;
|
||||||
#if MESH_ENABLED
|
|
||||||
mWeights = wght;
|
mWeights = wght;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
mBinormals = binorm;
|
mBinormals = binorm;
|
||||||
|
|
||||||
//std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
|
//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.mNumVertices, mNumVertices);
|
||||||
llswap(rhs.mNumIndices, mNumIndices);
|
llswap(rhs.mNumIndices, mNumIndices);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LerpPlanarVertex(LLVolumeFace::VertexData& v0,
|
void LerpPlanarVertex(LLVolumeFace::VertexData& v0,
|
||||||
LLVolumeFace::VertexData& v1,
|
LLVolumeFace::VertexData& v1,
|
||||||
LLVolumeFace::VertexData& v2,
|
LLVolumeFace::VertexData& v2,
|
||||||
@@ -6971,14 +7026,11 @@ void LLVolumeFace::allocateBinormals(S32 num_verts)
|
|||||||
mBinormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
mBinormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
void LLVolumeFace::allocateWeights(S32 num_verts)
|
void LLVolumeFace::allocateWeights(S32 num_verts)
|
||||||
{
|
{
|
||||||
|
|
||||||
ll_aligned_free_16(mWeights);
|
ll_aligned_free_16(mWeights);
|
||||||
mWeights = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
mWeights = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||||
}
|
}
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
void LLVolumeFace::resizeIndices(S32 num_indices)
|
void LLVolumeFace::resizeIndices(S32 num_indices)
|
||||||
{
|
{
|
||||||
@@ -7141,9 +7193,8 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
|
|||||||
{
|
{
|
||||||
resizeVertices(num_vertices);
|
resizeVertices(num_vertices);
|
||||||
resizeIndices(num_indices);
|
resizeIndices(num_indices);
|
||||||
#if MESH_ENABLED
|
|
||||||
if (!volume->isMeshAssetLoaded())
|
if (!volume->isMeshAssetLoaded())
|
||||||
#endif //MESH_ENABLED
|
|
||||||
{
|
{
|
||||||
mEdge.resize(num_indices);
|
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_TORUS = 2;
|
||||||
const U8 LL_SCULPT_TYPE_PLANE = 3;
|
const U8 LL_SCULPT_TYPE_PLANE = 3;
|
||||||
const U8 LL_SCULPT_TYPE_CYLINDER = 4;
|
const U8 LL_SCULPT_TYPE_CYLINDER = 4;
|
||||||
#if MESH_ENABLED
|
|
||||||
const U8 LL_SCULPT_TYPE_MESH = 5;
|
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 |
|
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;
|
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_INVERT = 64;
|
||||||
const U8 LL_SCULPT_FLAG_MIRROR = 128;
|
const U8 LL_SCULPT_FLAG_MIRROR = 128;
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
const S32 LL_SCULPT_MESH_MAX_FACES = 8;
|
const S32 LL_SCULPT_MESH_MAX_FACES = 8;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
class LLProfileParams
|
class LLProfileParams
|
||||||
{
|
{
|
||||||
@@ -655,9 +648,7 @@ public:
|
|||||||
const LLUUID& getSculptID() const { return mSculptID; }
|
const LLUUID& getSculptID() const { return mSculptID; }
|
||||||
const U8& getSculptType() const { return mSculptType; }
|
const U8& getSculptType() const { return mSculptType; }
|
||||||
bool isSculpt() const;
|
bool isSculpt() const;
|
||||||
#if MESH_ENABLED
|
bool isMeshSculpt() const;
|
||||||
bool isMeshSculpt() const;
|
|
||||||
#endif //MESH_ENABLED
|
|
||||||
BOOL isConvex() const;
|
BOOL isConvex() const;
|
||||||
|
|
||||||
// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
|
// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
|
||||||
@@ -865,9 +856,7 @@ public:
|
|||||||
|
|
||||||
void resizeVertices(S32 num_verts);
|
void resizeVertices(S32 num_verts);
|
||||||
void allocateBinormals(S32 num_verts);
|
void allocateBinormals(S32 num_verts);
|
||||||
#if MESH_ENABLED
|
|
||||||
void allocateWeights(S32 num_verts);
|
void allocateWeights(S32 num_verts);
|
||||||
#endif //MESH_ENABLED
|
|
||||||
void resizeIndices(S32 num_indices);
|
void resizeIndices(S32 num_indices);
|
||||||
void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
|
void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
|
||||||
|
|
||||||
@@ -939,12 +928,10 @@ public:
|
|||||||
|
|
||||||
std::vector<S32> mEdge;
|
std::vector<S32> mEdge;
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
//list of skin weights for rigged volumes
|
//list of skin weights for rigged volumes
|
||||||
// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
|
// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
|
||||||
// mWeights.size() should be empty or match mVertices.size()
|
// mWeights.size() should be empty or match mVertices.size()
|
||||||
LLVector4a* mWeights;
|
LLVector4a* mWeights;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
LLOctreeNode<LLVolumeTriangle>* mOctree;
|
LLOctreeNode<LLVolumeTriangle>* mOctree;
|
||||||
|
|
||||||
@@ -958,12 +945,7 @@ class LLVolume : public LLRefCount
|
|||||||
{
|
{
|
||||||
friend class LLVolumeLODGroup;
|
friend class LLVolumeLODGroup;
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
protected:
|
protected:
|
||||||
#endif //MESH_ENABLED
|
|
||||||
#if !MESH_ENABLED
|
|
||||||
private:
|
|
||||||
#endif //!MESH_ENABLED
|
|
||||||
LLVolume(const LLVolume&); // Don't implement
|
LLVolume(const LLVolume&); // Don't implement
|
||||||
~LLVolume(); // use unref
|
~LLVolume(); // use unref
|
||||||
|
|
||||||
@@ -989,6 +971,7 @@ public:
|
|||||||
S32 getNumFaces() const;
|
S32 getNumFaces() const;
|
||||||
S32 getNumVolumeFaces() const { return mVolumeFaces.size(); }
|
S32 getNumVolumeFaces() const { return mVolumeFaces.size(); }
|
||||||
F32 getDetail() const { return mDetail; }
|
F32 getDetail() const { return mDetail; }
|
||||||
|
F32 getSurfaceArea() const { return mSurfaceArea; }
|
||||||
const LLVolumeParams& getParams() const { return mParams; }
|
const LLVolumeParams& getParams() const { return mParams; }
|
||||||
LLVolumeParams getCopyOfParams() const { return mParams; }
|
LLVolumeParams getCopyOfParams() const { return mParams; }
|
||||||
const LLProfile& getProfile() const { return *mProfilep; }
|
const LLProfile& getProfile() const { return *mProfilep; }
|
||||||
@@ -1016,7 +999,7 @@ public:
|
|||||||
S32 getNumTriangleIndices() const;
|
S32 getNumTriangleIndices() const;
|
||||||
static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts);
|
static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts);
|
||||||
|
|
||||||
S32 getNumTriangles() const;
|
S32 getNumTriangles(S32* vcount = NULL) const;
|
||||||
|
|
||||||
void generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
void generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
||||||
std::vector<LLVector3> &normals,
|
std::vector<LLVector3> &normals,
|
||||||
@@ -1081,37 +1064,33 @@ private:
|
|||||||
protected:
|
protected:
|
||||||
BOOL generate();
|
BOOL generate();
|
||||||
void createVolumeFaces();
|
void createVolumeFaces();
|
||||||
#if MESH_ENABLED
|
|
||||||
public:
|
public:
|
||||||
virtual bool unpackVolumeFaces(std::istream& is, S32 size);
|
virtual bool unpackVolumeFaces(std::istream& is, S32 size);
|
||||||
|
|
||||||
virtual void setMeshAssetLoaded(BOOL loaded);
|
virtual void setMeshAssetLoaded(BOOL loaded);
|
||||||
virtual BOOL isMeshAssetLoaded();
|
virtual BOOL isMeshAssetLoaded();
|
||||||
#endif //MESH_ENABLED
|
|
||||||
protected:
|
protected:
|
||||||
BOOL mUnique;
|
BOOL mUnique;
|
||||||
F32 mDetail;
|
F32 mDetail;
|
||||||
S32 mSculptLevel;
|
S32 mSculptLevel;
|
||||||
#if MESH_ENABLED
|
F32 mSurfaceArea; //unscaled surface area
|
||||||
BOOL mIsMeshAssetLoaded;
|
BOOL mIsMeshAssetLoaded;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
|
|
||||||
LLVolumeParams mParams;
|
LLVolumeParams mParams;
|
||||||
LLPath *mPathp;
|
LLPath *mPathp;
|
||||||
LLProfile *mProfilep;
|
LLProfile *mProfilep;
|
||||||
std::vector<Point> mMesh;
|
std::vector<Point> mMesh;
|
||||||
|
|
||||||
BOOL mGenerateSingleFace;
|
BOOL mGenerateSingleFace;
|
||||||
typedef std::vector<LLVolumeFace> face_list_t;
|
typedef std::vector<LLVolumeFace> face_list_t;
|
||||||
face_list_t mVolumeFaces;
|
face_list_t mVolumeFaces;
|
||||||
|
|
||||||
#if MESH_ENABLED
|
|
||||||
public:
|
public:
|
||||||
LLVector4a* mHullPoints;
|
LLVector4a* mHullPoints;
|
||||||
U16* mHullIndices;
|
U16* mHullIndices;
|
||||||
S32 mNumHullPoints;
|
S32 mNumHullPoints;
|
||||||
S32 mNumHullIndices;
|
S32 mNumHullIndices;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
|
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);
|
volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
|
||||||
if( iter == mVolumeLODGroups.end() )
|
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)
|
if (mDataMutex)
|
||||||
{
|
{
|
||||||
mDataMutex->unlock();
|
mDataMutex->unlock();
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, c
|
|||||||
return (grt & 0x7) ? false : true;
|
return (grt & 0x7) ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node)
|
LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node)
|
||||||
{
|
{
|
||||||
node->addListener(this);
|
node->addListener(this);
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ public:
|
|||||||
{
|
{
|
||||||
U8 mV[LENGTHOFCOLOR4U];
|
U8 mV[LENGTHOFCOLOR4U];
|
||||||
U32 mAll;
|
U32 mAll;
|
||||||
LLColor4* mSources;
|
//LLColor4* mSources;
|
||||||
LLColor4U* mSourcesU;
|
//LLColor4U* mSourcesU;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,13 +39,10 @@
|
|||||||
const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f
|
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 MIN_OBJECT_Z = -256.f;
|
||||||
const F32 DEFAULT_MAX_PRIM_SCALE = 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;
|
const F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = DEFAULT_MAX_PRIM_SCALE;
|
||||||
#endif //MESH_ENABLED
|
|
||||||
const F32 MIN_PRIM_SCALE = 0.01f;
|
const F32 MIN_PRIM_SCALE = 0.01f;
|
||||||
const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX
|
const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX
|
||||||
|
|
||||||
|
|
||||||
class LLXform
|
class LLXform
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -30,13 +30,13 @@
|
|||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//*****************************************************************************
|
// *****************************************************************************
|
||||||
// llclassifiedflags.cpp
|
// llclassifiedflags.cpp
|
||||||
//
|
//
|
||||||
// Some exported symbols and functions for dealing with classified flags.
|
// Some exported symbols and functions for dealing with classified flags.
|
||||||
//
|
//
|
||||||
// Copyright 2005, Linden Research, Inc
|
// Copyright 2005, Linden Research, Inc
|
||||||
//*****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
|
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ U32 LLCurl::Easy::report(CURLcode code)
|
|||||||
if (code == CURLE_OK)
|
if (code == CURLE_OK)
|
||||||
{
|
{
|
||||||
check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode));
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -715,7 +715,7 @@ S32 LLCurl::Multi::process()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
response = 499;
|
response = 499;
|
||||||
//*TODO: change to llwarns
|
// *TODO: change to llwarns
|
||||||
llerrs << "cleaned up curl request completed!" << llendl;
|
llerrs << "cleaned up curl request completed!" << llendl;
|
||||||
}
|
}
|
||||||
if (response >= 400)
|
if (response >= 400)
|
||||||
|
|||||||
@@ -91,6 +91,8 @@
|
|||||||
#include "llsdserialize.h"
|
#include "llsdserialize.h"
|
||||||
#include "lluuid.h"
|
#include "lluuid.h"
|
||||||
|
|
||||||
|
#include "llfasttimer.h"
|
||||||
|
|
||||||
// spammy mode
|
// spammy mode
|
||||||
//#define LL_SPEW_STREAM_OUT_DEBUGGING 1
|
//#define LL_SPEW_STREAM_OUT_DEBUGGING 1
|
||||||
|
|
||||||
@@ -314,6 +316,7 @@ LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_RESPONSE("SD2XMLRPC Response");
|
||||||
// virtual
|
// virtual
|
||||||
LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
|
LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
|
||||||
const LLChannelDescriptors& channels,
|
const LLChannelDescriptors& channels,
|
||||||
@@ -322,6 +325,8 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_SD2XMLRPC_RESPONSE);
|
||||||
|
|
||||||
PUMP_DEBUG;
|
PUMP_DEBUG;
|
||||||
// This pipe does not work if it does not have everyting. This
|
// This pipe does not work if it does not have everyting. This
|
||||||
// could be addressed by making a stream parser for llsd which
|
// 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
|
// virtual
|
||||||
LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
|
LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
|
||||||
const LLChannelDescriptors& channels,
|
const LLChannelDescriptors& channels,
|
||||||
@@ -396,6 +403,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_SD2XMLRPC_REQUEST);
|
||||||
// This pipe does not work if it does not have everyting. This
|
// This pipe does not work if it does not have everyting. This
|
||||||
// could be addressed by making a stream parser for llsd which
|
// could be addressed by making a stream parser for llsd which
|
||||||
// handled partial information.
|
// handled partial information.
|
||||||
@@ -592,6 +600,8 @@ LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_RESPONSE("XMLRPC2LLSD Response");
|
||||||
|
|
||||||
LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
|
LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
|
||||||
const LLChannelDescriptors& channels,
|
const LLChannelDescriptors& channels,
|
||||||
buffer_ptr_t& buffer,
|
buffer_ptr_t& buffer,
|
||||||
@@ -599,6 +609,8 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_RESPONSE);
|
||||||
|
|
||||||
PUMP_DEBUG;
|
PUMP_DEBUG;
|
||||||
if(!eos) return STATUS_BREAK;
|
if(!eos) return STATUS_BREAK;
|
||||||
if(!buffer) return STATUS_ERROR;
|
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(
|
LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
|
||||||
const LLChannelDescriptors& channels,
|
const LLChannelDescriptors& channels,
|
||||||
buffer_ptr_t& buffer,
|
buffer_ptr_t& buffer,
|
||||||
@@ -681,6 +694,7 @@ LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_REQUEST);
|
||||||
PUMP_DEBUG;
|
PUMP_DEBUG;
|
||||||
if(!eos) return STATUS_BREAK;
|
if(!eos) return STATUS_BREAK;
|
||||||
if(!buffer) return STATUS_ERROR;
|
if(!buffer) return STATUS_ERROR;
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
#include "llstat.h"
|
#include "llstat.h"
|
||||||
#include "llstl.h"
|
#include "llstl.h"
|
||||||
#include "lltimer.h"
|
#include "lltimer.h"
|
||||||
|
#include "llfasttimer.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@@ -146,6 +147,7 @@ private:
|
|||||||
LLSD mHeaders;
|
LLSD mHeaders;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_PIPE("HTTP Pipe");
|
||||||
LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
||||||
const LLChannelDescriptors& channels,
|
const LLChannelDescriptors& channels,
|
||||||
buffer_ptr_t& buffer,
|
buffer_ptr_t& buffer,
|
||||||
@@ -153,6 +155,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_HTTP_PIPE);
|
||||||
PUMP_DEBUG;
|
PUMP_DEBUG;
|
||||||
lldebugs << "LLSDHTTPServer::process_impl" << llendl;
|
lldebugs << "LLSDHTTPServer::process_impl" << llendl;
|
||||||
|
|
||||||
@@ -434,6 +437,9 @@ protected:
|
|||||||
/**
|
/**
|
||||||
* LLHTTPResponseHeader
|
* LLHTTPResponseHeader
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_HEADER("HTTP Header");
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
|
LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
|
||||||
const LLChannelDescriptors& channels,
|
const LLChannelDescriptors& channels,
|
||||||
@@ -442,6 +448,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_HTTP_HEADER);
|
||||||
PUMP_DEBUG;
|
PUMP_DEBUG;
|
||||||
LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
|
LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
|
||||||
if(eos)
|
if(eos)
|
||||||
@@ -636,6 +643,8 @@ void LLHTTPResponder::markBad(
|
|||||||
<< "</body>\n</html>\n";
|
<< "</body>\n</html>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_RESPONDER("HTTP Responder");
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
LLIOPipe::EStatus LLHTTPResponder::process_impl(
|
LLIOPipe::EStatus LLHTTPResponder::process_impl(
|
||||||
const LLChannelDescriptors& channels,
|
const LLChannelDescriptors& channels,
|
||||||
@@ -644,6 +653,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_HTTP_RESPONDER);
|
||||||
PUMP_DEBUG;
|
PUMP_DEBUG;
|
||||||
LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
|
LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
|
||||||
LLIOPipe::EStatus status = STATUS_OK;
|
LLIOPipe::EStatus status = STATUS_OK;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
#include "llmemtype.h"
|
#include "llmemtype.h"
|
||||||
#include "llpumpio.h"
|
#include "llpumpio.h"
|
||||||
#include "llthread.h"
|
#include "llthread.h"
|
||||||
|
#include "llfasttimer.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// constants
|
// constants
|
||||||
@@ -290,6 +291,8 @@ LLIOSocketReader::~LLIOSocketReader()
|
|||||||
//lldebugs << "Destroying LLIOSocketReader" << llendl;
|
//lldebugs << "Destroying LLIOSocketReader" << llendl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PROCESS_SOCKET_READER("Socket Reader");
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
LLIOPipe::EStatus LLIOSocketReader::process_impl(
|
LLIOPipe::EStatus LLIOSocketReader::process_impl(
|
||||||
const LLChannelDescriptors& channels,
|
const LLChannelDescriptors& channels,
|
||||||
@@ -298,6 +301,7 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_SOCKET_READER);
|
||||||
PUMP_DEBUG;
|
PUMP_DEBUG;
|
||||||
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
||||||
if(!mSource) return STATUS_PRECONDITION_NOT_MET;
|
if(!mSource) return STATUS_PRECONDITION_NOT_MET;
|
||||||
@@ -390,6 +394,7 @@ LLIOSocketWriter::~LLIOSocketWriter()
|
|||||||
//lldebugs << "Destroying LLIOSocketWriter" << llendl;
|
//lldebugs << "Destroying LLIOSocketWriter" << llendl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PROCESS_SOCKET_WRITER("Socket Writer");
|
||||||
// virtual
|
// virtual
|
||||||
LLIOPipe::EStatus LLIOSocketWriter::process_impl(
|
LLIOPipe::EStatus LLIOSocketWriter::process_impl(
|
||||||
const LLChannelDescriptors& channels,
|
const LLChannelDescriptors& channels,
|
||||||
@@ -398,6 +403,7 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_SOCKET_WRITER);
|
||||||
PUMP_DEBUG;
|
PUMP_DEBUG;
|
||||||
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
||||||
if(!mDestination) return STATUS_PRECONDITION_NOT_MET;
|
if(!mDestination) return STATUS_PRECONDITION_NOT_MET;
|
||||||
@@ -542,6 +548,7 @@ void LLIOServerSocket::setResponseTimeout(F32 timeout_secs)
|
|||||||
mResponseTimeout = timeout_secs;
|
mResponseTimeout = timeout_secs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PROCESS_SERVER_SOCKET("Server Socket");
|
||||||
// virtual
|
// virtual
|
||||||
LLIOPipe::EStatus LLIOServerSocket::process_impl(
|
LLIOPipe::EStatus LLIOServerSocket::process_impl(
|
||||||
const LLChannelDescriptors& channels,
|
const LLChannelDescriptors& channels,
|
||||||
@@ -550,6 +557,7 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_SERVER_SOCKET);
|
||||||
PUMP_DEBUG;
|
PUMP_DEBUG;
|
||||||
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
LLMemType m1(LLMemType::MTYPE_IO_TCP);
|
||||||
if(!pump)
|
if(!pump)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
#include "llioutil.h"
|
#include "llioutil.h"
|
||||||
|
#include "llfasttimer.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LLIOFlush
|
* LLIOFlush
|
||||||
@@ -49,6 +50,8 @@ LLIOPipe::EStatus LLIOFlush::process_impl(
|
|||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PROCESS_SLEEP("IO Sleep");
|
||||||
/**
|
/**
|
||||||
* @class LLIOSleep
|
* @class LLIOSleep
|
||||||
*/
|
*/
|
||||||
@@ -59,6 +62,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_SLEEP);
|
||||||
if(mSeconds > 0.0)
|
if(mSeconds > 0.0)
|
||||||
{
|
{
|
||||||
if(pump) pump->sleepChain(mSeconds);
|
if(pump) pump->sleepChain(mSeconds);
|
||||||
@@ -68,6 +72,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl(
|
|||||||
return STATUS_DONE;
|
return STATUS_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PROCESS_ADD_CHAIN("Add Chain");
|
||||||
/**
|
/**
|
||||||
* @class LLIOAddChain
|
* @class LLIOAddChain
|
||||||
*/
|
*/
|
||||||
@@ -78,6 +83,7 @@ LLIOPipe::EStatus LLIOAddChain::process_impl(
|
|||||||
LLSD& context,
|
LLSD& context,
|
||||||
LLPumpIO* pump)
|
LLPumpIO* pump)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PROCESS_ADD_CHAIN);
|
||||||
pump->addChain(mChain, mTimeout);
|
pump->addChain(mChain, mTimeout);
|
||||||
return STATUS_DONE;
|
return STATUS_DONE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,18 +191,7 @@ LLPumpIO::LLPumpIO(void) :
|
|||||||
LLPumpIO::~LLPumpIO()
|
LLPumpIO::~LLPumpIO()
|
||||||
{
|
{
|
||||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||||
#if LL_THREADS_APR
|
cleanup();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)
|
bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)
|
||||||
@@ -447,11 +436,13 @@ void LLPumpIO::pump()
|
|||||||
pump(DEFAULT_POLL_TIMEOUT);
|
pump(DEFAULT_POLL_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO");
|
||||||
|
|
||||||
//timeout is in microseconds
|
//timeout is in microseconds
|
||||||
void LLPumpIO::pump(const S32& poll_timeout)
|
void LLPumpIO::pump(const S32& poll_timeout)
|
||||||
{
|
{
|
||||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||||
LLFastTimer t1(LLFastTimer::FTM_PUMPIO);
|
LLFastTimer t1(FTM_PUMP_IO);
|
||||||
//llinfos << "LLPumpIO::pump()" << llendl;
|
//llinfos << "LLPumpIO::pump()" << llendl;
|
||||||
|
|
||||||
// Run any pending runners.
|
// Run any pending runners.
|
||||||
@@ -779,6 +770,8 @@ bool LLPumpIO::respond(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLFastTimer::DeclareTimer FTM_PUMP_CALLBACK_CHAIN("Chain");
|
||||||
|
|
||||||
void LLPumpIO::callback()
|
void LLPumpIO::callback()
|
||||||
{
|
{
|
||||||
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
|
||||||
@@ -800,6 +793,7 @@ void LLPumpIO::callback()
|
|||||||
callbacks_t::iterator end = mCallbacks.end();
|
callbacks_t::iterator end = mCallbacks.end();
|
||||||
for(; it != end; ++it)
|
for(; it != end; ++it)
|
||||||
{
|
{
|
||||||
|
LLFastTimer t(FTM_PUMP_CALLBACK_CHAIN);
|
||||||
// it's always the first and last time for respone chains
|
// it's always the first and last time for respone chains
|
||||||
(*it).mHead = (*it).mChainLinks.begin();
|
(*it).mHead = (*it).mChainLinks.begin();
|
||||||
(*it).mInit = true;
|
(*it).mInit = true;
|
||||||
@@ -839,6 +833,22 @@ void LLPumpIO::initialize(void)
|
|||||||
apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
|
apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
|
||||||
#endif
|
#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()
|
void LLPumpIO::rebuildPollset()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -397,6 +397,7 @@ protected:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initialize();
|
void initialize();
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Given the internal state of the chains, rebuild the pollset
|
* @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