diff --git a/.gitattributes b/.gitattributes
index 30cc9de8f17..5c7f5b73b07 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,8 +1,5 @@
* text eol=lf
-# VSTool (normalization disabled)
-indra/tools/vstool/* -text
-
# Images
*.bmp binary
*.BMP binary
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 4bf2af644ae..5a5628ede2b 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -1,6 +1,7 @@
name: Build
on:
+ workflow_dispatch:
pull_request:
push:
branches: ["main", "release/*", "project/*"]
@@ -42,7 +43,7 @@ jobs:
needs: setup
strategy:
matrix:
- runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-latest","macos-15"]') }}
+ runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-2022","macos-15-xlarge"]') }}
configuration: ${{ fromJson(needs.setup.outputs.configurations) }}
runs-on: ${{ matrix.runner }}
outputs:
@@ -64,7 +65,7 @@ jobs:
# autobuild-package.xml.
AUTOBUILD_VCS_INFO: "true"
AUTOBUILD_VSVER: "170"
- DEVELOPER_DIR: "/Applications/Xcode_16.1.app/Contents/Developer"
+ DEVELOPER_DIR: "/Applications/Xcode_16.4.app/Contents/Developer"
# Ensure that Linden viewer builds engage Bugsplat.
BUGSPLAT_DB: ${{ needs.setup.outputs.bugsplat_db }}
build_coverity: false
@@ -93,7 +94,6 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: "3.11"
-
- name: Checkout build variables
uses: actions/checkout@v4
with:
@@ -306,11 +306,11 @@ jobs:
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
needs: build
- runs-on: windows-latest
+ runs-on: windows-2022
steps:
- name: Sign and package Windows viewer
if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID
- uses: secondlife/viewer-build-util/sign-pkg-windows@v2
+ uses: secondlife/viewer-build-util/sign-pkg-windows@v2.0.4
with:
vault_uri: "${{ env.AZURE_KEY_VAULT_URI }}"
cert_name: "${{ env.AZURE_CERT_NAME }}"
diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml
index 7866f943b5a..627ba512c41 100644
--- a/.github/workflows/cla.yaml
+++ b/.github/workflows/cla.yaml
@@ -23,4 +23,4 @@ jobs:
path-to-signatures: signatures.json
remote-organization-name: secondlife
remote-repository-name: cla-signatures
- allowlist: callum@mbp.localdomain,rye@lindenlab.com
+ allowlist: callum@mbp.localdomain,rye@lindenlab.com,rye
diff --git a/.github/workflows/qatest.yaml b/.github/workflows/qatest.yaml
index 4e10900441b..b6883d88d43 100644
--- a/.github/workflows/qatest.yaml
+++ b/.github/workflows/qatest.yaml
@@ -43,13 +43,25 @@ jobs:
artifact: Windows-installer
install-path: 'C:\viewer-automation-main'
- os: windows
- runner: qa-dan-asus
+ runner: qa-windows-asus-dan
+ artifact: Windows-installer
+ install-path: 'C:\viewer-automation-main'
+ - os: windows
+ runner: qa-windows-kurt
artifact: Windows-installer
install-path: 'C:\viewer-automation-main'
+ - os: mac
+ runner: qa-mac-dan
+ artifact: macOS-installer
+ install-path: '$HOME/Documents/viewer-automation'
- os: mac
runner: qa-mac-atlas
artifact: macOS-installer
install-path: '$HOME/Documents/viewer-automation'
+ - os: mac
+ runner: qa-mac-caleb
+ artifact: macOS-installer
+ install-path: '$HOME/Documents/viewer-automation'
fail-fast: false
runs-on: [self-hosted, "${{ matrix.runner }}"]
diff --git a/.gitignore b/.gitignore
index 3b3666af843..c4accf37b5b 100755
--- a/.gitignore
+++ b/.gitignore
@@ -26,7 +26,6 @@ debian/files
debian/secondlife-appearance-utility*
debian/secondlife-viewer*
indra/.distcc
-indra/cmake/*
indra/out/*
indra/packages/*
diff --git a/autobuild.xml b/autobuild.xml
index f792bac7895..43bdf6ed377 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -46,11 +46,11 @@
archive
name
darwin64
@@ -60,11 +60,11 @@
archive
name
linux64
@@ -74,11 +74,11 @@
archive
name
windows64
@@ -91,7 +91,7 @@
copyright
Copyright © 2012 The Apache Software Foundation, Licensed under the Apache License, Version 2.0.
version
- 1.7.4-10338381102
+ 1.7.5-12259255574
name
apr_suite
description
@@ -99,16 +99,6 @@
boost
+ license
+ boost 1.0
+ license_file
+ LICENSES/boost.txt
+ copyright
+ (see individual source files)
version
1.86
+ name
+ boost
+ description
+ Boost C++ Libraries
bugsplat
@@ -205,14 +205,6 @@
colladadom
- copyright
- Copyright 2006 Sony Computer Entertainment Inc.
- license
- SCEA
- license_file
- LICENSES/collada.txt
- name
- colladadom
platforms
darwin64
@@ -220,11 +212,11 @@
archive
hash
- 18b46ce8ebb5ae6ef6527b4e95408433e29ad3f4
+ bf2fe4e8272e990bc8687b3b37bf4bb2b2ad6eb4
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r8/colladadom-2.3.0-r8-darwin64-10476582237.tar.zst
+ https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-darwin64-13259816660.tar.zst
name
darwin64
@@ -234,11 +226,11 @@
archive
hash
- c088fe0be9ce7e42983c3c7708abe4ac8bd5a894
+ 118e509ca464182ef4b94ee8c4aa5b14a6c52a94
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r8/colladadom-2.3.0-r8-linux64-10476582237.tar.zst
+ https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-linux64-13259816660.tar.zst
name
linux64
@@ -248,18 +240,26 @@
archive
hash
- 8bfa9f1a78d077f3bd422f14ae360150b98c82f9
+ d7aee1b2ec17bd88a2c27359281b58a11ec52d48
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r8/colladadom-2.3.0-r8-windows64-10476582237.tar.zst
+ https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-windows64-13259816660.tar.zst
name
windows64
+ license
+ SCEA
+ license_file
+ LICENSES/collada.txt
+ copyright
+ Copyright 2006 Sony Computer Entertainment Inc.
version
- 2.3.0-r8
+ 2.3.0-r10
+ name
+ colladadom
cubemaptoequirectangular
@@ -290,6 +290,8 @@
url
https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-d7afe27/cubemaptoequirectangular-1.1.0-linux64-d7afe27.tar.zst
+ name
+ linux64
windows64
@@ -326,11 +328,11 @@
archive
hash
- 9c74adfd217fcc04869ef574078bc56a4a1380f3
+ e742b1e2d0a58d607b023bf55411041ac65e8a76
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r1/curl-7.54.1-10342910827-darwin64-10342910827.tar.zst
+ https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-darwin64-13259824618.tar.zst
name
darwin64
@@ -340,11 +342,11 @@
archive
hash
- 325ad581a1ba99fbc1e74d48481e07546eaf1e0e
+ 49621c70f385d37c95bcb69a9a24d86ac25f4781
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r1/curl-7.54.1-10342910827-linux64-10342910827.tar.zst
+ https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-linux64-13259824618.tar.zst
name
linux64
@@ -354,11 +356,11 @@
archive
hash
- 794480208e72a928552760cd048438b90aa1c80d
+ 2522201692116cf0adb7203e169be9126885108c
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r1/curl-7.54.1-10342910827-windows64-10342910827.tar.zst
+ https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-windows64-13259824618.tar.zst
name
windows64
@@ -371,7 +373,7 @@
copyright
Copyright (c) 1996 - 2014, Daniel Stenberg, (daniel@haxx.se).
version
- 7.54.1-10342910827
+ 7.54.1-13259824618
name
curl
description
@@ -441,16 +443,6 @@
dullahan
- copyright
- Copyright (c) 2017, Linden Research, Inc.
- description
- A headless browser SDK that uses the Chromium Embedded Framework (CEF). It is designed to make it easier to write applications that render modern web content directly to a memory buffer, inject synthesized mouse and keyboard events as well as interact with web based features like JavaScript or cookies.
- license
- MPL
- license_file
- LICENSES/LICENSE.txt
- name
- dullahan
platforms
darwin64
@@ -458,11 +450,11 @@
archive
hash
- 7fde76e3f0e62d0e0593b6157f4d740ecef2429d
+ d44256458ff0ef4db4c91e8e8cc83e8f98b4f1b8
hash_algorithm
sha1
url
- https://github.com/secondlife/dullahan/releases/download/v1.14.0-r3/dullahan-1.14.0.202408091638_118.4.1_g3dd6078_chromium-118.0.5993.54-darwin64-10322607516.tar.zst
+ https://github.com/secondlife/dullahan/releases/download/v1.21.0-CEF_139.0.28/dullahan-1.21.0.202508272158_139.0.28_g55ab8a8_chromium-139.0.7258.139-darwin64-17279703032.tar.zst
name
darwin64
@@ -486,18 +478,28 @@
archive
hash
- 4124c79d8b0e319877ffa4c12581d5c1318b4d93
+ 9d5af766a87052808e4062978504e9af124fb558
hash_algorithm
sha1
url
- https://github.com/secondlife/dullahan/releases/download/v1.14.0-r3/dullahan-1.14.0.202408091639_118.4.1_g3dd6078_chromium-118.0.5993.54-windows64-10322607516.tar.zst
+ https://github.com/secondlife/dullahan/releases/download/v1.21.0-CEF_139.0.28/dullahan-1.21.0.202508272159_139.0.28_g55ab8a8_chromium-139.0.7258.139-windows64-17279703032.tar.zst
name
windows64
+ license
+ MPL
+ license_file
+ LICENSES/LICENSE.txt
+ copyright
+ Copyright (c) 2017, Linden Research, Inc.
version
- 1.14.0.202408091639_118.4.1_g3dd6078_chromium-118.0.5993.54
+ 1.21.0.202508272158_139.0.28_g55ab8a8_chromium-139.0.7258.139
+ name
+ dullahan
+ description
+ A headless browser SDK that uses the Chromium Embedded Framework (CEF). It is designed to make it easier to write applications that render modern web content directly to a memory buffer, inject synthesized mouse and keyboard events as well as interact with web based features like JavaScript or cookies.
emoji_shortcodes
@@ -542,11 +544,11 @@
archive
hash
- 8cc4f38fd809d9ff5d8ca617d7e068eb236f4162
+ e0ba69946f2203c03faf89c1f6d5bbc48d88d2a9
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-expat/releases/download/v2.6.2-r5/expat-2.6.2-r5-darwin64-10337781902.tar.zst
+ https://github.com/secondlife/3p-expat/releases/download/v2.6.4-r1/expat-2.6.4-r1-darwin64-11943227858.tar.zst
name
darwin64
@@ -556,11 +558,11 @@
archive
hash
- d7f3bbfd65fce365c3cd5be9ab72072580408dec
+ 13483477c1f8b4bad9055fba561c64137453c3da
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-expat/releases/download/v2.6.2-r5/expat-2.6.2-r5-linux64-10337781902.tar.zst
+ https://github.com/secondlife/3p-expat/releases/download/v2.6.4-r1/expat-2.6.4-r1-linux64-11943227858.tar.zst
name
linux64
@@ -570,11 +572,11 @@
archive
hash
- f11d91205bb753d7389a73e629627b200219c62f
+ 542af7d8bb8de3297c80c23a771bbcb513a630b7
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-expat/releases/download/v2.6.2-r5/expat-2.6.2-r5-windows64-10337781902.tar.zst
+ https://github.com/secondlife/3p-expat/releases/download/v2.6.4-r1/expat-2.6.4-r1-windows64-11943227858.tar.zst
name
windows64
@@ -587,7 +589,7 @@
copyright
Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper - Copyright (c) 2001-2022 Expat maintainers.
version
- 2.6.2-r5
+ 2.6.4-r1
name
expat
description
@@ -625,16 +627,6 @@
freetype
- copyright
- Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg.
- description
- Font rendering library
- license
- FreeType
- license_file
- LICENSES/freetype.txt
- name
- freetype
platforms
darwin64
@@ -642,11 +634,11 @@
archive
hash
- 51ad743c8943602913eedd2b6e2309abf46849d8
+ 5e6c7b9aaf73d90d7feab846a4024193c48eff6c
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-cb2e120/freetype-2.13.3-cb2e120-darwin64-10475886095.tar.zst
+ https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-darwin64-13259804885.tar.zst
name
darwin64
@@ -656,11 +648,11 @@
archive
hash
- bc27e272e004dc2fc573550e8c1cd8b4ad07f5b2
+ a9a3c371958e64a49b07d7be8f59218dfd6b0352
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-cb2e120/freetype-2.13.3-cb2e120-linux64-10475886095.tar.zst
+ https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-linux64-13259804885.tar.zst
name
linux64
@@ -670,18 +662,28 @@
archive
hash
- 01971b998122a17c97e3616c428cc77077a0c39a
+ ad7fbc4a01607ec43d86035a49dadd43d6f2a4e5
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-cb2e120/freetype-2.13.3-cb2e120-windows64-10475886095.tar.zst
+ https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-windows64-13259804885.tar.zst
name
windows64
+ license
+ FreeType
+ license_file
+ LICENSES/freetype.txt
+ copyright
+ Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg.
version
- 2.13.3-cb2e120
+ 2.13.3-r3
+ name
+ freetype
+ description
+ Font rendering library
glext
@@ -916,11 +918,11 @@
archive
hash
- f271809c0d4244128fb52a71226a4d7674e14e0a
+ b05374300cdd40c381614f2ee4497de340eda991
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-9165e47/jpegencoderbasic-1.0-darwin64-9165e47.tar.zst
+ https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-790015a/jpegencoderbasic-1.0-darwin64-790015a.tar.zst
name
darwin64
@@ -930,23 +932,25 @@
archive
hash
- 35d6a617444fde9c8a5e998ef29dc43b95747637
+ 23daab838f4b8f92e5dc1a2f6c568cb7b0cb43b7
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-9165e47/jpegencoderbasic-1.0-linux64-9165e47.tar.zst
+ https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-790015a/jpegencoderbasic-1.0-linux64-790015a.tar.zst
+ name
+ linux64
windows64
archive
hash
- 8ec22e9fc8734ba3d1826f4b88171a6017cc8676
+ 23e8ba22aadf88d249a21844bfcdd01138c05937
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-9165e47/jpegencoderbasic-1.0-windows64-9165e47.tar.zst
+ https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-790015a/jpegencoderbasic-1.0-windows64-790015a.tar.zst
name
windows64
@@ -972,11 +976,11 @@
archive
hash
- 34cf4fdbbc999e67b0528f7ca3c7f31f35267ecf
+ 10f14875ce5c7f5028217c8b7468733190fd333d
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libjpeg-turbo/releases/download/v3.0.3-r2/libjpeg_turbo-3.0.3-r2-windows64-10341191820.tar.zst
+ https://github.com/secondlife/3p-libjpeg-turbo/releases/download/v3.0.4-r1/libjpeg_turbo-3.0.4-r1-windows64-11968659895.tar.zst
name
windows64
@@ -986,11 +990,11 @@
archive
hash
- 5ff05a0e5ed0aba1514b84d3c2edaf70c18738b5
+ d3b1b0fde28c8cf0c33fed167dba87bba5c6cc64
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libjpeg-turbo/releases/download/v3.0.3-r2/libjpeg_turbo-3.0.3-r2-linux64-10341191820.tar.zst
+ https://github.com/secondlife/3p-libjpeg-turbo/releases/download/v3.0.4-r1/libjpeg_turbo-3.0.4-r1-linux64-11968659895.tar.zst
name
linux64
@@ -1000,11 +1004,11 @@
archive
hash
- 7c38eabc050b4a6bdb183a1d7a38da885341049c
+ 79e78cbaaec9a99c0ae4a5cdd4a98535c8fa3c6d
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libjpeg-turbo/releases/download/v3.0.3-r2/libjpeg_turbo-3.0.3-r2-darwin64-10341191820.tar.zst
+ https://github.com/secondlife/3p-libjpeg-turbo/releases/download/v3.0.4-r1/libjpeg_turbo-3.0.4-r1-darwin64-11968659895.tar.zst
name
darwin64
@@ -1017,7 +1021,7 @@
copyright
Copyright (C)2009-2024 D. R. Commander. All Rights Reserved. Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
version
- 3.0.3-r2
+ 3.0.4-r1
name
libjpeg-turbo
canonical_repo
@@ -1036,11 +1040,11 @@
creds
github
hash
- ad72fa1d103df777906f0d98f3e882b9916aeada
+ da318f0813e4126d90e35b22a8dce235e908707a
hash_algorithm
sha1
url
- https://api.github.com/repos/secondlife/3p-kdu/releases/assets/136774118
+ https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381808
name
darwin64
@@ -1052,11 +1056,11 @@
creds
github
hash
- e46e4ac93a237b5c4a14183766f76ba5d58935a2
+ 1ba58cf884726dfdf02a7662d52f1befe3f16d44
hash_algorithm
sha1
url
- https://api.github.com/repos/secondlife/3p-kdu/releases/assets/136774125
+ https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381812
name
linux64
@@ -1068,11 +1072,11 @@
creds
github
hash
- bb37557f78c72b26580a521f8b8dabfa1b34e6e6
+ e8d693089b9ecd15b6644f13ada7ae7c317944df
hash_algorithm
sha1
url
- https://api.github.com/repos/secondlife/3p-kdu/releases/assets/136774126
+ https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381814
name
windows64
@@ -1084,11 +1088,11 @@
creds
github
hash
- 711b82f9f588d3a125af7dcd8c81f93d9c343a7d
+ 85e294becce8b2ac5d2e5e052b0e21ff865d1108
hash_algorithm
sha1
url
- https://api.github.com/repos/secondlife/3p-kdu/releases/assets/136774121
+ https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381806
name
linux
@@ -1101,7 +1105,7 @@
copyright
Kakadu software
version
- 7.10.4.4b9ec5f
+ 8.4.1.11976899217
name
kdu
description
@@ -1116,11 +1120,11 @@
archive
hash
- e71ae7a645603fe967a69aa5beb5b3009185e177
+ 91acd05f450162b07ca2f68094778c483d28128d
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libhunspell/releases/download/v1.7.2-r1/libhunspell-1.7.2.10207243663-darwin64-10207243663.tar.zst
+ https://github.com/secondlife/3p-libhunspell/releases/download/v1.7.2-r2/libhunspell-1.7.2.11968900321-darwin64-11968900321.tar.zst
name
darwin64
@@ -1130,11 +1134,11 @@
archive
hash
- 275ffb7f60064d8008aed8406f80f34229f651fc
+ 10e5b5d793c3c5cb5335dea89734302bda5a9f59
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libhunspell/releases/download/v1.7.2-r1/libhunspell-1.7.2.10207243663-linux64-10207243663.tar.zst
+ https://github.com/secondlife/3p-libhunspell/releases/download/v1.7.2-r2/libhunspell-1.7.2.11968900321-linux64-11968900321.tar.zst
name
linux64
@@ -1144,11 +1148,11 @@
archive
hash
- 89ff24e93eaeca7949ccdb5cc368f938f5b1f307
+ 0f7b9c46dc4e81a6296e4836467f5fe52aa5761d
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libhunspell/releases/download/v1.7.2-r1/libhunspell-1.7.2.10207243663-windows64-10207243663.tar.zst
+ https://github.com/secondlife/3p-libhunspell/releases/download/v1.7.2-r2/libhunspell-1.7.2.11968900321-windows64-11968900321.tar.zst
name
windows64
@@ -1161,7 +1165,7 @@
copyright
LGPL 2.1
version
- 1.7.2.10207243663
+ 1.7.2.11968900321
name
libhunspell
description
@@ -1176,11 +1180,11 @@
archive
hash
- e3dd320c90e67e0c80caf4d4df23257b0196dfb6
+ d1638886671b31935ea7e3c824e015ea1a45b12e
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libndofdev/releases/download/v0.1.8e9edc7/libndofdev-0.1.8e9edc7-darwin64-8e9edc7.tar.zst
+ https://github.com/secondlife/3p-libndofdev/releases/download/v0.1.a0b7d99/libndofdev-0.1.11968678219-darwin64-11968678219.tar.zst
name
darwin64
@@ -1190,11 +1194,11 @@
archive
hash
- ae9d554e8839f42230b8ed6c850445d54654a38f
+ 7b3e504885c4c0cc75db298e682f408c4f2e95f7
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libndofdev/releases/download/v0.1.8e9edc7/libndofdev-0.1.8e9edc7-windows64-8e9edc7.tar.zst
+ https://github.com/secondlife/3p-libndofdev/releases/download/v0.1.a0b7d99/libndofdev-0.1.11968678219-windows64-11968678219.tar.zst
name
windows64
@@ -1207,7 +1211,7 @@
copyright
Copyright (c) 2007, 3Dconnexion, Inc. - All rights reserved.
version
- 0.1.8e9edc7
+ 0.1.11968678219
name
libndofdev
description
@@ -1222,11 +1226,11 @@
archive
hash
- 6fe46ed1e2e40616abdacf7115e510645d5f62e7
+ a453355ee032f79aea4142218a957085a22c7656
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libpng/releases/download/v1.6.43-r2/libpng-1.6.43-r2-darwin64-10329429325.tar.zst
+ https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-darwin64-13246065198.tar.zst
name
darwin64
@@ -1236,11 +1240,11 @@
archive
hash
- b54a4710d9c3ddfa044e1d29f9c38974e9fc645d
+ 75c7608646c9f5b99b1a9e3946326e2804a304d7
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libpng/releases/download/v1.6.43-r2/libpng-1.6.43-r2-linux64-10329429325.tar.zst
+ https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-linux64-13246065198.tar.zst
name
linux64
@@ -1250,11 +1254,11 @@
archive
hash
- eddb96c73c8916bf71eaa5d0edb812d20e72c255
+ 09af51774c4ee7c03fe67a87dfc52e846aa625ea
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libpng/releases/download/v1.6.43-r2/libpng-1.6.43-r2-windows64-10329429325.tar.zst
+ https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-windows64-13246065198.tar.zst
name
windows64
@@ -1267,7 +1271,7 @@
copyright
Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson
version
- 1.6.43-r2
+ 1.6.44-r2
name
libpng
description
@@ -1312,11 +1316,11 @@
archive
hash
- b2bf9adc84841b6fcf48d4c00787b221607cdea3
+ 372c92936d940b1cfb5ba34310691d4bb435c161
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libxml2/releases/download/v2.13.3-r1/libxml2-2.13.3-r1-darwin64-10329675166.tar.zst
+ https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-darwin64-13246071272.tar.zst
name
darwin64
@@ -1326,11 +1330,11 @@
archive
hash
- 6ab8108ea0a42e0bd462568c495e5ce5c4cdc0ff
+ ba6fbc34112b1acab1c8615dcd13de983f3678d3
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libxml2/releases/download/v2.13.3-r1/libxml2-2.13.3-r1-linux64-10329675166.tar.zst
+ https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-linux64-13246071272.tar.zst
name
linux64
@@ -1340,11 +1344,11 @@
archive
hash
- 5181bd267de3ad4466227f91c7e2cbed7e8b85d9
+ 71968c4b621636e8ae0c5680e631f4aa67561944
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-libxml2/releases/download/v2.13.3-r1/libxml2-2.13.3-r1-windows64-10329675166.tar.zst
+ https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-windows64-13246071272.tar.zst
name
windows64
@@ -1357,7 +1361,7 @@
copyright
Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved.
version
- 2.13.3-r1
+ 2.13.5-r2
name
libxml2
description
@@ -1395,15 +1399,6 @@
llca
- copyright
- Copyright (c) 2016, Linden Research, Inc.; data provided by the Mozilla NSS Project.
-
- license
- mit
- license_file
- LICENSES/ca-license.txt
- name
- llca
platforms
common
@@ -1421,8 +1416,17 @@
common
+ license
+ mit
+ license_file
+ LICENSES/ca-license.txt
+ copyright
+ Copyright (c) 2016, Linden Research, Inc.; data provided by the Mozilla NSS Project.
+
version
202407221423.0
+ name
+ llca
llphysicsextensions_source
@@ -1435,11 +1439,11 @@
creds
github
hash
- 9e59c93c7110e87b4ff3db330f11a23c50e5000f
+ 7facda95e2f00c260513f3d4db42588fa8ba703c
hash_algorithm
sha1
url
- https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/178910560
+ https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289774
name
darwin64
@@ -1451,11 +1455,11 @@
creds
github
hash
- 7ed994db5bafa9a7ad09a1b53da850a84715c65e
+ 01d08f13c7bc8d1b95b0330fa6833b7d8274e4d0
hash_algorithm
sha1
url
- https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/178910561
+ https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289775
name
linux64
@@ -1467,11 +1471,11 @@
creds
github
hash
- 66824c02e0e5eabbfbe37bfb173360195f89697c
+ 6d00345c7d3471bc5f7c1218e014dd0f1a2c069b
hash_algorithm
sha1
url
- https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/178910562
+ https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289778
name
windows64
@@ -1484,7 +1488,7 @@
copyright
Copyright (c) 2010, Linden Research, Inc.
version
- 1.0.66e6919
+ 1.0.11137145495
name
llphysicsextensions_source
@@ -1627,42 +1631,42 @@
archive
hash
- d79631d845e2b5e4a9e6f6b660310795fd49023e
+ 874a7d2bc843554aa4facd03b3a6d681f2b5150c
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-meshoptimizer/releases/download/v210-r2/meshoptimizer-210.0.0-r2-darwin64-10341021290.tar.zst
+ https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-darwin64-11968851109.tar.zst
name
darwin64
- windows64
+ linux64
archive
hash
- 024ce689a6f13e66d0c7e431ac34071434e2365a
+ 31a537f1a3d38ef85443214315111dd56a534d9a
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-meshoptimizer/releases/download/v210-r2/meshoptimizer-210.0.0-r2-windows64-10341021290.tar.zst
+ https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-linux64-11968851109.tar.zst
name
- windows64
+ linux64
- linux64
+ windows64
archive
hash
- c947107c0aca46e94e22f66328a3cbbd01d99b36
+ 6fd727a9ccb3e7a6c6b4ffef8179e266c032eb3e
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-meshoptimizer/releases/download/v210-r2/meshoptimizer-210.0.0-r2-linux64-10341021290.tar.zst
+ https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-windows64-11968851109.tar.zst
name
- linux64
+ windows64
license
@@ -1672,7 +1676,7 @@
copyright
Copyright (c) 2016-2021 Arseny Kapoulkine
version
- 210.0.0-r2
+ 220.0.0-r1
name
meshoptimizer
canonical_repo
@@ -1751,11 +1755,11 @@
archive
hash
- 6bedaa9d770ef0ae6147f49a26fc3209fde9cb80
+ b628d088e1f368a0cd51a6b66292aaf9a025e2d4
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r1/minizip_ng-4.0.7-r1-darwin64-10324657515.tar.zst
+ https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-darwin64-13246046977.tar.zst
name
darwin64
@@ -1765,11 +1769,11 @@
archive
hash
- ce2c91b8c4f89af252ce1b6a96af6985fe54f509
+ 492ce9175b730d43df63821c4481685e035af623
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r1/minizip_ng-4.0.7-r1-linux64-10324657515.tar.zst
+ https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-linux64-13246046977.tar.zst
name
linux64
@@ -1779,11 +1783,11 @@
archive
hash
- 9cee9d85f9a7c6fb051125775f0122a926da5cc9
+ 58773e707ff3490822b7b8217d7729ade2186632
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r1/minizip_ng-4.0.7-r1-windows64-10324657515.tar.zst
+ https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-windows64-13246046977.tar.zst
name
windows64
@@ -1796,7 +1800,7 @@
copyright
This project uses the zlib license. Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
version
- 4.0.7-r1
+ 4.0.7-r3
name
minizip-ng
canonical_repo
@@ -1869,11 +1873,11 @@
archive
hash
- 3f3374a5d97803bf78acf20847c2900c7d68ce2b
+ f45ea5a42d6a419f9b605dd3f976fbcb3850d736
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-nghttp2/releases/download/v1.62.1/nghttp2-1.62.1-darwin64-10329456052.tar.zst
+ https://github.com/secondlife/3p-nghttp2/releases/download/v1.64.0-r2/nghttp2-1.64.0-r1-darwin64-13184359419.tar.zst
name
darwin64
@@ -1883,11 +1887,11 @@
archive
hash
- bd9c211f9f53c04821f0ab0e1268a691926331b6
+ c6e450fa41f24f1b4103d2006d706595f2a36c59
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-nghttp2/releases/download/v1.62.1/nghttp2-1.62.1-linux64-10329456052.tar.zst
+ https://github.com/secondlife/3p-nghttp2/releases/download/v1.64.0-r2/nghttp2-1.64.0-r1-linux64-13184359419.tar.zst
name
linux64
@@ -1897,11 +1901,11 @@
archive
hash
- c23e25a7c47f5233f543a90f1a9ccf4da9282379
+ 3bd92f892e155104740570fe244ea4dbb0b57d4b
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-nghttp2/releases/download/v1.62.1/nghttp2-1.62.1-windows64-10329456052.tar.zst
+ https://github.com/secondlife/3p-nghttp2/releases/download/v1.64.0-r2/nghttp2-1.64.0-r1-windows64-13184359419.tar.zst
name
windows64
@@ -1915,7 +1919,7 @@
Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa
Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
version
- 1.62.1
+ 1.64.0-r1
name
nghttp2
description
@@ -1964,11 +1968,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 3abb5d21655aeca9d6a4de37704e8475821c28d9
+ 68657c5c161c3fe8ff64eac3787172fcb06da972
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.5-1.3.7-r1/ogg_vorbis-1.3.5-1.3.7.10341271136-darwin64-10341271136.tar.zst
+ https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.5-1.3.7-r2/ogg_vorbis-1.3.5-1.3.7.11968798109-darwin64-11968798109.tar.zst
name
darwin64
@@ -1978,11 +1982,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- d89dff615c51b46ebdb3d42ac6bd9e0faae5ddf1
+ 9a6ffad7b4186a158c019c5a5a5d7b8badb441da
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.5-1.3.7-r1/ogg_vorbis-1.3.5-1.3.7.10341271136-linux64-10341271136.tar.zst
+ https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.5-1.3.7-r2/ogg_vorbis-1.3.5-1.3.7.11968798109-linux64-11968798109.tar.zst
name
linux64
@@ -1992,11 +1996,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 0dc0f5334d1c882d5d7bce6d2cfaecf2f7ab1ae6
+ 5f4cbb928ebfe774a9c07d3f2c255fd38bd6b4d6
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.5-1.3.7-r1/ogg_vorbis-1.3.5-1.3.7.10341271136-windows64-10341271136.tar.zst
+ https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.5-1.3.7-r2/ogg_vorbis-1.3.5-1.3.7.11968798109-windows64-11968798109.tar.zst
name
windows64
@@ -2009,7 +2013,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
copyright
Copyright (c) 2002, Xiph.org Foundation
version
- 1.3.5-1.3.7.10341271136
+ 1.3.5-1.3.7.11968798109
name
ogg_vorbis
description
@@ -2024,7 +2028,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
copyright
Copyright (c) 2008, Jan Ciger (jan.ciger (at) gmail.com)
version
- 0.3
+ 0.14.11968684513
name
open-libndofdev
description
@@ -2084,7 +2088,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
copyright
Copyright (C) 1999-2007 by authors.
version
- 1.23.1
+ 1.24.2-r1
name
openal
description
@@ -2099,11 +2103,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 76444e37be0cfccdbb5921370ba150ded2bf3c59
+ 94a72c6ddbfb23796ce913c55bc47c128542a582
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r1/openjpeg-2.5.2.10604495243-darwin64-10604495243.tar.zst
+ https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.3-r1/openjpeg-2.5.3.15590356935-darwin64-15590356935.tar.zst
name
darwin64
@@ -2113,11 +2117,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 6bd289a9c4564b80369ce40ecbb24a213c2732ff
+ 751172af405f4a47a3aebb37729d62229cab6c07
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r1/openjpeg-2.5.2.10604495243-linux64-10604495243.tar.zst
+ https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.3-r1/openjpeg-2.5.3.15590356935-linux64-15590356935.tar.zst
name
linux64
@@ -2127,11 +2131,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 5e6e0180adc01e07438cb98daec96543b5d85019
+ 8aab9cf250dfee252386e1c79b5205e6d3b3e19e
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r1/openjpeg-2.5.2.10604495243-windows64-10604495243.tar.zst
+ https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.3-r1/openjpeg-2.5.3.15590356935-windows64-15590356935.tar.zst
name
windows64
@@ -2144,7 +2148,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
copyright
Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium; Copyright (c) 2002-2007, Professor Benoit Macq; Copyright (c) 2001-2003, David Janssens; Copyright (c) 2002-2003, Yannick Verschueren; Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe; Copyright (c) 2005, Herve Drolon, FreeImage Team; Copyright (c) 2006-2007, Parvatha Elangovan; Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr>; Copyright (c) 2010-2011, Kaori Hagihara; Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France; Copyright (c) 2012, CS Systemes d'Information, France;
version
- 2.5.0.ea12248
+ 2.5.3.15590356935
name
openjpeg
description
@@ -2159,11 +2163,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- a20277991043a4a00fb8280a27a41fbd87c4b840
+ 157193699127ac5056c5fc1a410f9c98d39731e2
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r1/openssl-1.1.1w-darwin64-10329796904.tar.zst
+ https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-darwin64-13246054022.tar.zst
name
darwin64
@@ -2173,11 +2177,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 0f2cd519431b11cacf85971c66c49e5b4d26c56f
+ 2e29c127dbd002d64ae55bc000f8b6ed0249fad7
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r1/openssl-1.1.1w-linux64-10329796904.tar.zst
+ https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-linux64-13246054022.tar.zst
name
linux64
@@ -2187,11 +2191,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 5e396eedf1492d18126b7281367123c1d64b89aa
+ ae9ced89051e03a99628c99b9ac78530fdea1e5a
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r1/openssl-1.1.1w-windows64-10329796904.tar.zst
+ https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-windows64-13246054022.tar.zst
name
windows64
@@ -2204,7 +2208,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
copyright
Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved; Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
version
- 1.1.1w
+ 1.1.1w-r3
name
openssl
description
@@ -2330,16 +2334,42 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
description
Vivox SDK components
- threejs
+ sse2neon
- copyright
- Copyright © 2010-2021 three.js authors
+ platforms
+
+ common
+
+ archive
+
+ hash
+ e51fb1d24836d897ce90b8a72010635915b959d6
+ hash_algorithm
+ sha1
+ url
+ https://github.com/secondlife/3p-sse2neon/releases/download/v1.8.0/sse2neon-1.8.0-common-17657389472.tar.zst
+
+ name
+ common
+
+
license
MIT
license_file
- LICENSES/THREEJS_LICENSE.txt
+ LICENSES/sse2neon.txt
+ copyright
+ Copyright (c) 2015-2024 SSE2NEON Contributors.
+ version
+ 1.8.0
name
- threejs
+ sse2neon
+ canonical_repo
+ https://github.com/secondlife/3p-sse2neon
+ description
+ A translator from Intel SSE intrinsics to Arm/Aarch64 NEON implementation
+
+ threejs
+
platforms
common
@@ -2357,8 +2387,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
common
+ license
+ MIT
+ license_file
+ LICENSES/THREEJS_LICENSE.txt
+ copyright
+ Copyright © 2010-2021 three.js authors
version
0.132.2
+ name
+ threejs
tinygltf
@@ -2407,11 +2445,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 226225ec049826c35adc5e897e0398ed64d4bedb
+ 0c3d01b7e9e39c23f0f40c56a1a04d1fba08ead0
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-tracy/releases/download/v0.11.0%2Br1/tracy-v0.11.0.10376230034-darwin64-10376230034.tar.zst
+ https://github.com/secondlife/3p-tracy/releases/download/v0.11.1-r1/tracy-v0.11.1.11706699176-darwin64-11706699176.tar.zst
name
darwin64
@@ -2421,11 +2459,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 8c5429d1a1486f40cf7e5e88a232222d1fa4f78e
+ b46cef5646a8d0471ab6256fe5119220fa238772
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-tracy/releases/download/v0.11.0%2Br1/tracy-v0.11.0.10376230034-windows64-10376230034.tar.zst
+ https://github.com/secondlife/3p-tracy/releases/download/v0.11.1-r1/tracy-v0.11.1.11706699176-windows64-11706699176.tar.zst
name
windows64
@@ -2435,11 +2473,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- ed0664a009aba1dcf1246d845839f524e857162e
+ beab04c9ea6036b1851a485b65c66cf6a38f0be4
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-tracy/releases/download/v0.11.0%2Br1/tracy-v0.11.0.10376230034-linux64-10376230034.tar.zst
+ https://github.com/secondlife/3p-tracy/releases/download/v0.11.1-r1/tracy-v0.11.1.11706699176-linux64-11706699176.tar.zst
name
linux64
@@ -2452,7 +2490,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
copyright
Copyright (c) 2017-2024, Bartosz Taudul (wolf@nereid.pl)
version
- v0.11.0.10376230034
+ v0.11.1.11706699176
name
tracy
canonical_repo
@@ -2594,14 +2632,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
vlc-bin
- copyright
- Copyright (C) 1998-2016 VLC authors and VideoLAN
- license
- GPL2
- license_file
- LICENSES/vlc.txt
- name
- vlc-bin
platforms
darwin64
@@ -2609,11 +2639,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- f13c82042ef8311e57dd75a3b2bda02d70f711b5
+ 6d72afd5cc21446c65899615909b1f09f155585d
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.21.e60ee26/vlc_bin-3.0.21.10218721728-darwin64-10218721728.tar.zst
+ https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.21.296d9f4/vlc_bin-3.0.21.11968962952-darwin64-11968962952.tar.zst
name
darwin64
@@ -2623,18 +2653,26 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- bd995441c1a229ed1432ddd837d7d1663b8c5548
+ f986e6e93acf8a32a8be5b638f0bd0e2e07d7507
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.21.e60ee26/vlc_bin-3.0.21.10218721728-windows64-10218721728.tar.zst
+ https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.21.296d9f4/vlc_bin-3.0.21.11968962952-windows64-11968962952.tar.zst
name
windows64
+ license
+ GPL2
+ license_file
+ LICENSES/vlc.txt
+ copyright
+ Copyright (C) 1998-2016 VLC authors and VideoLAN
version
- 3.0.21.10218721728
+ 3.0.21.11968962952
+ name
+ vlc-bin
vulkan_gltf
@@ -2679,11 +2717,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 3570b6442d472cd97bad8622c2ec2571d72218a0
+ 43c5f93517794aeade550e4266b959d1f0cfcb7f
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.72-test/webrtc-m114.5735.08.72-test.10444682919-darwin64-10444682919.tar.zst
+ https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-darwin64-17630578914.tar.zst
name
darwin64
@@ -2693,11 +2731,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- eadf6aa99313940ded11801d42c11375669f1628
+ efc5b176d878cfc16b8f82445d82ddb96815b6ab
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.72-test/webrtc-m114.5735.08.72-test.10444682919-linux64-10444682919.tar.zst
+ https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-linux64-17630578914.tar.zst
name
linux64
@@ -2707,11 +2745,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 0081fd35290adbc8e66dd366535fb6cd8a966f1e
+ 1e36f100de32c7c71325497a672fb1659b3f206d
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.72-test/webrtc-m114.5735.08.72-test.10444682919-windows64-10444682919.tar.zst
+ https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-windows64-17630578914.tar.zst
name
windows64
@@ -2724,7 +2762,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
copyright
Copyright (c) 2011, The WebRTC project authors. All rights reserved.
version
- m114.5735.08.72-test.10444682919
+ m137.7151.04.20-universal.17630578914
name
webrtc
vcs_branch
@@ -2777,11 +2815,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 3a6593c71c59ace76d1349483759fcde4b719a76
+ e363e3b889c52fda7601d7aeaa9832307034651e
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.1-r2/zlib_ng-2.2.1-r2-darwin64-10324415171.tar.zst
+ https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-darwin64-13183604450.tar.zst
name
darwin64
@@ -2791,11 +2829,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- fbadeb0b8c771cb06c0055c9fab6d40c6764dacd
+ 3cdd52f7fb3691789d50f0b40ed6f5642321ff32
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.1-r2/zlib_ng-2.2.1-r2-linux64-10324415171.tar.zst
+ https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-linux64-13183604450.tar.zst
name
linux64
@@ -2805,11 +2843,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
hash
- 0094031715662be626f5106ff6c814f4fc3dacfa
+ e802a28139328bb2421ad39e13d996d350d8106d
hash_algorithm
sha1
url
- https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.1-r2/zlib_ng-2.2.1-r2-windows64-10324415171.tar.zst
+ https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-windows64-13183604450.tar.zst
name
windows64
@@ -2822,7 +2860,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
copyright
Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
version
- 2.2.1-r2
+ 2.2.3-dev0.g8aa13e3.d20250206
name
zlib-ng
canonical_repo
@@ -2832,16 +2870,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
tinyexr
- copyright
- Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors.
- description
- tinyexr import library
- license
- 3-clause BSD
- license_file
- LICENSES/tinyexr_license.txt
- name
- tinyexr
platforms
common
@@ -2859,16 +2887,26 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
common
- source_type
- git
+ license
+ 3-clause BSD
+ license_file
+ LICENSES/tinyexr_license.txt
+ copyright
+ Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors.
+ version
+ 1.0.9-5e8947c
+ name
+ tinyexr
vcs_branch
dependabot/github_actions/secondlife/action-autobuild-4
vcs_revision
4dc4d1d90d82a22843e2adf5130f9ecb5ee5769e
vcs_url
https://github.com/secondlife/3p-tinyexr
- version
- 1.0.9-5e8947c
+ description
+ tinyexr import library
+ source_type
+ git
discord_sdk
@@ -2928,6 +2966,46 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
description
Discord Social SDK
+ websocketpp
+
+ platforms
+
+ common
+
+ archive
+
+ hash
+ 9b02492bbc5effd8afca1bb7c95110d43a8f75da
+ hash_algorithm
+ sha1
+ url
+ https://github.com/secondlife/3p-websocketpp/releases/download/v0.8.2/websocketpp-0.8.2.17134644226-common-17134644226.tar.zst
+
+ name
+ common
+
+
+ license
+ websocketpp
+ license_file
+ LICENSES/websocketpp.txt
+ copyright
+ Copyright (c) 2014, Peter Thorson
+ version
+ 0.8.2.17134644226
+ name
+ websocketpp
+ vcs_branch
+ refs/tags/v0.8.2
+ vcs_revision
+ bdcf1453101976fc4dc26a62c87bc98c12e9c6dc
+ vcs_url
+ git://github.com/secondlife/3p-websocketpp.git
+ canonical_repo
+ https://github.com/secondlife/3p-websocketpp
+ description
+ WebSocket++ is a C++ header only library for interacting with WebSocket servers and clients.
+
package_description
@@ -3149,7 +3227,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
build_directory
- build-darwin-x86_64
+ build-darwin-universal
name
darwin64
diff --git a/build.sh b/build.sh
index eb81ff319a4..36e332cf42c 100755
--- a/build.sh
+++ b/build.sh
@@ -40,7 +40,7 @@ retry_cmd()
build_dir_Darwin()
{
- echo build-darwin-x86_64
+ echo build-darwin-universal
}
build_dir_Linux()
@@ -158,6 +158,7 @@ pre_build()
if [[ "$arch" == "Darwin" ]]
then
+ HAVOK=OFF
SIGNING=("-DENABLE_SIGNING:BOOL=YES" \
"-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.")
fi
@@ -387,7 +388,7 @@ do
if `cat "$build_dir/build_ok"`
then
case "$variant" in
- Release)
+ Release*)
if [ -r "$build_dir/autobuild-package.xml" ]
then
begin_section "Autobuild metadata"
diff --git a/doc/external-editor-json-rpc.md b/doc/external-editor-json-rpc.md
new file mode 100644
index 00000000000..b8c7fa69e32
--- /dev/null
+++ b/doc/external-editor-json-rpc.md
@@ -0,0 +1,464 @@
+# Viewer to External Editor JSON-RPC
Message Interfaces Documentation
+
+This document describes all the message interfaces defined in for WebSocket communication between the Second Life viewer and an external editor such as a VSCode extension.
+
+## Table of Contents
+
+- [Usage Flow](#usage-flow)
+- [JSON-RPC Method Summary](#json-rpc-method-summary)
+- [Session Management Interfaces](#session-management-interfaces)
+ - [SessionHandshake](#sessionhandshake)
+ - [SessionHandshakeResponse](#sessionhandshakeresponse)
+ - [Session OK](#session-ok)
+ - [SessionDisconnect](#sessiondisconnect)
+- [Language and Syntax Interfaces](#language-and-syntax-interfaces)
+ - [SyntaxChange](#syntaxchange)
+ - [Language Syntax ID Request](#language-syntax-id-request)
+ - [Language Syntax Request](#language-syntax-request)
+- [Script Subscription Interfaces](#script-subscription-interfaces)
+ - [ScriptSubscribe](#scriptsubscribe)
+ - [ScriptSubscribeResponse](#scriptsubscriberesponse)
+ - [ScriptUnsubscribe](#scriptunsubscribe)
+- [Compilation Interfaces](#compilation-interfaces)
+ - [CompilationError](#compilationerror)
+ - [CompilationResult](#compilationresult)
+- [Runtime Event Interfaces](#runtime-event-interfaces)
+ - [RuntimeDebug](#runtimedebug)
+ - [RuntimeError](#runtimeerror)
+- [Handler and Configuration Interfaces](#handler-and-configuration-interfaces)
+ - [WebSocketHandlers](#websockethandlers)
+ - [ClientInfo](#clientinfo)
+
+## Usage Flow
+
+1. **Connection Establishment:**
+
+ - Viewer sends `session.handshake` notification with `SessionHandshake` data
+ - Extension responds with `SessionHandshakeResponse`
+ - Viewer confirms with `session.ok` notification
+
+2. **Language Information Exchange:**
+
+ - Extension makes `language.syntax.id` call to get current syntax version
+ - Extension makes `language.syntax` calls with different `kind` parameters to get specific language data
+ - Viewer responds with `LanguageInfo` data containing the requested information
+
+3. **Script Subscription Management:**
+
+ - Extension makes `script.subscribe` call with `ScriptSubscribe` data to request live synchronization for a script
+ - Viewer responds with `ScriptSubscribeResponse` indicating success or failure
+ - When subscription needs to be terminated, viewer sends `script.unsubscribe` notification with `ScriptUnsubscribe` data
+ - Extension handles unsubscription by cleaning up local script tracking
+
+4. **Runtime Events:**
+
+ - Viewer sends `language.syntax.change` notification with `SyntaxChange` when language changes
+ - Viewer sends `script.compiled` notification with `CompilationResult` after script compilation
+ - Viewer sends `runtime.debug` notification with `RuntimeDebug` for debug messages during script execution
+ - Viewer sends `runtime.error` notification with `RuntimeError` when runtime errors occur
+
+5. **Connection Termination:**
+ - Either side can send `session.disconnect` notification with `SessionDisconnect` data
+ - Connection is closed gracefully
+
+## JSON-RPC Method Summary
+
+| Method | Direction | Type | Interface/Parameters |
+| ------------------------------- | ------------------ | ------------ | -------------------------- |
+| `session.handshake` | Viewer → Extension | Notification | `SessionHandshake` |
+| `session.handshake` (response) | Extension → Viewer | Response | `SessionHandshakeResponse` |
+| `session.ok` | Viewer → Extension | Notification | _(no interface)_ |
+| `session.disconnect` | Bidirectional | Notification | `SessionDisconnect` |
+| `script.subscribe` | Extension → Viewer | Call | `ScriptSubscribe` |
+| `script.subscribe` (response) | Viewer → Extension | Response | `ScriptSubscribeResponse` |
+| `script.unsubscribe` | Viewer → Extension | Notification | `ScriptUnsubscribe` |
+| `language.syntax.id` | Extension → Viewer | Call | _(no parameters)_ |
+| `language.syntax.id` (response) | Viewer → Extension | Response | `{ id: string }` |
+| `language.syntax` | Extension → Viewer | Call | `{ kind: string }` |
+| `language.syntax` (response) | Viewer → Extension | Response | `LanguageInfo` |
+| `language.syntax.change` | Viewer → Extension | Notification | `SyntaxChange` |
+| `script.compiled` | Viewer → Extension | Notification | `CompilationResult` |
+| `runtime.debug` | Viewer → Extension | Notification | `RuntimeDebug` |
+| `runtime.error` | Viewer → Extension | Notification | `RuntimeError` |
+
+## Session Management Interfaces
+
+### SessionHandshake
+
+**JSON-RPC Method:** `session.handshake` (notification from viewer)
+
+The initial handshake message sent by the viewer to establish a connection.
+
+```typescript
+interface SessionHandshake {
+ server_version: "1.0.0";
+ protocol_version: "1.0";
+ viewer_name: string;
+ viewer_version: string;
+ agent_id: string;
+ agent_name: string;
+ challenge?: string;
+ languages: string[];
+ syntax_id: string;
+ features: { [feature: string]: boolean };
+}
+```
+
+**Fields:**
+
+- `server_version`: Fixed version "1.0.0" indicating the server API version
+- `protocol_version`: Fixed version "1.0" for the communication protocol
+- `viewer_name`: Name of the Second Life viewer application
+- `viewer_version`: Version string of the viewer
+- `agent_id`: Unique identifier for the user/agent
+- `agent_name`: Human-readable name of the agent
+- `challenge` (optional): Security challenge string for authentication
+- `languages`: Array of supported scripting languages (e.g., ["lsl", "luau"])
+- `syntax_id`: Current active syntax/language identifier
+- `features`: Dictionary of feature flags indicating viewer capabilities
+
+### SessionHandshakeResponse
+
+**JSON-RPC Method:** Response to `session.handshake`
+
+The response sent by the VS Code extension to complete the handshake.
+
+```typescript
+interface SessionHandshakeResponse {
+ client_name: string;
+ client_version: "1.0";
+ protocol_version: string;
+ challenge_response?: string;
+ languages: string[];
+ features: { [feature: string]: boolean };
+}
+```
+
+**Fields:**
+
+- `client_name`: Name of the client (VS Code extension)
+- `client_version`: Fixed version "1.0" of the client
+- `protocol_version`: Protocol version the client supports
+- `challenge_response` (optional): Response to the security challenge if provided
+- `languages`: Array of languages supported by the client
+- `features`: Dictionary of features supported by the client
+
+### Session OK
+
+**JSON-RPC Method:** `session.ok` (notification from viewer)
+
+Confirmation notification sent by the viewer after successful handshake completion. This interface has no defined structure as it appears to be a simple confirmation message.
+
+### SessionDisconnect
+
+**JSON-RPC Method:** `session.disconnect` (notification, bidirectional)
+
+Message sent when terminating the connection.
+
+```typescript
+interface SessionDisconnect {
+ reason: number;
+ message: string;
+}
+```
+
+**Fields:**
+
+- `reason`: Numeric code indicating the reason for disconnection
+- `message`: Human-readable description of the disconnect reason
+
+## Language and Syntax Interfaces
+
+### SyntaxChange
+
+**JSON-RPC Method:** `language.syntax.change` (notification from viewer)
+
+Notification sent when the active language syntax changes in the viewer.
+
+```typescript
+interface SyntaxChange {
+ id: string;
+}
+```
+
+**Fields:**
+
+- `id`: Identifier for the new syntax/language
+
+### Language Syntax ID Request
+
+**JSON-RPC Method:** `language.syntax.id` (call from extension to viewer)
+
+Requests the current active language syntax identifier from the viewer. This method takes no parameters.
+
+**Response:** Returns an object with an `id` field containing the current syntax identifier.
+
+### Language Syntax Request
+
+**JSON-RPC Method:** `language.syntax` (call from extension to viewer)
+
+Requests detailed syntax information for a specific language kind.
+
+**Parameters:**
+
+```typescript
+{
+ kind: string; // The type of syntax information requested
+}
+```
+
+**Fields:**
+
+- `kind`: The type of syntax information to retrieve (e.g., "functions", "constants", "events", "types.luau")
+
+**Response:** Returns `LanguageInfo` data containing the requested syntax information:
+
+```typescript
+interface LanguageInfo {
+ id: string;
+ lslDefs?: {
+ controls?: any;
+ types?: any;
+ constants?: { [name: string]: ConstantDef };
+ events?: { [name: string]: FunctionDef };
+ functions?: { [name: string]: FunctionDef };
+ };
+ luaDefs?: {
+ modules?: { [name: string]: TypeDef };
+ classes?: { [name: string]: TypeDef };
+ aliases?: { [name: string]: TypeDef };
+ functions?: { [name: string]: FunctionDef };
+ };
+}
+```
+
+**Response Fields:**
+
+- `id`: Version identifier for the language syntax
+- `lslDefs` (optional): LSL-specific language definitions containing:
+ - `controls` (optional): Control flow and language constructs
+ - `types` (optional): LSL type definitions
+ - `constants` (optional): Object containing constant definitions keyed by constant name
+ - `events` (optional): Object containing event definitions keyed by event name
+ - `functions` (optional): Object containing function definitions keyed by function name
+- `luaDefs` (optional): Lua-specific language definitions containing:
+ - `modules` (optional): Module type definitions keyed by module name
+ - `classes` (optional): Class type definitions keyed by class name
+ - `aliases` (optional): Type alias definitions keyed by alias name
+ - `functions` (optional): Function definitions keyed by function name
+
+The specific sections returned depend on the `kind` parameter and the active language context.
+
+## Script Subscription Interfaces
+
+### ScriptSubscribe
+
+**JSON-RPC Method:** `script.subscribe` (call from extension to viewer)
+
+Requests subscription to a script for live synchronization between the editor and viewer.
+
+```typescript
+interface ScriptSubscribe {
+ script_id: string;
+ script_name: string;
+ script_language: string;
+}
+```
+
+**Fields:**
+
+- `script_id`: Unique identifier for the script to subscribe to
+- `script_name`: Display name of the script file
+- `script_language`: Programming language of the script (e.g., "lsl", "luau")
+
+### ScriptSubscribeResponse
+
+**JSON-RPC Method:** Response to `script.subscribe`
+
+Response from the viewer indicating whether script subscription was successful.
+
+```typescript
+interface ScriptSubscribeResponse {
+ script_id: string;
+ success: boolean;
+ status: number;
+ object_id?: string;
+ object_name?: string;
+ item_id?: string;
+ message?: string;
+}
+```
+
+**Fields:**
+
+- `script_id`: The script identifier that was subscribed to
+- `success`: Whether the subscription was successful
+- `status`: Numeric status code indicating the result
+- `object_id` (optional): The in-world ID of the object containing the script
+- `object_name` (optional): The name of the object containing the script.
+- `message` (optional): Additional information about the subscription result
+
+### ScriptUnsubscribe
+
+**JSON-RPC Method:** `script.unsubscribe` (notification from viewer)
+
+Notification sent by the viewer when a script subscription should be terminated.
+
+```typescript
+interface ScriptUnsubscribe {
+ script_id: string;
+}
+```
+
+**Fields:**
+
+- `script_id`: Unique identifier for the script to unsubscribe from
+
+## Compilation Interfaces
+
+### CompilationError
+
+Individual compilation error record.
+
+```typescript
+interface CompilationError {
+ row: number;
+ column: number;
+ level: "ERROR";
+ message: string;
+}
+```
+
+**Fields:**
+
+- `row`: Line number where the error occurred (0-based or 1-based depending on context)
+- `column`: Column position of the error
+- `level`: Severity level (currently only "ERROR" is defined)
+- `message`: Error description
+
+### CompilationResult
+
+**JSON-RPC Method:** `script.compiled` (notification from viewer)
+
+Result of a compilation operation in the viewer.
+
+```typescript
+interface CompilationResult {
+ script_id: string;
+ success: boolean;
+ running: boolean;
+ errors?: CompilationError[];
+}
+```
+
+**Fields:**
+
+- `script_id`: Unique identifier for the script that was compiled
+- `success`: Whether the compilation was successful
+- `running`: Whether the compiled script is currently running
+- `errors` (optional): Array of compilation errors if any occurred
+
+## Runtime Event Interfaces
+
+### RuntimeDebug
+
+**JSON-RPC Method:** `runtime.debug` (notification from viewer)
+
+Debug message notification sent by the viewer during script execution.
+
+```typescript
+interface RuntimeDebug {
+ script_id: string;
+ object_id: string;
+ object_name: string;
+ message: string;
+}
+```
+
+**Fields:**
+
+- `script_id`: Unique identifier for the script generating the debug message
+- `object_id`: Unique identifier for the object containing the script
+- `object_name`: Human-readable name of the object
+- `message`: The debug message content
+
+### RuntimeError
+
+**JSON-RPC Method:** `runtime.error` (notification from viewer)
+
+Runtime error notification sent by the viewer when a script encounters an error during execution.
+
+```typescript
+interface RuntimeError {
+ script_id: string;
+ object_id: string;
+ object_name: string;
+ message: string;
+ error: string;
+ line: number;
+ stack?: string[];
+}
+```
+
+**Fields:**
+
+- `script_id`: Unique identifier for the script that encountered the error
+- `object_id`: Unique identifier for the object containing the script
+- `object_name`: Human-readable name of the object
+- `message`: Error message description
+- `error`: Specific error type or code
+- `line`: Line number where the error occurred
+- `stack` (optional): Stack trace information if available
+
+## Handler and Configuration Interfaces
+
+### WebSocketHandlers
+
+Event handler interface for WebSocket events.
+
+```typescript
+interface WebSocketHandlers {
+ onHandshake?: (message: SessionHandshake) => SessionHandshakeResponse;
+ onHandshakeOk?: () => void;
+ onDisconnect?: (message: SessionDisconnect) => void;
+ onSubscribe?: (message: ScriptSubscribe) => ScriptSubscribeResponse;
+ onUnsubscribe?: (message: ScriptUnsubscribe) => void;
+ onSyntaxChange?: (message: SyntaxChange) => void;
+ onConnectionClosed?: () => void;
+ onCompilationResult?: (message: CompilationResult) => void;
+ onRuntimeDebug?: (message: RuntimeDebug) => void;
+ onRuntimeError?: (message: RuntimeError) => void;
+}
+```
+
+**Methods:**
+
+- `onHandshake`: Handler for initial handshake message, returns handshake response
+- `onHandshakeOk`: Handler called when handshake is successfully completed
+- `onDisconnect`: Handler for disconnect notifications
+- `onSubscribe`: Handler for script subscription requests from viewer, returns subscription response
+- `onUnsubscribe`: Handler for script unsubscription notifications from viewer
+- `onSyntaxChange`: Handler for syntax change notifications
+- `onConnectionClosed`: Handler called when connection is closed
+- `onCompilationResult`: Handler for compilation result notifications
+- `onRuntimeDebug`: Handler for runtime debug message notifications
+- `onRuntimeError`: Handler for runtime error notifications
+
+### ClientInfo
+
+Client information used in handshake responses.
+
+```typescript
+interface ClientInfo {
+ scriptName: string;
+ scriptId: string;
+ extension: string;
+}
+```
+
+**Fields:**
+
+- `scriptName`: Name of the script being edited
+- `scriptId`: Unique identifier for the script
+- `extension`: File extension or script type
+
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 3170dbc180c..6504002dd98 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -10,7 +10,13 @@
## Nicky: Ideally we want at least 3.21 for good preset support
## We're not there yet, but once done, there is a kludge in Linking.cmake
# "if(${CMAKE_VERSION} VERSION_LESS "3.20.0")" that can also be removed
-cmake_minimum_required(VERSION 3.16.0 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.16.0...4.0 FATAL_ERROR)
+if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.29.0")
+ cmake_policy(SET CMP0156 NEW)
+endif()
+if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.31.0")
+ cmake_policy(SET CMP0179 NEW)
+endif()
set(ROOT_PROJECT_NAME "SecondLife" CACHE STRING
"The root project/makefile/solution name. Defaults to SecondLife.")
@@ -33,6 +39,14 @@ if (NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 20)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_SCAN_FOR_MODULES OFF) # This slows down build massively
+
+set(CMAKE_OPTIMIZE_DEPENDENCIES ON)
+
+set(CMAKE_COLOR_DIAGNOSTICS ON)
+
+# Speeds up cmake generation significantly in some cases
+set(CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY ON)
include(Variables)
include(BuildVersion)
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index c895f423624..99ea22ab4b6 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -34,7 +34,10 @@ add_compile_definitions(BOOST_BIND_GLOBAL_PLACEHOLDERS)
# Force enable SSE2 instructions in GLM per the manual
# https://github.com/g-truc/glm/blob/master/manual.md#section2_10
-add_compile_definitions(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES=1 GLM_FORCE_SSE2=1 GLM_ENABLE_EXPERIMENTAL=1)
+add_compile_definitions(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES=1 GLM_ENABLE_EXPERIMENTAL=1)
+
+# SSE2NEON throws a pointless warning when compiler optimizations are enabled
+add_compile_definitions(SSE2NEON_SUPPRESS_WARNINGS=1)
# Configure crash reporting
set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds")
@@ -78,6 +81,8 @@ if (WINDOWS)
NOMINMAX
# DOM_DYNAMIC # For shared library colladadom
_CRT_SECURE_NO_WARNINGS # Allow use of sprintf etc
+ _CRT_NONSTDC_NO_DEPRECATE # Allow use of sprintf etc
+ _CRT_OBSOLETE_NO_WARNINGS
_WINSOCK_DEPRECATED_NO_WARNINGS # Disable deprecated WinSock API warnings
)
add_compile_options(
@@ -160,46 +165,40 @@ if (LINUX)
set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG}")
endif (LINUX)
-
if (DARWIN)
+ # Use rpath loading on macos
+ set(CMAKE_MACOSX_RPATH TRUE)
+
# Warnings should be fatal -- thanks, Nicky Perian, for spotting reversed default
set(CLANG_DISABLE_FATAL_WARNINGS OFF)
set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINK_FLAGS}")
- set(DARWIN_extra_cstar_flags "-Wno-unused-local-typedef -Wno-deprecated-declarations")
- # Ensure that CMAKE_CXX_FLAGS has the correct -g debug information format --
- # see Variables.cmake.
- string(REPLACE "-gdwarf-2" "-g${CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT}"
- CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARWIN_extra_cstar_flags}")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DARWIN_extra_cstar_flags}")
- # NOTE: it's critical that the optimization flag is put in front.
- # NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered.
-## Really?? On developer machines too?
-##set(ENABLE_SIGNING TRUE)
-##set(SIGNING_IDENTITY "Developer ID Application: Linden Research, Inc.")
-
- # required for clang-15/xcode-15 since our boost package still uses deprecated std::unary_function/binary_function
- # see https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#C++-Standard-Library
- add_compile_definitions(_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION)
-endif (DARWIN)
-if (LINUX OR DARWIN)
- set(GCC_WARNINGS -Wall -Wno-sign-compare -Wno-trigraphs)
+ # Ensure debug symbols are always generated
+ add_compile_options(-g --debug) # --debug is a clang synonym for -g that bypasses cmake behaviors
+
+ # Silence GL deprecation warnings
+ add_compile_definitions(GL_SILENCE_DEPRECATION=1)
+endif(DARWIN)
- if (NOT GCC_DISABLE_FATAL_WARNINGS)
- list(APPEND GCC_WARNINGS -Werror)
- endif (NOT GCC_DISABLE_FATAL_WARNINGS)
+if (LINUX OR DARWIN)
+ add_compile_options(-Wall -Wno-sign-compare -Wno-trigraphs -Wno-reorder -Wno-unused-but-set-variable -Wno-unused-variable)
- list(APPEND GCC_WARNINGS -Wno-reorder -Wno-non-virtual-dtor )
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+ # libstdc++ headers contain deprecated declarations that fail on clang
+ # macOS currently has many deprecated calls
+ add_compile_options(-Wno-unused-local-typedef)
+ endif()
- if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13)
- list(APPEND GCC_WARNINGS -Wno-unused-but-set-variable -Wno-unused-variable )
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ add_compile_options(-Wno-stringop-truncation -Wno-parentheses -Wno-maybe-uninitialized)
endif()
+ if (NOT GCC_DISABLE_FATAL_WARNINGS AND NOT CLANG_DISABLE_FATAL_WARNINGS)
+ add_compile_options(-Werror)
+ endif ()
+
add_compile_options(${GCC_WARNINGS})
add_compile_options(-m${ADDRESS_SIZE})
endif (LINUX OR DARWIN)
-
-
diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake
index 97b316c4c7c..e0807a7d19d 100644
--- a/indra/cmake/APR.cmake
+++ b/indra/cmake/APR.cmake
@@ -9,35 +9,25 @@ use_system_binary( apr apr-util )
use_prebuilt_binary(apr_suite)
if (WINDOWS)
- if (LLCOMMON_LINK_SHARED)
- set(APR_selector "lib")
- else (LLCOMMON_LINK_SHARED)
- set(APR_selector "")
- endif (LLCOMMON_LINK_SHARED)
- target_link_libraries( ll::apr INTERFACE
- ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apr-1.lib
- ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}aprutil-1.lib
- )
- target_compile_definitions( ll::apr INTERFACE APR_DECLARE_STATIC=1 APU_DECLARE_STATIC=1 API_DECLARE_STATIC=1)
-elseif (DARWIN)
- if (LLCOMMON_LINK_SHARED)
- set(APR_selector "0.dylib")
- set(APRUTIL_selector "0.dylib")
- else (LLCOMMON_LINK_SHARED)
- set(APR_selector "a")
- set(APRUTIL_selector "a")
- endif (LLCOMMON_LINK_SHARED)
-
- target_link_libraries( ll::apr INTERFACE
- ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.${APR_selector}
- ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.${APR_selector}
- iconv
- )
-else()
- target_link_libraries( ll::apr INTERFACE
- ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.a
- ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.a
- rt
- )
+ target_compile_definitions(ll::apr INTERFACE APR_DECLARE_STATIC=1 APU_DECLARE_STATIC=1 API_DECLARE_STATIC=1)
endif ()
-target_include_directories( ll::apr SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/apr-1 )
+
+find_library(APR_LIBRARY
+ NAMES
+ apr-1.lib
+ libapr-1.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+find_library(APRUTIL_LIBRARY
+ NAMES
+ aprutil-1.lib
+ libaprutil-1.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::apr INTERFACE ${APR_LIBRARY} ${APRUTIL_LIBRARY})
+
+if(DARWIN)
+ target_link_libraries(ll::apr INTERFACE iconv)
+endif()
+
+target_include_directories(ll::apr SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/apr-1)
diff --git a/indra/cmake/Audio.cmake b/indra/cmake/Audio.cmake
index 8c82749cabb..5a7a7ab0b52 100644
--- a/indra/cmake/Audio.cmake
+++ b/indra/cmake/Audio.cmake
@@ -9,23 +9,29 @@ use_system_binary(vorbis)
use_prebuilt_binary(ogg_vorbis)
target_include_directories( ll::vorbis SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include )
-if (WINDOWS)
- target_link_libraries(ll::vorbis INTERFACE
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libogg.lib
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libogg.lib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libvorbisenc.lib
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libvorbisenc.lib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libvorbisfile.lib
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libvorbisfile.lib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libvorbis.lib
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libvorbis.lib
- )
-else (WINDOWS)
- target_link_libraries(ll::vorbis INTERFACE
- ${ARCH_PREBUILT_DIRS_RELEASE}/libogg.a
- ${ARCH_PREBUILT_DIRS_RELEASE}/libvorbisenc.a
- ${ARCH_PREBUILT_DIRS_RELEASE}/libvorbisfile.a
- ${ARCH_PREBUILT_DIRS_RELEASE}/libvorbis.a
- )
-endif (WINDOWS)
+find_library(OGG_LIBRARY
+ NAMES
+ libogg.lib
+ libogg.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+find_library(VORBIS_LIBRARY
+ NAMES
+ libvorbis.lib
+ libvorbis.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+find_library(VORBISENC_LIBRARY
+ NAMES
+ libvorbisenc.lib
+ libvorbisenc.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+find_library(VORBISFILE_LIBRARY
+ NAMES
+ libvorbisfile.lib
+ libvorbisfile.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::vorbis INTERFACE ${VORBISENC_LIBRARY} ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY} )
diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 8c5b946753f..b57c33c3e00 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -17,40 +17,118 @@ use_prebuilt_binary(boost)
set(addrsfx "-x${ADDRESS_SIZE}")
if (WINDOWS)
- target_link_libraries( ll::boost INTERFACE
- libboost_context-mt${addrsfx}
- libboost_fiber-mt${addrsfx}
- libboost_filesystem-mt${addrsfx}
- libboost_program_options-mt${addrsfx}
- libboost_regex-mt${addrsfx}
- libboost_system-mt${addrsfx}
- libboost_thread-mt${addrsfx}
- libboost_url-mt${addrsfx})
-elseif (LINUX)
- target_link_libraries( ll::boost INTERFACE
- boost_context-mt${addrsfx}
- boost_fiber-mt${addrsfx}
- boost_filesystem-mt${addrsfx}
- boost_program_options-mt${addrsfx}
- boost_regex-mt${addrsfx}
- boost_signals-mt${addrsfx}
- boost_system-mt${addrsfx}
- boost_thread-mt${addrsfx}
- boost_url-mt${addrsfx})
-elseif (DARWIN)
- target_link_libraries( ll::boost INTERFACE
- boost_context-mt${addrsfx}
- boost_fiber-mt${addrsfx}
- boost_filesystem-mt${addrsfx}
- boost_program_options-mt${addrsfx}
- boost_regex-mt${addrsfx}
- boost_system-mt${addrsfx}
- boost_thread-mt${addrsfx}
- boost_url-mt${addrsfx})
+
+ find_library(BOOST_CONTEXT_LIBRARY
+ NAMES
+ libboost_context-mt
+ libboost_context-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_FIBER_LIBRARY
+ NAMES
+ libboost_fiber-mt
+ libboost_fiber-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_FILESYSTEM_LIBRARY
+ NAMES
+ libboost_filesystem-mt
+ libboost_filesystem-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_PROGRAMOPTIONS_LIBRARY
+ NAMES
+ libboost_program_options-mt
+ libboost_program_options-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_REGEX_LIBRARY
+ NAMES
+ libboost_regex-mt
+ libboost_regex-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_SYSTEM_LIBRARY
+ NAMES
+ libboost_system-mt
+ libboost_system-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_THREAD_LIBRARY
+ NAMES
+ libboost_thread-mt
+ libboost_thread-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_URL_LIBRARY
+ NAMES
+ libboost_url-mt
+ libboost_url-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+else (WINDOWS)
+
+ find_library(BOOST_CONTEXT_LIBRARY
+ NAMES
+ boost_context-mt
+ boost_context-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_FIBER_LIBRARY
+ NAMES
+ boost_fiber-mt
+ boost_fiber-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_FILESYSTEM_LIBRARY
+ NAMES
+ boost_filesystem-mt
+ boost_filesystem-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_PROGRAMOPTIONS_LIBRARY
+ NAMES
+ boost_program_options-mt
+ boost_program_options-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_REGEX_LIBRARY
+ NAMES
+ boost_regex-mt
+ boost_regex-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_SYSTEM_LIBRARY
+ NAMES
+ boost_system-mt
+ boost_system-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_THREAD_LIBRARY
+ NAMES
+ boost_thread-mt
+ boost_thread-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(BOOST_URL_LIBRARY
+ NAMES
+ boost_url-mt
+ boost_url-mt${addrsfx}
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
endif (WINDOWS)
+target_link_libraries(ll::boost INTERFACE
+ ${BOOST_FIBER_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_FILESYSTEM_LIBRARY}
+ ${BOOST_PROGRAMOPTIONS_LIBRARY}
+ ${BOOST_REGEX_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY}
+ ${BOOST_THREAD_LIBRARY}
+ ${BOOST_URL_LIBRARY})
+
if (LINUX)
- set(BOOST_SYSTEM_LIBRARY ${BOOST_SYSTEM_LIBRARY} rt)
- set(BOOST_THREAD_LIBRARY ${BOOST_THREAD_LIBRARY} rt)
+ target_link_libraries(ll::boost INTERFACE rt)
endif (LINUX)
diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake
index 9b77becf29f..e27929fa088 100644
--- a/indra/cmake/CEFPlugin.cmake
+++ b/indra/cmake/CEFPlugin.cmake
@@ -29,7 +29,6 @@ elseif (DARWIN)
${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a
${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a
${APPKIT_LIBRARY}
- "-F ${CEF_LIBRARY}"
)
elseif (LINUX)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 0a00ccbb5b8..d378366e6bb 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -53,9 +53,11 @@ set(cmake_SOURCE_FILES
Prebuilt.cmake
PulseAudio.cmake
Python.cmake
+ SSE2NEON.cmake
TemplateCheck.cmake
TinyEXR.cmake
TinyGLTF.cmake
+ Tracy.cmake
Tut.cmake
UI.cmake
UnixInstall.cmake
@@ -64,6 +66,7 @@ set(cmake_SOURCE_FILES
VisualLeakDetector.cmake
LibVLCPlugin.cmake
WebRTC.cmake
+ websocketpp.cmake
xxHash.cmake
ZLIBNG.cmake
)
diff --git a/indra/cmake/CURL.cmake b/indra/cmake/CURL.cmake
index eea0a2da623..b1595d57a89 100644
--- a/indra/cmake/CURL.cmake
+++ b/indra/cmake/CURL.cmake
@@ -7,19 +7,13 @@ add_library( ll::libcurl INTERFACE IMPORTED )
use_system_binary(libcurl)
use_prebuilt_binary(curl)
-if (WINDOWS)
- target_link_libraries(ll::libcurl INTERFACE
- ${ARCH_PREBUILT_DIRS_RELEASE}/libcurl.lib
- ll::openssl
- ll::nghttp2
- ll::zlib-ng
- )
-else ()
- target_link_libraries(ll::libcurl INTERFACE
- ${ARCH_PREBUILT_DIRS_RELEASE}/libcurl.a
- ll::openssl
- ll::nghttp2
- ll::zlib-ng
- )
-endif ()
+
+find_library(CURL_LIBRARY
+ NAMES
+ libcurl.lib
+ libcurl.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::libcurl INTERFACE ${CURL_LIBRARY} ll::openssl ll::nghttp2 ll::zlib-ng)
+
target_include_directories( ll::libcurl SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 0153e69d5b8..680f2f3ac20 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -59,11 +59,6 @@ if(WINDOWS)
openjp2.dll
)
- if(LLCOMMON_LINK_SHARED)
- set(release_files ${release_files} libapr-1.dll)
- set(release_files ${release_files} libaprutil-1.dll)
- endif()
-
# Filenames are different for 32/64 bit BugSplat file and we don't
# have any control over them so need to branch.
if (USE_BUGSPLAT)
@@ -178,15 +173,6 @@ elseif(DARWIN)
libndofdev.dylib
)
- if(LLCOMMON_LINK_SHARED)
- set(release_files ${release_files}
- libapr-1.0.dylib
- libapr-1.dylib
- libaprutil-1.0.dylib
- libaprutil-1.dylib
- )
- endif()
-
if (TARGET ll::discord_sdk)
list(APPEND release_files libdiscord_partner_sdk.dylib)
endif ()
@@ -236,13 +222,6 @@ elseif(LINUX)
libgmodule-2.0.so
libgobject-2.0.so
)
-
- if(LLCOMMON_LINK_SHARED)
- set(release_files ${release_files}
- libapr-1.so.0
- libaprutil-1.so.0
- )
- endif()
endif()
else(WINDOWS)
diff --git a/indra/cmake/EXPAT.cmake b/indra/cmake/EXPAT.cmake
index 1a0b8789dc4..fe6dced7959 100644
--- a/indra/cmake/EXPAT.cmake
+++ b/indra/cmake/EXPAT.cmake
@@ -2,18 +2,21 @@
include(Prebuilt)
include_guard()
-add_library( ll::expat INTERFACE IMPORTED )
+add_library(ll::expat INTERFACE IMPORTED)
use_system_binary(expat)
use_prebuilt_binary(expat)
+
if (WINDOWS)
- target_compile_definitions( ll::expat INTERFACE XML_STATIC=1)
- target_link_libraries( ll::expat INTERFACE
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libexpatd.lib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libexpat.lib)
-else ()
- target_link_libraries( ll::expat INTERFACE
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libexpat.a
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libexpat.a)
+ target_compile_definitions(ll::expat INTERFACE XML_STATIC=1)
endif ()
-target_include_directories( ll::expat SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include )
+
+find_library(EXPAT_LIBRARY
+ NAMES
+ libexpat.lib
+ libexpat.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::expat INTERFACE ${EXPAT_LIBRARY})
+
+target_include_directories(ll::expat SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
diff --git a/indra/cmake/FreeType.cmake b/indra/cmake/FreeType.cmake
index 563491556d2..3c635e851b1 100644
--- a/indra/cmake/FreeType.cmake
+++ b/indra/cmake/FreeType.cmake
@@ -9,9 +9,10 @@ use_system_binary(freetype)
use_prebuilt_binary(freetype)
target_include_directories( ll::freetype SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/freetype2/)
-if (WINDOWS)
- target_link_libraries( ll::freetype INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/freetype.lib)
-else()
- target_link_libraries( ll::freetype INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libfreetype.a)
-endif()
+find_library(FREETYPE_LIBRARY
+ NAMES
+ freetype.lib
+ libfreetype.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+target_link_libraries(ll::freetype INTERFACE ${FREETYPE_LIBRARY})
diff --git a/indra/cmake/Hunspell.cmake b/indra/cmake/Hunspell.cmake
index 129679febdb..b063363bc02 100644
--- a/indra/cmake/Hunspell.cmake
+++ b/indra/cmake/Hunspell.cmake
@@ -8,17 +8,17 @@ use_prebuilt_binary(dictionaries)
add_library( ll::hunspell INTERFACE IMPORTED )
use_system_binary(hunspell)
use_prebuilt_binary(libhunspell)
+
if (WINDOWS)
target_compile_definitions( ll::hunspell INTERFACE HUNSPELL_STATIC=1)
- target_link_libraries( ll::hunspell INTERFACE
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libhunspell.lib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libhunspell.lib
- )
-elseif(DARWIN)
- target_link_libraries( ll::hunspell INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libhunspell-1.7.a
- )
-elseif(LINUX)
- target_link_libraries( ll::hunspell INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libhunspell-1.7.a
- )
endif()
+
+find_library(HUNSPELL_LIBRARY
+ NAMES
+ libhunspell.lib
+ libhunspell-1.7.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::hunspell INTERFACE ${HUNSPELL_LIBRARY})
+
target_include_directories( ll::hunspell SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/hunspell)
diff --git a/indra/cmake/JPEG.cmake b/indra/cmake/JPEG.cmake
index ade5a070ccf..f864ca7f8d1 100644
--- a/indra/cmake/JPEG.cmake
+++ b/indra/cmake/JPEG.cmake
@@ -8,13 +8,13 @@ add_library( ll::libjpeg INTERFACE IMPORTED )
use_system_binary(libjpeg)
use_prebuilt_binary(libjpeg-turbo)
-if (LINUX)
- target_link_libraries( ll::libjpeg INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libjpeg.a)
-elseif (DARWIN)
- target_link_libraries( ll::libjpeg INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libjpeg.a)
-elseif (WINDOWS)
- target_link_libraries( ll::libjpeg INTERFACE
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/jpeg.lib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/jpeg.lib)
-endif (LINUX)
-target_include_directories( ll::libjpeg SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
+
+find_library(JPEG_LIBRARY
+ NAMES
+ jpeg.lib
+ libjpeg.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::libjpeg INTERFACE ${JPEG_LIBRARY})
+
+target_include_directories(ll::libjpeg SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake
index 6408f1200cb..83725ffd1b8 100644
--- a/indra/cmake/LLAddBuildTest.cmake
+++ b/indra/cmake/LLAddBuildTest.cmake
@@ -92,6 +92,13 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
target_include_directories (PROJECT_${project}_TEST_${name} PRIVATE ${LIBS_OPEN_DIR}/test )
set_target_properties(PROJECT_${project}_TEST_${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}")
+ if (DARWIN)
+ set_target_properties(PROJECT_${project}_TEST_${name}
+ PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1
+ INSTALL_RPATH "@executable_path/Resources"
+ )
+ endif(DARWIN)
#
# Per-codefile additional / external project dep and lib dep property extraction
@@ -225,7 +232,10 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
# test binaries always need to be signed for local development
set_target_properties(INTEGRATION_TEST_${testname}
PROPERTIES
- XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-")
+ XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-"
+ BUILD_WITH_INSTALL_RPATH 1
+ INSTALL_RPATH "@executable_path/Resources"
+ )
endif ()
# Add link deps to the executable
diff --git a/indra/cmake/LLKDU.cmake b/indra/cmake/LLKDU.cmake
index 668b07ffab4..7680ab7b542 100644
--- a/indra/cmake/LLKDU.cmake
+++ b/indra/cmake/LLKDU.cmake
@@ -13,14 +13,26 @@ add_library( ll::kdu INTERFACE IMPORTED )
if (USE_KDU)
include(Prebuilt)
use_prebuilt_binary(kdu)
+
if (WINDOWS)
- target_link_libraries( ll::kdu INTERFACE kdu.lib)
+ find_library(KDU_LIBRARY
+ NAMES
+ kdu
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
else (WINDOWS)
- target_link_libraries( ll::kdu INTERFACE libkdu.a)
+ find_library(KDU_LIBRARY
+ NAMES
+ libkdu.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
endif (WINDOWS)
+ target_link_libraries(ll::kdu INTERFACE ${KDU_LIBRARY})
+
target_include_directories( ll::kdu SYSTEM INTERFACE
${AUTOBUILD_INSTALL_DIR}/include/kdu
${LIBS_OPEN_DIR}/llkdu
)
+ target_compile_definitions(ll::kdu INTERFACE KDU_NO_THREADS=1)
endif (USE_KDU)
diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake
index d0a52ffb63e..2699f8efee1 100644
--- a/indra/cmake/LLPrimitive.cmake
+++ b/indra/cmake/LLPrimitive.cmake
@@ -24,26 +24,35 @@ use_prebuilt_binary(colladadom)
use_prebuilt_binary(minizip-ng) # needed for colladadom
use_prebuilt_binary(libxml2)
-if (WINDOWS)
- target_link_libraries( ll::minizip-ng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/minizip.lib )
-else()
- target_link_libraries( ll::minizip-ng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libminizip.a )
-endif()
+find_library(MINIZIPNG_LIBRARY
+ NAMES
+ minizip.lib
+ libminizip.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::minizip-ng INTERFACE ${MINIZIPNG_LIBRARY})
+
+find_library(LIBXML2_LIBRARY
+ NAMES
+ libxml2.lib
+ libxml2.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::libxml INTERFACE ${LIBXML2_LIBRARY})
if (WINDOWS)
- target_link_libraries( ll::libxml INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libxml2.lib Bcrypt.lib)
-else()
- target_link_libraries( ll::libxml INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libxml2.a)
+ target_link_libraries( ll::libxml INTERFACE Bcrypt.lib)
endif()
target_include_directories( ll::colladadom SYSTEM INTERFACE
${LIBS_PREBUILT_DIR}/include/collada
${LIBS_PREBUILT_DIR}/include/collada/1.4
)
-if (WINDOWS)
- target_link_libraries(ll::colladadom INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libcollada14dom23-s.lib ll::libxml ll::minizip-ng )
-elseif (DARWIN)
- target_link_libraries(ll::colladadom INTERFACE collada14dom ll::boost ll::libxml ll::minizip-ng)
-elseif (LINUX)
- target_link_libraries(ll::colladadom INTERFACE collada14dom ll::boost ll::libxml ll::minizip-ng)
-endif()
+
+find_library(COLLADADOM_LIBRARY
+ NAMES
+ libcollada14dom23-s.lib
+ collada14dom
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::colladadom INTERFACE ${COLLADADOM_LIBRARY} ll::boost ll::libxml ll::minizip-ng)
diff --git a/indra/cmake/LibVLCPlugin.cmake b/indra/cmake/LibVLCPlugin.cmake
index 599ce028445..6361028c0c4 100644
--- a/indra/cmake/LibVLCPlugin.cmake
+++ b/indra/cmake/LibVLCPlugin.cmake
@@ -9,20 +9,16 @@ use_prebuilt_binary(vlc-bin)
set(LIBVLCPLUGIN ON CACHE BOOL
"LIBVLCPLUGIN support for the llplugin/llmedia test apps.")
-if (WINDOWS)
- target_link_libraries( ll::libvlc INTERFACE
- libvlc.lib
- libvlccore.lib
- )
-elseif (DARWIN)
- target_link_libraries( ll::libvlc INTERFACE
- libvlc.dylib
- libvlccore.dylib
- )
-elseif (LINUX)
- # Specify a full path to make sure we get a static link
- target_link_libraries( ll::libvlc INTERFACE
- ${LIBS_PREBUILT_DIR}/lib/libvlc.a
- ${LIBS_PREBUILT_DIR}/lib/libvlccore.a
- )
-endif (WINDOWS)
+find_library(VLC_LIBRARY
+ NAMES
+ libvlc.lib
+ libvlc.dylib
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+find_library(VLCCORE_LIBRARY
+ NAMES
+ libvlccore.lib
+ libvlccore.dylib
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::libvlc INTERFACE ${VLC_LIBRARY} ${VLCCORE_LIBRARY})
diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake
index 8451659c34d..900a64e2dd4 100644
--- a/indra/cmake/Linking.cmake
+++ b/indra/cmake/Linking.cmake
@@ -38,9 +38,10 @@ endif ()
# windows) and CMAKE_BUILD_TYPE on Makefile based generators (like linux). The reason for this is
# that CMAKE_BUILD_TYPE is essentially meaningless at configuration time for IDE generators and
# CMAKE_CFG_INTDIR is meaningless at build time for Makefile generators
-
-link_directories(${AUTOBUILD_INSTALL_DIR}/lib/$>)
-link_directories(${AUTOBUILD_INSTALL_DIR}/lib/release)
+if(NOT DARWIN)
+ link_directories(${AUTOBUILD_INSTALL_DIR}/lib/$>)
+ link_directories(${AUTOBUILD_INSTALL_DIR}/lib/release)
+endif(NOT DARWIN)
add_library( ll::oslibraries INTERFACE IMPORTED )
@@ -74,6 +75,8 @@ else()
find_library(APPKIT_LIBRARY AppKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
+ find_library(COREGRAPHICS_LIBRARY CoreGraphics)
+ find_library(AUDIOTOOLBOX_LIBRARY AudioToolbox)
target_link_libraries( ll::oslibraries INTERFACE
${COCOA_LIBRARY}
@@ -82,6 +85,8 @@ else()
${CARBON_LIBRARY}
${APPKIT_LIBRARY}
${COREAUDIO_LIBRARY}
+ ${AUDIOTOOLBOX_LIBRARY}
+ ${COREGRAPHICS_LIBRARY}
)
endif()
diff --git a/indra/cmake/Meshoptimizer.cmake b/indra/cmake/Meshoptimizer.cmake
index fd144d2b97c..af1c51f032a 100644
--- a/indra/cmake/Meshoptimizer.cmake
+++ b/indra/cmake/Meshoptimizer.cmake
@@ -9,12 +9,12 @@ add_library( ll::meshoptimizer INTERFACE IMPORTED )
use_system_binary(meshoptimizer)
use_prebuilt_binary(meshoptimizer)
-if (WINDOWS)
- target_link_libraries( ll::meshoptimizer INTERFACE meshoptimizer.lib)
-elseif (LINUX)
- target_link_libraries( ll::meshoptimizer INTERFACE meshoptimizer.o)
-elseif (DARWIN)
- target_link_libraries( ll::meshoptimizer INTERFACE libmeshoptimizer.a)
-endif (WINDOWS)
+find_library(MESHOPTIMIZER_LIBRARY
+ NAMES
+ meshoptimizer.lib
+ libmeshoptimizer.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
-target_include_directories( ll::meshoptimizer SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/meshoptimizer)
+target_link_libraries(ll::meshoptimizer INTERFACE ${MESHOPTIMIZER_LIBRARY})
+
+target_include_directories(ll::meshoptimizer SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/meshoptimizer)
diff --git a/indra/cmake/NDOF.cmake b/indra/cmake/NDOF.cmake
index b88fbccf2a1..a8f63f945b1 100644
--- a/indra/cmake/NDOF.cmake
+++ b/indra/cmake/NDOF.cmake
@@ -13,12 +13,15 @@ if (NDOF)
use_prebuilt_binary(open-libndofdev)
endif (WINDOWS OR DARWIN)
- if (WINDOWS)
- target_link_libraries( ll::ndof INTERFACE libndofdev)
- elseif (DARWIN OR LINUX)
- target_link_libraries( ll::ndof INTERFACE ndofdev)
- endif (WINDOWS)
- target_compile_definitions( ll::ndof INTERFACE LIB_NDOF=1)
+ find_library(NDOF_LIBRARY
+ NAMES
+ libndofdev
+ ndofdev
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ target_link_libraries(ll::ndof INTERFACE ${NDOF_LIBRARY})
+
+ target_compile_definitions(ll::ndof INTERFACE LIB_NDOF=1)
endif (NDOF)
diff --git a/indra/cmake/NGHTTP2.cmake b/indra/cmake/NGHTTP2.cmake
index 7b2aa5971f5..e81204d7166 100644
--- a/indra/cmake/NGHTTP2.cmake
+++ b/indra/cmake/NGHTTP2.cmake
@@ -6,9 +6,12 @@ add_library( ll::nghttp2 INTERFACE IMPORTED )
use_system_binary(nghttp2)
use_prebuilt_binary(nghttp2)
-if (WINDOWS)
- target_link_libraries( ll::nghttp2 INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/nghttp2.lib)
-else ()
- target_link_libraries( ll::nghttp2 INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libnghttp2.a)
-endif ()
+
+find_library(NGHTTP2_LIBRARY
+ NAMES
+ nghttp2.lib
+ libnghttp2.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::nghttp2 INTERFACE ${NGHTTP2_LIBRARY})
target_include_directories( ll::nghttp2 SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/nghttp2)
diff --git a/indra/cmake/OPENAL.cmake b/indra/cmake/OPENAL.cmake
index 347dd02cd7d..ab1604aa22a 100644
--- a/indra/cmake/OPENAL.cmake
+++ b/indra/cmake/OPENAL.cmake
@@ -8,7 +8,7 @@ include_guard()
# to have memory leaks, has no option to play music streams
# It probably makes sense to to completely remove it
-set(USE_OPENAL OFF CACHE BOOL "Enable OpenAL")
+set(USE_OPENAL ON CACHE BOOL "Enable OpenAL")
# ND: To streamline arguments passed, switch from OPENAL to USE_OPENAL
# To not break all old build scripts convert old arguments but warn about it
if(OPENAL)
@@ -22,20 +22,21 @@ if (USE_OPENAL)
target_compile_definitions( ll::openal INTERFACE LL_OPENAL=1)
use_prebuilt_binary(openal)
- if(WINDOWS)
- target_link_libraries( ll::openal INTERFACE
- OpenAL32
- alut
- )
- elseif(LINUX)
- target_link_libraries( ll::openal INTERFACE
- openal
- alut
- )
- else()
- target_link_libraries( ll::openal INTERFACE
- openal
- alut
- )
- endif()
+ find_library(OPENAL_LIBRARY
+ NAMES
+ OpenAL32
+ openal
+ libopenal.dylib
+ libopenal.so
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ find_library(ALUT_LIBRARY
+ NAMES
+ alut
+ libalut.dylib
+ libalut.so
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+ target_link_libraries(ll::openal INTERFACE ${OPENAL_LIBRARY} ${ALUT_LIBRARY})
+
endif ()
diff --git a/indra/cmake/OpenJPEG.cmake b/indra/cmake/OpenJPEG.cmake
index c4aab2e9e53..95e71fd78e8 100644
--- a/indra/cmake/OpenJPEG.cmake
+++ b/indra/cmake/OpenJPEG.cmake
@@ -1,11 +1,22 @@
# -*- cmake -*-
+include_guard()
+
include(Prebuilt)
+include(Linking)
-include_guard()
add_library( ll::openjpeg INTERFACE IMPORTED )
use_system_binary(openjpeg)
use_prebuilt_binary(openjpeg)
-target_link_libraries(ll::openjpeg INTERFACE openjp2 )
-target_include_directories( ll::openjpeg SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/openjpeg)
+find_library(OPENJPEG_LIBRARY
+ NAMES
+ openjp2
+ openjp2.lib
+ libopenjp2.a
+ libopenjp2.so
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::openjpeg INTERFACE ${OPENJPEG_LIBRARY})
+
+target_include_directories(ll::openjpeg SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/openjpeg)
diff --git a/indra/cmake/OpenSSL.cmake b/indra/cmake/OpenSSL.cmake
index 67a84e14afd..9d33f2e0dec 100644
--- a/indra/cmake/OpenSSL.cmake
+++ b/indra/cmake/OpenSSL.cmake
@@ -7,12 +7,24 @@ add_library( ll::openssl INTERFACE IMPORTED )
use_system_binary(openssl)
use_prebuilt_binary(openssl)
+
+find_library(SSL_LIBRARY
+ NAMES
+ libssl.lib
+ libssl.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+find_library(CRYPTO_LIBRARY
+ NAMES
+ libcrypto.lib
+ libcrypto.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::openssl INTERFACE ${SSL_LIBRARY} ${CRYPTO_LIBRARY})
+
if (WINDOWS)
- target_link_libraries(ll::openssl INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libssl.lib ${ARCH_PREBUILT_DIRS_RELEASE}/libcrypto.lib Crypt32.lib)
-elseif (LINUX)
- target_link_libraries(ll::openssl INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libssl.a ${ARCH_PREBUILT_DIRS_RELEASE}/libcrypto.a dl)
-else()
- target_link_libraries(ll::openssl INTERFACE ssl crypto)
+ target_link_libraries(ll::openssl INTERFACE Crypt32.lib)
endif (WINDOWS)
-target_include_directories( ll::openssl SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
+
+target_include_directories(ll::openssl SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
diff --git a/indra/cmake/PNG.cmake b/indra/cmake/PNG.cmake
index e5893e9a206..0c01e5ee78f 100644
--- a/indra/cmake/PNG.cmake
+++ b/indra/cmake/PNG.cmake
@@ -6,9 +6,12 @@ add_library( ll::libpng INTERFACE IMPORTED )
use_system_binary(libpng)
use_prebuilt_binary(libpng)
-if (WINDOWS)
- target_link_libraries(ll::libpng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libpng16.lib)
-else()
- target_link_libraries(ll::libpng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libpng16.a)
-endif()
-target_include_directories( ll::libpng SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/libpng16)
+
+find_library(LIBPNG_LIBRARY
+ NAMES
+ libpng16.lib
+ libpng16.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::libpng INTERFACE ${LIBPNG_LIBRARY})
+target_include_directories(ll::libpng SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/libpng16)
diff --git a/indra/cmake/PluginAPI.cmake b/indra/cmake/PluginAPI.cmake
index 114415e514b..a2bf13db2c9 100644
--- a/indra/cmake/PluginAPI.cmake
+++ b/indra/cmake/PluginAPI.cmake
@@ -1,5 +1,7 @@
# -*- cmake -*-
+include(OpenGL)
+
add_library( ll::pluginlibraries INTERFACE IMPORTED )
if (WINDOWS)
@@ -13,4 +15,6 @@ if (WINDOWS)
)
endif (WINDOWS)
+target_link_libraries( ll::pluginlibraries INTERFACE OpenGL::GL)
+target_include_directories( ll::pluginlibraries INTERFACE ${CMAKE_SOURCE_DIR}/llimage ${CMAKE_SOURCE_DIR}/llrender)
diff --git a/indra/cmake/SSE2NEON.cmake b/indra/cmake/SSE2NEON.cmake
new file mode 100644
index 00000000000..797f2af80e2
--- /dev/null
+++ b/indra/cmake/SSE2NEON.cmake
@@ -0,0 +1,12 @@
+# -*- cmake -*-
+
+include(Prebuilt)
+
+add_library(ll::sse2neon INTERFACE IMPORTED)
+
+if (DARWIN)
+ use_system_binary(sse2neon)
+ use_prebuilt_binary(sse2neon)
+
+ target_include_directories( ll::sse2neon SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/sse2neon)
+endif()
diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake
index a7eac2711fe..cb09337d15e 100644
--- a/indra/cmake/Tracy.cmake
+++ b/indra/cmake/Tracy.cmake
@@ -15,6 +15,7 @@ endif()
if (USE_TRACY)
option(USE_TRACY_ON_DEMAND "Use on-demand Tracy profiling." ON)
option(USE_TRACY_LOCAL_ONLY "Disallow remote Tracy profiling." OFF)
+ option(USE_TRACY_GPU "Use Tracy GPU profiling" OFF)
use_system_binary(tracy)
use_prebuilt_binary(tracy)
@@ -31,9 +32,8 @@ if (USE_TRACY)
target_compile_definitions(ll::tracy INTERFACE -DTRACY_NO_BROADCAST=1 -DTRACY_ONLY_LOCALHOST=1)
endif ()
- # GHA runners don't always provide invariant TSC support, but always build with LL_TESTS enabled
- if (DARWIN AND LL_TESTS)
- target_compile_definitions(ll::tracy INTERFACE -DTRACY_TIMER_FALLBACK=1)
+ if (USE_TRACY_GPU AND NOT DARWIN) # Tracy OpenGL mode is incompatible with macOS/iOS
+ target_compile_definitions(ll::tracy INTERFACE -DLL_PROFILER_ENABLE_TRACY_OPENGL=1)
endif ()
# See: indra/llcommon/llprofiler.h
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index 5b3aeb8b7f8..22c2156bb88 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -144,52 +144,19 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(DARWIN 1)
string(REGEX MATCH "-mmacosx-version-min=([^ ]+)" scratch "$ENV{LL_BUILD}")
- set(CMAKE_OSX_DEPLOYMENT_TARGET "${CMAKE_MATCH_1}")
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "${CMAKE_MATCH_1}" CACHE STRING "macOS Deploy Target" FORCE)
message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET = '${CMAKE_OSX_DEPLOYMENT_TARGET}'")
- string(REGEX MATCH "-stdlib=([^ ]+)" scratch "$ENV{LL_BUILD}")
- set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "${CMAKE_MATCH_1}")
- message(STATUS "CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY = '${CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY}'")
-
- string(REGEX MATCH " -g([^ ]*)" scratch "$ENV{LL_BUILD}")
- set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "${CMAKE_MATCH_1}")
- # -gdwarf-2 is passed in LL_BUILD according to 00-COMPILE-LINK-RUN.txt.
- # However, when CMake 3.9.2 sees -gdwarf-2, it silently deletes the whole -g
- # switch, producing no symbols at all! The same thing happens if we specify
- # plain -g ourselves, i.e. CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT is
- # the empty string. Specifying -gdwarf-with-dsym or just -gdwarf drives a
- # different CMake behavior: it substitutes plain -g. As of 2017-09-19,
- # viewer-build-variables/variables still passes -gdwarf-2, which is the
- # no-symbols case. Set -gdwarf, triggering CMake to substitute plain -g --
- # at least that way we should get symbols, albeit mangled ones. It Would Be
- # Nice if CMake's behavior could be predicted from a consistent mental
- # model, instead of only observed experimentally.
- string(REPLACE "dwarf-2" "dwarf"
- CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT
- "${CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT}")
- message(STATUS "CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT = '${CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT}'")
+ # Use dwarf symbols for most libraries for compilation speed
+ set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf")
string(REGEX MATCH "-O([^ ]*)" scratch "$ENV{LL_BUILD}")
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL "${CMAKE_MATCH_1}")
message(STATUS "CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL = '${CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL}'")
- # allow disabling this check by setting LL_SKIP_REQUIRE_SYSROOT either ON as cmake cache var or non-empty as environment var
- set(LL_SKIP_REQUIRE_SYSROOT OFF CACHE BOOL "Skip requirement to set toolchain sysroot ahead of time. Not skipped by default for consistency, but skipping can be useful for selecting alternative xcode versions side by side")
- if("$ENV{LL_SKIP_REQUIRE_SYSROOT}" STREQUAL "" AND NOT ${LL_SKIP_REQUIRE_SYSROOT})
- string(REGEX MATCHALL "[^ ]+" LL_BUILD_LIST "$ENV{LL_BUILD}")
- list(FIND LL_BUILD_LIST "-iwithsysroot" sysroot_idx)
- if ("${sysroot_idx}" LESS 0)
- message(FATAL_ERROR "Environment variable LL_BUILD must contain '-iwithsysroot'")
- endif ()
- math(EXPR sysroot_idx "${sysroot_idx} + 1")
- list(GET LL_BUILD_LIST "${sysroot_idx}" CMAKE_OSX_SYSROOT)
- endif()
- message(STATUS "CMAKE_OSX_SYSROOT = '${CMAKE_OSX_SYSROOT}'")
-
- set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0")
set(CMAKE_XCODE_ATTRIBUTE_GCC_STRICT_ALIASING NO)
set(CMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH NO)
- set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS ssse3)
+ set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS sse4.2)
# we must hard code this to off for now. xcode's built in signing does not
# handle embedded app bundles such as CEF and others. Any signing for local
# development must be done after the build as we do in viewer_manifest.py for
@@ -204,9 +171,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "")
set(CMAKE_XCODE_ATTRIBUTE_DISABLE_MANUAL_TARGET_ORDER_BUILD_WARNING YES)
set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION NO)
- set(CMAKE_OSX_ARCHITECTURES "${ARCH}")
- string(REPLACE "i686" "i386" CMAKE_OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}")
- string(REPLACE "AMD64" "x86_64" CMAKE_OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}")
+ set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "macOS Build Arch" FORCE)
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# Default deploy grid
diff --git a/indra/cmake/WebRTC.cmake b/indra/cmake/WebRTC.cmake
index 230522a40af..7fefaa41522 100644
--- a/indra/cmake/WebRTC.cmake
+++ b/indra/cmake/WebRTC.cmake
@@ -1,32 +1,24 @@
# -*- cmake -*-
+include_guard()
+
include(Linking)
include(Prebuilt)
-include_guard()
-
add_library( ll::webrtc INTERFACE IMPORTED )
target_include_directories( ll::webrtc SYSTEM INTERFACE "${LIBS_PREBUILT_DIR}/include/webrtc" "${LIBS_PREBUILT_DIR}/include/webrtc/third_party/abseil-cpp")
use_prebuilt_binary(webrtc)
-if (WINDOWS)
- target_link_libraries( ll::webrtc INTERFACE webrtc.lib )
-elseif (DARWIN)
- FIND_LIBRARY(COREAUDIO_LIBRARY CoreAudio)
- FIND_LIBRARY(COREGRAPHICS_LIBRARY CoreGraphics)
- FIND_LIBRARY(AUDIOTOOLBOX_LIBRARY AudioToolbox)
- FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation)
- FIND_LIBRARY(COCOA_LIBRARY Cocoa)
+find_library(WEBRTC_LIBRARY
+ NAMES
+ webrtc
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries( ll::webrtc INTERFACE ${WEBRTC_LIBRARY} )
- target_link_libraries( ll::webrtc INTERFACE
- libwebrtc.a
- ${COREAUDIO_LIBRARY}
- ${AUDIOTOOLBOX_LIBRARY}
- ${COREGRAPHICS_LIBRARY}
- ${COREFOUNDATION_LIBRARY}
- ${COCOA_LIBRARY}
- )
+if (DARWIN)
+ target_link_libraries( ll::webrtc INTERFACE ll::oslibraries )
elseif (LINUX)
- target_link_libraries( ll::webrtc INTERFACE libwebrtc.a X11 )
-endif (WINDOWS)
+ target_link_libraries( ll::webrtc INTERFACE X11 )
+endif ()
diff --git a/indra/cmake/ZLIBNG.cmake b/indra/cmake/ZLIBNG.cmake
index d7b920da26d..a6d67489e71 100644
--- a/indra/cmake/ZLIBNG.cmake
+++ b/indra/cmake/ZLIBNG.cmake
@@ -11,11 +11,14 @@ if(USE_CONAN )
endif()
use_prebuilt_binary(zlib-ng)
-if (WINDOWS)
- target_link_libraries( ll::zlib-ng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/zlib.lib )
-else()
- target_link_libraries( ll::zlib-ng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libz.a )
-endif (WINDOWS)
+
+find_library(ZLIBNG_LIBRARY
+ NAMES
+ zlib.lib
+ libz.a
+ PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
+
+target_link_libraries(ll::zlib-ng INTERFACE ${ZLIBNG_LIBRARY})
if( NOT LINUX )
target_include_directories( ll::zlib-ng SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/zlib-ng)
diff --git a/indra/cmake/websocketpp.cmake b/indra/cmake/websocketpp.cmake
new file mode 100644
index 00000000000..726f0a5e0b4
--- /dev/null
+++ b/indra/cmake/websocketpp.cmake
@@ -0,0 +1,7 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+add_library( ll::websocketpp INTERFACE IMPORTED )
+
+use_system_binary( websocketpp )
+use_prebuilt_binary(websocketpp)
diff --git a/indra/cmake/xxHash.cmake b/indra/cmake/xxHash.cmake
index a7c1cba62c9..e4f8517d9bf 100644
--- a/indra/cmake/xxHash.cmake
+++ b/indra/cmake/xxHash.cmake
@@ -1,8 +1,5 @@
# -*- cmake -*-
-if (XXHASH_CMAKE_INCLUDED)
- return()
-endif (XXHASH_CMAKE_INCLUDED)
-set (XXHASH_CMAKE_INCLUDED TRUE)
+include_guard()
include(Prebuilt)
use_prebuilt_binary(xxhash)
diff --git a/indra/doxygen/CMakeLists.txt b/indra/doxygen/CMakeLists.txt
index 354ae7b6369..43ebf4ae263 100644
--- a/indra/doxygen/CMakeLists.txt
+++ b/indra/doxygen/CMakeLists.txt
@@ -1,13 +1,5 @@
# -*- cmake -*-
-set(ROOT_PROJECT_NAME "SecondLife" CACHE STRING
- "The root project/makefile/solution name. Defaults to SecondLife.")
-project(${ROOT_PROJECT_NAME})
-
-set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
-
-include(Variables)
-
# add a target to generate API documentation with Doxygen
find_package(Doxygen)
if(DOXYGEN_FOUND)
diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt
deleted file mode 100644
index 8b137891791..00000000000
--- a/indra/edit-me-to-trigger-new-build.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/indra/integration_tests/CMakeLists.txt b/indra/integration_tests/CMakeLists.txt
index ced2b3dbcfb..1d5f0772b5a 100644
--- a/indra/integration_tests/CMakeLists.txt
+++ b/indra/integration_tests/CMakeLists.txt
@@ -1,8 +1,3 @@
# -*- cmake -*-
add_subdirectory(llui_libtest)
-IF (LLIMAGE_LIBTEST)
- MESSAGE(STATUS "Build llimage_libtest")
- add_subdirectory(llimage_libtest)
-ELSE (LLIMAGE_LIBTEST)
- MESSAGE(STATUS "Skip llimage_libtest")
-ENDIF (LLIMAGE_LIBTEST)
+add_subdirectory(llimage_libtest)
diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt
index ee2890778b4..e6ff142626c 100644
--- a/indra/integration_tests/llimage_libtest/CMakeLists.txt
+++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt
@@ -1,6 +1,7 @@
# -*- cmake -*-
# Integration tests of the llimage library (JPEG2000, PNG, jpeg, etc... images reading and writing)
+if (LL_TESTS)
project (llimage_libtest)
@@ -8,9 +9,7 @@ include(00-Common)
include(LLCommon)
include(LLImage)
include(LLMath)
-include(LLImageJ2COJ)
include(LLKDU)
-include(LLFileSystem)
set(llimage_libtest_SOURCE_FILES
llimage_libtest.cpp
@@ -24,17 +23,9 @@ set(llimage_libtest_HEADER_FILES
list(APPEND llimage_libtest_SOURCE_FILES ${llimage_libtest_HEADER_FILES})
add_executable(llimage_libtest
- WIN32
- MACOSX_BUNDLE
${llimage_libtest_SOURCE_FILES}
)
-set_target_properties(llimage_libtest
- PROPERTIES
- WIN32_EXECUTABLE
- FALSE
-)
-
# Libraries on which this application depends on
# Sort by high-level to low-level
target_link_libraries(llimage_libtest
@@ -42,64 +33,9 @@ target_link_libraries(llimage_libtest
llfilesystem
llmath
llimage
- llkdu
- llimagej2coj
)
-
-if (DARWIN)
- # Path inside the app bundle where we'll need to copy libraries
- set(LLIMAGE_LIBTEST_DESTINATION_DIR
- ${CMAKE_CURRENT_BINARY_DIR}/$,$,>/llimage_libtest.app/Contents/Resources
- )
- # Create the Contents/Resources directory
- add_custom_command(
- TARGET llimage_libtest POST_BUILD
- COMMAND ${CMAKE_COMMAND}
- ARGS
- -E
- make_directory
- ${LLIMAGE_LIBTEST_DESTINATION_DIR}
- COMMENT "Creating Resources directory in app bundle."
- )
-else (DARWIN)
- set(LLIMAGE_LIBTEST_DESTINATION_DIR
- ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/
- )
-endif (DARWIN)
-
-get_target_property(BUILT_LLCOMMON llcommon LOCATION)
-add_custom_command(TARGET llimage_libtest POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${BUILT_LLCOMMON} ${LLIMAGE_LIBTEST_DESTINATION_DIR}
- DEPENDS ${BUILT_LLCOMMON}
-)
-
-if (DARWIN)
- # Copy the required libraries to the package app
- add_custom_command(TARGET llimage_libtest POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${AUTOBUILD_INSTALL_DIR}/lib/release/libapr-1.0.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
- DEPENDS ${AUTOBUILD_INSTALL_DIR}/lib/release/libapr-1.0.dylib
- )
- add_custom_command(TARGET llimage_libtest POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${AUTOBUILD_INSTALL_DIR}/lib/release/libaprutil-1.0.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
- DEPENDS ${AUTOBUILD_INSTALL_DIR}/lib/release/libaprutil-1.0.dylib
- )
- add_custom_command(TARGET llimage_libtest POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${AUTOBUILD_INSTALL_DIR}/lib/release/libexception_handler.dylib ${LLIMAGE_LIBTEST_DESTINATION_DIR}
- DEPENDS ${AUTOBUILD_INSTALL_DIR}/lib/release/libexception_handler.dylib
- )
- foreach(expat ${EXPAT_COPY})
- add_custom_command(TARGET llimage_libtest POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy ${AUTOBUILD_INSTALL_DIR}/lib/release/${expat} ${LLIMAGE_LIBTEST_DESTINATION_DIR}
- DEPENDS ${AUTOBUILD_INSTALL_DIR}/lib/release/${expat}
- )
- endforeach(expat)
-endif (DARWIN)
-
-if (WINDOWS)
- # Check indra/test_apps/llplugintest/CMakeLists.txt for an example of what to copy over for Windows and how
-endif (WINDOWS)
# Ensure people working on the viewer don't break this library
-# *NOTE: This could be removed, or only built by TeamCity, if the build
-# and link times become too long.
add_dependencies(viewer llimage_libtest)
+
+endif(LL_TESTS)
diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
index 95102094aec..c45bd6fd01a 100644
--- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
+++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp
@@ -43,6 +43,8 @@
#include "v4coloru.h"
#include "llsdserialize.h"
#include "llcleanup.h"
+#include "lltrace.h"
+#include "llfasttimer.h"
// system libraries
#include
@@ -573,10 +575,10 @@ int main(int argc, char** argv)
// Create the logging thread if required
- if (LLFastTimer::sMetricLog)
+ if (LLTrace::BlockTimer::sMetricLog)
{
- LLFastTimer::sLogLock = new LLMutex(NULL);
- fast_timer_log_thread = new LogThread(LLFastTimer::sLogName);
+ LLTrace::BlockTimer::setLogLock(new LLMutex());
+ fast_timer_log_thread = new LogThread(LLTrace::BlockTimer::sLogName);
fast_timer_log_thread->start();
}
@@ -618,9 +620,9 @@ int main(int argc, char** argv)
// Output perf data if requested by user
if (analyze_performance)
{
- std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
- std::string current_name = LLFastTimer::sLogName + ".slp";
- std::string report_name = LLFastTimer::sLogName + "_report.csv";
+ std::string baseline_name = LLTrace::BlockTimer::sLogName + "_baseline.slp";
+ std::string current_name = LLTrace::BlockTimer::sLogName + ".slp";
+ std::string report_name = LLTrace::BlockTimer::sLogName + "_report.csv";
std::cout << "Analyzing performance, check report in : " << report_name << std::endl;
@@ -628,9 +630,9 @@ int main(int argc, char** argv)
}
// Stop the perf gathering system if needed
- if (LLFastTimer::sMetricLog)
+ if (LLTrace::BlockTimer::sMetricLog)
{
- LLMetricPerformanceTesterBasic::deleteTester(LLFastTimer::sLogName);
+ LLMetricPerformanceTesterBasic::deleteTester(LLTrace::BlockTimer::sLogName);
sAllDone = true;
}
diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp
index 83e7fad92fd..d115dc309d2 100644
--- a/indra/llaudio/llvorbisencode.cpp
+++ b/indra/llaudio/llvorbisencode.cpp
@@ -34,38 +34,6 @@
#include "llmath.h"
#include "llapr.h"
-//#if LL_DARWIN
-// MBW -- XXX -- Getting rid of SecondLifeVorbis for now
-#if 0
-#include "VorbisFramework.h"
-
-#define vorbis_analysis mac_vorbis_analysis
-#define vorbis_analysis_headerout mac_vorbis_analysis_headerout
-#define vorbis_analysis_init mac_vorbis_analysis_init
-#define vorbis_encode_ctl mac_vorbis_encode_ctl
-#define vorbis_encode_setup_init mac_vorbis_encode_setup_init
-#define vorbis_encode_setup_managed mac_vorbis_encode_setup_managed
-
-#define vorbis_info_init mac_vorbis_info_init
-#define vorbis_info_clear mac_vorbis_info_clear
-#define vorbis_comment_init mac_vorbis_comment_init
-#define vorbis_comment_clear mac_vorbis_comment_clear
-#define vorbis_block_init mac_vorbis_block_init
-#define vorbis_block_clear mac_vorbis_block_clear
-#define vorbis_dsp_clear mac_vorbis_dsp_clear
-#define vorbis_analysis_buffer mac_vorbis_analysis_buffer
-#define vorbis_analysis_wrote mac_vorbis_analysis_wrote
-#define vorbis_analysis_blockout mac_vorbis_analysis_blockout
-
-#define ogg_stream_packetin mac_ogg_stream_packetin
-#define ogg_stream_init mac_ogg_stream_init
-#define ogg_stream_flush mac_ogg_stream_flush
-#define ogg_stream_pageout mac_ogg_stream_pageout
-#define ogg_page_eos mac_ogg_page_eos
-#define ogg_stream_clear mac_ogg_stream_clear
-
-#endif
-
S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& error_msg)
{
U16 num_channels = 0;
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index a504e71340b..daa1def7263 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -11,7 +11,7 @@ include(LLSharedLibs)
include(Copy3rdPartyLibs)
include(ZLIBNG)
include(Tracy)
-
+include(SSE2NEON)
set(llcommon_SOURCE_FILES
apply.cpp
@@ -277,6 +277,7 @@ target_link_libraries(
ll::boost
ll::oslibraries
ll::tracy
+ ll::sse2neon
)
target_include_directories(llcommon INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
@@ -313,7 +314,7 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llmainthreadtask "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llpounceable "" "${test_libs}")
- LL_ADD_INTEGRATION_TEST(llprocess "" "${test_libs}")
+ #LL_ADD_INTEGRATION_TEST(llprocess "" "${test_libs}") RIDER: Test is a known failure. Disabling for the moment.
LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llprocinfo "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")
diff --git a/indra/llcommon/fsyspath.h b/indra/llcommon/fsyspath.h
index e9c96edce39..2c900c02a70 100644
--- a/indra/llcommon/fsyspath.h
+++ b/indra/llcommon/fsyspath.h
@@ -12,7 +12,10 @@
#if ! defined(LL_FSYSPATH_H)
#define LL_FSYSPATH_H
+#include
#include
+#include
+#include
// While std::filesystem::path can be directly constructed from std::string on
// both Posix and Windows, that's not what we want on Windows. Per
@@ -33,37 +36,43 @@
// char"), the "native narrow encoding" isn't UTF-8, so file paths containing
// non-ASCII characters get mangled.
//
-// Once we're building with C++20, we could pass a UTF-8 std::string through a
-// vector to engage std::filesystem::path's own UTF-8 conversion. But
-// sigh, as of 2024-04-03 we're not yet there.
-//
-// Anyway, encapsulating the important UTF-8 conversions in our own subclass
-// allows us to migrate forward to C++20 conventions without changing
-// referencing code.
+// Encapsulating the important UTF-8 conversions in our own subclass allows us
+// to migrate forward to C++20 conventions without changing referencing code.
class fsyspath: public std::filesystem::path
{
using super = std::filesystem::path;
+ // In C++20 (__cpp_lib_char8_t), std::filesystem::u8path() is deprecated.
+ // std::filesystem::path(iter, iter) performs UTF-8 conversions when the
+ // value_type of the iterators is char8_t. While we could copy into a
+ // temporary std::u8string and from there into std::filesystem::path, to
+ // minimize string copying we'll define a transform_iterator that accepts
+ // a std::string_view::iterator and dereferences to char8_t.
+ struct u8ify
+ {
+ char8_t operator()(char c) const { return char8_t(c); }
+ };
+ using u8iter = boost::transform_iterator;
+
public:
// default
fsyspath() {}
- // construct from UTF-8 encoded std::string
- fsyspath(const std::string& path): super(std::filesystem::u8path(path)) {}
- // construct from UTF-8 encoded const char*
- fsyspath(const char* path): super(std::filesystem::u8path(path)) {}
+ // construct from UTF-8 encoded string
+ fsyspath(const std::string& path): fsyspath(std::string_view(path)) {}
+ fsyspath(const char* path): fsyspath(std::string_view(path)) {}
+ fsyspath(std::string_view path):
+ super(u8iter(path.begin(), u8ify()), u8iter(path.end(), u8ify()))
+ {}
// construct from existing path
fsyspath(const super& path): super(path) {}
- fsyspath& operator=(const super& p) { super::operator=(p); return *this; }
- fsyspath& operator=(const std::string& p)
- {
- super::operator=(std::filesystem::u8path(p));
- return *this;
- }
- fsyspath& operator=(const char* p)
+ fsyspath& operator=(const super& p) { super::operator=(p); return *this; }
+ fsyspath& operator=(const std::string& p) { return (*this) = std::string_view(p); }
+ fsyspath& operator=(const char* p) { return (*this) = std::string_view(p); }
+ fsyspath& operator=(std::string_view p)
{
- super::operator=(std::filesystem::u8path(p));
+ assign(u8iter(p.begin(), u8ify()), u8iter(p.end(), u8ify()));
return *this;
}
diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index a918caa2e83..a41af153fe7 100644
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -28,12 +28,6 @@
#define LL_LINDEN_COMMON_H
#include "llprofiler.h"
-#if TRACY_ENABLE && !defined(LL_PROFILER_ENABLE_TRACY_OPENGL) // hooks for memory profiling
-void *tracy_aligned_malloc(size_t size, size_t alignment);
-void tracy_aligned_free(void *memblock);
-#define _aligned_malloc(X, Y) tracy_aligned_malloc((X), (Y))
-#define _aligned_free(X) tracy_aligned_free((X))
-#endif
// *NOTE: Please keep includes here to a minimum!
//
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 08a43983d32..c532620daa1 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -229,7 +229,7 @@ bool LLApp::parseCommandOptions(int argc, wchar_t** wargv)
if(wargv[ii][1] == '-') ++offset;
#if LL_WINDOWS
- name.assign(utf16str_to_utf8str(&wargv[ii][offset]));
+ name.assign(ll_convert_wide_to_string(&wargv[ii][offset]));
#else
name.assign(wstring_to_utf8str(&wargv[ii][offset]));
#endif
@@ -253,7 +253,7 @@ bool LLApp::parseCommandOptions(int argc, wchar_t** wargv)
++ii;
#if LL_WINDOWS
- value.assign(utf16str_to_utf8str((wargv[ii])));
+ value.assign(ll_convert_wide_to_string((wargv[ii])));
#else
value.assign(wstring_to_utf8str((wargv[ii])));
#endif
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 84b35749ccd..7a22eaf2032 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -33,23 +33,23 @@
#include "lltracethreadrecorder.h"
#include "llcleanup.h"
-thread_local bool gProfilerEnabled = false;
-
-#if (TRACY_ENABLE)
+#if LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY && TRACY_ENABLE
// Override new/delete for tracy memory profiling
void* ll_tracy_new(size_t size)
{
- void* ptr;
- if (gProfilerEnabled)
- {
- //LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
- ptr = (malloc)(size);
- }
- else
+ void* ptr = (malloc)(size);
+ if (!ptr)
{
- ptr = (malloc)(size);
+ throw std::bad_alloc();
}
+ LL_PROFILE_ALLOC(ptr, size);
+ return ptr;
+}
+
+void* ll_tracy_aligned_new(size_t size, size_t alignment)
+{
+ void* ptr = ll_aligned_malloc_fallback(size, alignment);
if (!ptr)
{
throw std::bad_alloc();
@@ -58,6 +58,18 @@ void* ll_tracy_new(size_t size)
return ptr;
}
+void ll_tracy_delete(void* ptr)
+{
+ LL_PROFILE_FREE(ptr);
+ (free)(ptr);
+}
+
+void ll_tracy_aligned_delete(void* ptr)
+{
+ LL_PROFILE_FREE(ptr);
+ ll_aligned_free_fallback(ptr);
+}
+
void* operator new(size_t size)
{
return ll_tracy_new(size);
@@ -68,18 +80,14 @@ void* operator new[](std::size_t count)
return ll_tracy_new(count);
}
-void ll_tracy_delete(void* ptr)
+void* operator new(size_t size, std::align_val_t align)
{
- LL_PROFILE_FREE(ptr);
- if (gProfilerEnabled)
- {
- //LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
- (free)(ptr);
- }
- else
- {
- (free)(ptr);
- }
+ return ll_tracy_aligned_new(size, (size_t)align);
+}
+
+void* operator new[](std::size_t count, std::align_val_t align)
+{
+ return ll_tracy_aligned_new(count, (size_t)align);
}
void operator delete(void *ptr) noexcept
@@ -92,27 +100,17 @@ void operator delete[](void* ptr) noexcept
ll_tracy_delete(ptr);
}
-// C-style malloc/free can't be so easily overridden, so we define tracy versions and use
-// a pre-processor #define in linden_common.h to redirect to them. The parens around the native
-// functions below prevents recursive substitution by the preprocessor.
-//
-// Unaligned mallocs are rare in LL code but hooking them causes problems in 3p lib code (looking at
-// you, Havok), so we'll only capture the aligned version.
-
-void *tracy_aligned_malloc(size_t size, size_t alignment)
+void operator delete(void *ptr, std::align_val_t align) noexcept
{
- auto ptr = ll_aligned_malloc_fallback(size, alignment);
- if (ptr) LL_PROFILE_ALLOC(ptr, size);
- return ptr;
+ ll_tracy_aligned_delete(ptr);
}
-void tracy_aligned_free(void *memblock)
+void operator delete[](void* ptr, std::align_val_t align) noexcept
{
- LL_PROFILE_FREE(memblock);
- ll_aligned_free_fallback(memblock);
+ ll_tracy_aligned_delete(ptr);
}
-#endif
+#endif // TRACY_ENABLE && !LL_PROFILER_ENABLE_TRACY_OPENGL
//static
bool LLCommon::sAprInitialized = false;
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index d8340989948..3411e9c6bb5 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -79,7 +79,7 @@ namespace {
//
if (s.size())
{
- OutputDebugString(utf8str_to_utf16str(s).c_str());
+ OutputDebugString(ll_convert(s).c_str());
OutputDebugString(TEXT("\n"));
}
}
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 722743f4538..1c5fe9d2f53 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -64,7 +64,7 @@ bool BlockTimer::sLog = false;
std::string BlockTimer::sLogName = "";
bool BlockTimer::sMetricLog = false;
-#if LL_LINUX
+#if LL_LINUX || (LL_DARWIN && LL_ARM64)
U64 BlockTimer::sClockResolution = 1000000000; // Nanosecond resolution
#else
U64 BlockTimer::sClockResolution = 1000000; // Microsecond resolution
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 09fcf8a1afe..271dade0979 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -30,9 +30,14 @@
#include "llinstancetracker.h"
#include "lltrace.h"
#include "lltreeiterators.h"
+#include "llprocessor.h"
+#if LL_X86 || LL_X86_64
#if LL_WINDOWS
#include
+#else
+#include
+#endif
#endif
#define LL_FAST_TIMER_ON 1
@@ -68,35 +73,10 @@ class BlockTimer
//
// Windows implementation of CPU clock
//
-
- //
- // NOTE: put back in when we aren't using platform sdk anymore
- //
- // because MS has different signatures for these functions in winnt.h
- // need to rename them to avoid conflicts
- //#define _interlockedbittestandset _renamed_interlockedbittestandset
- //#define _interlockedbittestandreset _renamed_interlockedbittestandreset
- //#include
- //#undef _interlockedbittestandset
- //#undef _interlockedbittestandreset
-
- //inline U32 getCPUClockCount32()
- //{
- // U64 time_stamp = __rdtsc();
- // return (U32)(time_stamp >> 8);
- //}
- //
- //// return full timer value, *not* shifted by 8 bits
- //inline U64 getCPUClockCount64()
- //{
- // return __rdtsc();
- //}
-
-
+#if LL_FASTTIMER_USE_RDTSC
// 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
-#if LL_FASTTIMER_USE_RDTSC
static U32 getCPUClockCount32()
{
unsigned __int64 val = __rdtsc();
@@ -159,23 +139,37 @@ class BlockTimer
#endif // (LL_LINUX) && !(defined(__i386__) || defined(__amd64__))
-#if (LL_LINUX || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
+#if LL_DARWIN && LL_ARM64
+ //
+ // Mac implementation of CPU clock - non-x86.
+ //
+ static U64 getCPUClockCount64()
+ {
+ return clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
+ }
+
+ static U32 getCPUClockCount32()
+ {
+ return (U32)(getCPUClockCount64() >> 8);
+ }
+#endif // LL_DARWIN && LL_ARM64
+
+#if (LL_LINUX || LL_DARWIN) && (LL_X86 || LL_X86_64)
//
// Mac+Linux FAST x86 implementation of CPU clock
+ //
+#if LL_FASTTIMER_USE_RDTSC
static U32 getCPUClockCount32()
{
- U32 low(0),high(0);
- __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) );
- return (low>>8) | (high<<24);
+ U64 time_stamp = __rdtsc() >> 8U;
+ return static_cast(time_stamp);
}
static U64 getCPUClockCount64()
{
- U32 low(0),high(0);
- __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) );
- return (U64)low | ( ((U64)high) << 32);
+ return static_cast(__rdtsc());
}
-
+#endif
#endif
static BlockTimerStatHandle& getRootTimeBlock();
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index d0bc8f7652d..53659ac13ff 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -178,8 +178,7 @@ int LLFile::mkdir(const std::string& dirname, int perms)
{
#if LL_WINDOWS
// permissions are ignored on Windows
- std::string utf8dirname = dirname;
- llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname);
+ std::wstring utf16dirname = ll_convert(dirname);
int rc = _wmkdir(utf16dirname.c_str());
#else
int rc = ::mkdir(dirname.c_str(), (mode_t)perms);
@@ -201,8 +200,7 @@ int LLFile::rmdir(const std::string& dirname)
{
#if LL_WINDOWS
// permissions are ignored on Windows
- std::string utf8dirname = dirname;
- llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname);
+ std::wstring utf16dirname = ll_convert(dirname);
int rc = _wrmdir(utf16dirname.c_str());
#else
int rc = ::rmdir(dirname.c_str());
@@ -214,10 +212,8 @@ int LLFile::rmdir(const std::string& dirname)
LLFILE* LLFile::fopen(const std::string& filename, const char* mode) /* Flawfinder: ignore */
{
#if LL_WINDOWS
- std::string utf8filename = filename;
- std::string utf8mode = std::string(mode);
- llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
- llutf16string utf16mode = utf8str_to_utf16str(utf8mode);
+ std::wstring utf16filename = ll_convert(filename);
+ std::wstring utf16mode = ll_convert(std::string(mode));
return _wfopen(utf16filename.c_str(),utf16mode.c_str());
#else
return ::fopen(filename.c_str(),mode); /* Flawfinder: ignore */
@@ -227,10 +223,8 @@ LLFILE* LLFile::fopen(const std::string& filename, const char* mode) /* Flawf
LLFILE* LLFile::_fsopen(const std::string& filename, const char* mode, int sharingFlag)
{
#if LL_WINDOWS
- std::string utf8filename = filename;
- std::string utf8mode = std::string(mode);
- llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
- llutf16string utf16mode = utf8str_to_utf16str(utf8mode);
+ std::wstring utf16filename = ll_convert(filename);
+ std::wstring utf16mode = ll_convert(std::string(mode));
return _wfsopen(utf16filename.c_str(),utf16mode.c_str(),sharingFlag);
#else
llassert(0);//No corresponding function on non-windows
@@ -270,8 +264,7 @@ std::string LLFile::getContents(const std::string& filename)
int LLFile::remove(const std::string& filename, int supress_error)
{
#if LL_WINDOWS
- std::string utf8filename = filename;
- llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
+ std::wstring utf16filename = ll_convert(filename);
int rc = _wremove(utf16filename.c_str());
#else
int rc = ::remove(filename.c_str());
@@ -282,10 +275,8 @@ int LLFile::remove(const std::string& filename, int supress_error)
int LLFile::rename(const std::string& filename, const std::string& newname, int supress_error)
{
#if LL_WINDOWS
- std::string utf8filename = filename;
- std::string utf8newname = newname;
- llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
- llutf16string utf16newname = utf8str_to_utf16str(utf8newname);
+ std::wstring utf16filename = ll_convert(filename);
+ std::wstring utf16newname = ll_convert(newname);
int rc = _wrename(utf16filename.c_str(),utf16newname.c_str());
#else
int rc = ::rename(filename.c_str(),newname.c_str());
@@ -327,8 +318,7 @@ bool LLFile::copy(const std::string& from, const std::string& to)
int LLFile::stat(const std::string& filename, llstat* filestatus)
{
#if LL_WINDOWS
- std::string utf8filename = filename;
- llutf16string utf16filename = utf8str_to_utf16str(utf8filename);
+ std::wstring utf16filename = ll_convert(filename);
int rc = _wstat(utf16filename.c_str(),filestatus);
#else
int rc = ::stat(filename.c_str(),filestatus);
@@ -453,14 +443,14 @@ llifstream::llifstream() {}
// explicit
llifstream::llifstream(const std::string& _Filename, ios_base::openmode _Mode):
- std::ifstream(utf8str_to_utf16str( _Filename ).c_str(),
+ std::ifstream(ll_convert( _Filename ).c_str(),
_Mode | ios_base::in)
{
}
void llifstream::open(const std::string& _Filename, ios_base::openmode _Mode)
{
- std::ifstream::open(utf8str_to_utf16str(_Filename).c_str(),
+ std::ifstream::open(ll_convert(_Filename).c_str(),
_Mode | ios_base::in);
}
@@ -472,14 +462,14 @@ llofstream::llofstream() {}
// explicit
llofstream::llofstream(const std::string& _Filename, ios_base::openmode _Mode):
- std::ofstream(utf8str_to_utf16str( _Filename ).c_str(),
+ std::ofstream(ll_convert( _Filename ).c_str(),
_Mode | ios_base::out)
{
}
void llofstream::open(const std::string& _Filename, ios_base::openmode _Mode)
{
- std::ofstream::open(utf8str_to_utf16str( _Filename ).c_str(),
+ std::ofstream::open(ll_convert( _Filename ).c_str(),
_Mode | ios_base::out);
}
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index 662a2511cdc..ada6b9519e5 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -188,6 +188,17 @@ class LLLeapImpl: public LLLeap
<< childout.peek(0, peeklen) << "..." << LL_ENDL;
}
+ // Handle any remaining stderr data (partial lines) the same way as we do
+ // for stdout: log it.
+ LLProcess::ReadPipe& childerr(mChild->getReadPipe(LLProcess::STDERR));
+ if (childerr.size())
+ {
+ LLProcess::ReadPipe::size_type
+ peeklen((std::min)(LLProcess::ReadPipe::size_type(50), childerr.size()));
+ LL_WARNS("LLLeap") << "Final stderr " << childerr.size() << " bytes: "
+ << childerr.peek(0, peeklen) << "..." << LL_ENDL;
+ }
+
// Kill this instance. MUST BE LAST before return!
delete this;
return false;
diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp
index e999b8f597d..c8ca586e7fc 100644
--- a/indra/llcommon/llmd5.cpp
+++ b/indra/llcommon/llmd5.cpp
@@ -255,6 +255,11 @@ void LLMD5::raw_digest(unsigned char* s) const
memcpy(s, digest, 16); /* Flawfinder: ignore */
}
+#if LL_DARWIN
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
void LLMD5::hex_digest(char* s) const
{
if (!finalized)
@@ -273,6 +278,10 @@ void LLMD5::hex_digest(char* s) const
s[32] = '\0';
}
+#if LL_DARWIN
+#pragma clang diagnostic pop
+#endif
+
std::ostream& operator<<(std::ostream& stream, const LLMD5& context)
{
char s[33]; /* Flawfinder: ignore */
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index b616edfde71..adc556d180f 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -71,7 +71,11 @@ LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);
#define ll_assert_aligned(ptr,alignment)
#endif
+#if LL_ARM64
+#include "sse2neon.h"
+#else
#include
+#endif
template T* LL_NEXT_ALIGNED_ADDRESS(T* address)
{
@@ -231,8 +235,6 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
#if defined(LL_WINDOWS)
void* ret = _aligned_malloc(size, 32);
-#elif defined(LL_DARWIN)
- void* ret = ll_aligned_malloc_fallback( size, 32 );
#else
void *ret;
if (0 != posix_memalign(&ret, 32, size))
@@ -248,8 +250,31 @@ inline void ll_aligned_free_32(void *p)
LL_PROFILE_FREE(p);
#if defined(LL_WINDOWS)
_aligned_free(p);
-#elif defined(LL_DARWIN)
- ll_aligned_free_fallback( p );
+#else
+ free(p); // posix_memalign() is compatible with heap deallocator
+#endif
+}
+
+inline void* ll_aligned_malloc_64(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
+#if defined(LL_WINDOWS)
+ void* ret = _aligned_malloc(size, 64);
+#else
+ void *ret;
+ if (0 != posix_memalign(&ret, 64, size))
+ return nullptr;
+#endif
+ LL_PROFILE_ALLOC(ret, size);
+ return ret;
+}
+
+inline void ll_aligned_free_64(void *p)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
+ LL_PROFILE_FREE(p);
+#if defined(LL_WINDOWS)
+ _aligned_free(p);
#else
free(p); // posix_memalign() is compatible with heap deallocator
#endif
@@ -261,19 +286,23 @@ LL_FORCE_INLINE void* ll_aligned_malloc(size_t size)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
void* ret;
- if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0)
+ if constexpr (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0)
{
ret = malloc(size);
LL_PROFILE_ALLOC(ret, size);
}
- else if (ALIGNMENT == 16)
+ else if constexpr (ALIGNMENT == 16)
{
ret = ll_aligned_malloc_16(size);
}
- else if (ALIGNMENT == 32)
+ else if constexpr (ALIGNMENT == 32)
{
ret = ll_aligned_malloc_32(size);
}
+ else if constexpr (ALIGNMENT == 64)
+ {
+ ret = ll_aligned_malloc_64(size);
+ }
else
{
ret = ll_aligned_malloc_fallback(size, ALIGNMENT);
@@ -285,16 +314,20 @@ template
LL_FORCE_INLINE void ll_aligned_free(void* ptr)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
- if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN)
+ if constexpr (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN)
{
LL_PROFILE_FREE(ptr);
free(ptr);
}
- else if (ALIGNMENT == 16)
+ else if constexpr (ALIGNMENT == 16)
{
ll_aligned_free_16(ptr);
}
- else if (ALIGNMENT == 32)
+ else if constexpr (ALIGNMENT == 32)
+ {
+ return ll_aligned_free_32(ptr);
+ }
+ else if constexpr (ALIGNMENT == 64)
{
return ll_aligned_free_32(ptr);
}
@@ -310,6 +343,9 @@ LL_FORCE_INLINE void ll_aligned_free(void* ptr)
inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
+#if defined(LL_ARM64)
+ memcpy(dst, src, bytes);
+#else
assert(src != NULL);
assert(dst != NULL);
assert(bytes > 0);
@@ -375,6 +411,7 @@ inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __
dst += 16;
src += 16;
}
+#endif
}
#ifndef __DEBUG_PRIVATE_MEM__
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index b499a9ce10e..b2a97345487 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -76,6 +76,23 @@
#endif
#endif
+// Set up CPU architecture defines
+#if LL_MSVC && defined(_M_ARM64)
+# define LL_ARM64 1
+#elif LL_GNUC && (defined(__arm64__) || defined(__aarch64__))
+# define LL_ARM64 1
+#elif LL_MSVC && _M_X64
+# define LL_X86_64 1
+# define LL_X86 1
+#elif LL_MSVC && _M_IX86
+# define LL_X86 1
+#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
+# define LL_X86_64 1
+# define LL_X86 1
+#elif LL_GNUC && ( defined(__i386__) )
+# define LL_X86 1
+#endif
+
// Deal with minor differences on Unixy OSes.
#if LL_DARWIN || LL_LINUX
// Different name, same functionality.
@@ -118,11 +135,8 @@
#if LL_WINDOWS
#define LL_DLLEXPORT __declspec(dllexport)
#define LL_DLLIMPORT __declspec(dllimport)
-#elif LL_LINUX
-#define LL_DLLEXPORT __attribute__ ((visibility("default")))
-#define LL_DLLIMPORT
#else
-#define LL_DLLEXPORT
+#define LL_DLLEXPORT __attribute__ ((visibility("default")))
#define LL_DLLIMPORT
#endif // LL_WINDOWS
@@ -167,7 +181,7 @@
#define LL_TO_STRING_HELPER(x) #x
#define LL_TO_STRING(x) LL_TO_STRING_HELPER(x)
-#define LL_TO_WSTRING_HELPER(x) L#x
+#define LL_TO_WSTRING_HELPER(x) L## #x
#define LL_TO_WSTRING(x) LL_TO_WSTRING_HELPER(x)
#define LL_FILE_LINENO_MSG(msg) __FILE__ "(" LL_TO_STRING(__LINE__) ") : " msg
#define LL_GLUE_IMPL(x, y) x##y
@@ -187,4 +201,16 @@
#define LL_PRETTY_FUNCTION __PRETTY_FUNCTION__
#endif
+#if LL_ARM64
+#define GLM_FORCE_NEON 1
+#else
+#define GLM_FORCE_SSE2 1
+#endif
+
+#if LL_ARM64
+#define KDU_NEON_INTRINSICS 1
+#else
+#define KDU_X86_INTRINSICS 1
+#endif
+
#endif // not LL_LINDEN_PREPROCESSOR_H
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index 2e94651083b..718f4713213 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -628,6 +628,8 @@ class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl
#elif LL_DARWIN
+#include
+#include
#include
#include
@@ -638,25 +640,21 @@ class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl
{
getCPUIDInfo();
uint64_t frequency = getSysctlInt64("hw.cpufrequency");
- if (!frequency)
+ if (frequency == 0) // fallback to clockrate and tbfrequency
{
- auto tbfrequency = getSysctlInt64("hw.tbfrequency");
- struct clockinfo clockrate;
- auto clockrate_len = sizeof(clockrate);
- if (!sysctlbyname("kern.clockrate", &clockrate, &clockrate_len, NULL, 0))
- frequency = tbfrequency * clockrate.hz;
+ frequency = getSysctlClockrate() * getSysctlInt64("hw.tbfrequency");
}
setInfo(eFrequency, (F64)frequency / (F64)1000000);
}
- virtual ~LLProcessorInfoDarwinImpl() {}
+ virtual ~LLProcessorInfoDarwinImpl() = default;
private:
int getSysctlInt(const char* name)
{
int result = 0;
size_t len = sizeof(int);
- int error = sysctlbyname(name, (void*)&result, &len, NULL, 0);
+ int error = sysctlbyname(name, (void*)&result, &len, nullptr, 0);
return error == -1 ? 0 : result;
}
@@ -664,7 +662,7 @@ class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl
{
uint64_t value = 0;
size_t size = sizeof(value);
- int result = sysctlbyname(name, (void*)&value, &size, NULL, 0);
+ int result = sysctlbyname(name, (void*)&value, &size, nullptr, 0);
if ( result == 0 )
{
if ( size == sizeof( uint64_t ) )
@@ -684,6 +682,14 @@ class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl
return result == -1 ? 0 : value;
}
+ uint64_t getSysctlClockrate()
+ {
+ struct clockinfo clockrate{};
+ size_t size = sizeof(clockrate);
+ int error = sysctlbyname("kern.clockrate", &clockrate, &size, nullptr, 0);
+ return error == -1 ? 0 : clockrate.hz;
+ }
+
void getCPUIDInfo()
{
size_t len = 0;
diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h
index f8ccf686c87..b955f7f55cf 100644
--- a/indra/llcommon/llprocessor.h
+++ b/indra/llcommon/llprocessor.h
@@ -28,20 +28,7 @@
#ifndef LLPROCESSOR_H
#define LLPROCESSOR_H
#include "llunits.h"
-
-#if LL_MSVC && _M_X64
-# define LL_X86_64 1
-# define LL_X86 1
-#elif LL_MSVC && _M_IX86
-# define LL_X86 1
-#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
-# define LL_X86_64 1
-# define LL_X86 1
-#elif LL_GNUC && ( defined(__i386__) )
-# define LL_X86 1
-#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
-# define LL_PPC 1
-#endif
+#include "llpreprocessor.h"
class LLProcessorInfoImpl;
diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h
index f6a4d247471..5fb32d62804 100644
--- a/indra/llcommon/llprofiler.h
+++ b/indra/llcommon/llprofiler.h
@@ -74,23 +74,18 @@
#define LL_PROFILER_CONFIGURATION LL_PROFILER_CONFIG_FAST_TIMER
#endif
-extern thread_local bool gProfilerEnabled;
-
#if defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION > LL_PROFILER_CONFIG_NONE)
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
#include "tracy/Tracy.hpp"
- // Enable OpenGL profiling
- #define LL_PROFILER_ENABLE_TRACY_OPENGL 0
-
// Enable RenderDoc labeling
- #define LL_PROFILER_ENABLE_RENDER_DOC 0
+ //#define LL_PROFILER_ENABLE_RENDER_DOC 0
#endif
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY
#define LL_PROFILER_FRAME_END FrameMark
- #define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name ); gProfilerEnabled = true;
+ #define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name );
#define LL_RECORD_BLOCK_TIME(name) ZoneScoped // Want descriptive names; was: ZoneNamedN( ___tracy_scoped_zone, #name, true );
#define LL_PROFILE_ZONE_NAMED(name) ZoneNamedN( ___tracy_scoped_zone, name, true );
#define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, true ) // RGB
@@ -133,7 +128,7 @@ extern thread_local bool gProfilerEnabled;
#endif
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
#define LL_PROFILER_FRAME_END FrameMark
- #define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name ); gProfilerEnabled = true;
+ #define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name );
#define LL_RECORD_BLOCK_TIME(name) ZoneNamedN(___tracy_scoped_zone, #name, true); const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
#define LL_PROFILE_ZONE_NAMED(name) ZoneNamedN( ___tracy_scoped_zone, #name, true );
#define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, true ) // RGB
@@ -158,23 +153,20 @@ extern thread_local bool gProfilerEnabled;
#endif // LL_PROFILER
#if LL_PROFILER_ENABLE_TRACY_OPENGL
-#define LL_PROFILE_GPU_ZONE(name) TracyGpuZone(name)
-#define LL_PROFILE_GPU_ZONEC(name,color) TracyGpuZoneC(name,color)
+#define LL_PROFILE_GPU_ZONE(name) TracyGpuZone(name)
+#define LL_PROFILE_GPU_ZONEC(name,color) TracyGpuZoneC(name,color)
#define LL_PROFILER_GPU_COLLECT TracyGpuCollect
#define LL_PROFILER_GPU_CONTEXT TracyGpuContext
-
-// disable memory tracking (incompatible with GPU tracing
-#define LL_PROFILE_ALLOC(ptr, size) (void)(ptr); (void)(size);
-#define LL_PROFILE_FREE(ptr) (void)(ptr);
+#define LL_PROFILER_GPU_CONTEXT_NAMED TracyGpuContextName
#else
-#define LL_PROFILE_GPU_ZONE(name) (void)name;
-#define LL_PROFILE_GPU_ZONEC(name,color) (void)name;(void)color;
+#define LL_PROFILE_GPU_ZONE(name) (void)name;
+#define LL_PROFILE_GPU_ZONEC(name,color) (void)name;(void)color;
#define LL_PROFILER_GPU_COLLECT
#define LL_PROFILER_GPU_CONTEXT
+#define LL_PROFILER_GPU_CONTEXT_NAMED(name) (void)name;
+#endif // LL_PROFILER_ENABLE_TRACY_OPENGL
-#define LL_LABEL_OBJECT_GL(type, name, length, label)
-
-#if !LL_DARWIN && LL_PROFILER_CONFIGURATION > 1
+#if LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY
#define LL_PROFILE_ALLOC(ptr, size) TracyAlloc(ptr, size)
#define LL_PROFILE_FREE(ptr) TracyFree(ptr)
#else
@@ -182,8 +174,6 @@ extern thread_local bool gProfilerEnabled;
#define LL_PROFILE_FREE(ptr) (void)(ptr);
#endif
-#endif
-
#if LL_PROFILER_ENABLE_RENDER_DOC
#define LL_LABEL_OBJECT_GL(type, name, length, label) glObjectLabel(type, name, length, label)
#else
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index 7d41c42ba7f..0088eeec67d 100644
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -35,6 +35,7 @@
#include
#include
#include
+#include
#ifdef LL_LINUX
// For strcmp
@@ -709,5 +710,208 @@ struct ll_template_cast_impl \
} \
}
+//-----------------------------------------------
+namespace LL
+{
+ /**
+ * @brief A range adapter that provides filtered iteration over a container.
+ *
+ * filter_range creates a filtered view of an iterator range using a predicate function.
+ * Only elements that satisfy the predicate will be accessible when iterating through
+ * the range. This is useful for processing subsets of containers without copying data.
+ *
+ * The class uses boost::filter_iterator internally to provide the filtering functionality.
+ *
+ * @tparam Predicate A callable object (function, functor, lambda) that takes an element
+ * from the iterator range and returns true if the element should be
+ * included in the filtered range.
+ * @tparam Iterator The iterator type for the underlying container/range.
+ *
+ * Example usage:
+ * @code
+ * std::vector numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ *
+ * // Create a predicate to filter even numbers
+ * auto is_even = [](int n) { return n % 2 == 0; };
+ *
+ * // Create filtered range using make_filter helper
+ * auto even_range = LL::make_filter(is_even, numbers.begin(), numbers.end());
+ *
+ * // Iterate through only even numbers
+ * for (auto value : even_range) {
+ * std::cout << value << " "; // Prints: 2 4 6 8 10
+ * }
+ *
+ * // Or manually construct the filter_range
+ * LL::filter_range::iterator>
+ * manual_range(is_even, numbers.begin(), numbers.end());
+ * @endcode
+ *
+ * @note This class provides a lightweight view over the original data.
+ * No copying of elements occurs, making it efficient for large containers.
+ * @note The predicate is applied during iteration, so complex predicates may
+ * impact performance for frequently-accessed ranges.
+ * @note The underlying container must remain valid for the lifetime of the filter_range.
+ *
+ * @see make_filter() for a convenient factory function
+ * @see boost::filter_iterator for the underlying implementation details
+ */
+ template
+ class filter_range
+ {
+ public:
+ /// The filtered iterator type - combines predicate with base iterator
+ using filter_iter = boost::filter_iterator;
+
+ /// Value type of the filtered elements
+ using value_type = typename std::iterator_traits::value_type;
+
+ /// Iterator type for range-based for loops and STL algorithms
+ using iterator = filter_iter;
+ using const_iterator = filter_iter;
+
+ /**
+ * @brief Constructs a filter_range with the given predicate and iterator range.
+ *
+ * @param pred The predicate function/functor to filter elements.
+ * Must be callable with signature: bool(const value_type&)
+ * @param begin Iterator to the beginning of the range to filter
+ * @param end Iterator to the end of the range to filter
+ *
+ * @pre begin and end must form a valid iterator range
+ * @pre pred must be a valid callable that can be invoked with elements from [begin, end)
+ */
+ filter_range(Predicate pred, Iterator begin, Iterator end)
+ : begin_(pred, begin, end), end_(pred, end, end) {}
+
+ /**
+ * @brief Returns an iterator to the first element that satisfies the predicate.
+ *
+ * @return filter_iter Iterator pointing to the first filtered element,
+ * or equal to end() if no elements satisfy the predicate.
+ */
+ filter_iter begin() const { return begin_; }
+
+ /**
+ * @brief Returns an iterator representing the end of the filtered range.
+ *
+ * @return filter_iter Past-the-end iterator for the filtered range.
+ */
+ filter_iter end() const { return end_; }
+
+ /**
+ * @brief Checks if the filtered range is empty.
+ *
+ * @return true if no elements in the range satisfy the predicate, false otherwise.
+ *
+ * @note This operation has O(1) complexity as it only compares iterators.
+ */
+ bool empty() const { return begin_ == end_; }
+
+ private:
+ filter_iter begin_; ///< Iterator to first element satisfying predicate
+ filter_iter end_; ///< Past-the-end iterator for the filtered range
+ };
+
+ /**
+ * @brief Factory function to create a filter_range with automatic template deduction.
+ *
+ * This convenience function eliminates the need to explicitly specify template parameters
+ * when creating a filter_range. The template parameters are automatically deduced from
+ * the function arguments.
+ *
+ * @tparam Predicate Automatically deduced predicate type
+ * @tparam Iterator Automatically deduced iterator type
+ *
+ * @param pred Predicate function/functor for filtering elements
+ * @param begin Iterator to the beginning of the range
+ * @param end Iterator to the end of the range
+ *
+ * @return filter_range A filter_range object configured with
+ * the provided predicate and range
+ *
+ * Example usage:
+ * @code
+ * std::vector words = {"hello", "world", "test", "example"};
+ *
+ * // Filter strings longer than 4 characters
+ * auto long_words = LL::make_filter(
+ * [](const std::string& s) { return s.length() > 4; },
+ * words.begin(),
+ * words.end()
+ * );
+ *
+ * // Use with range-based for loop
+ * for (const auto& word : long_words) {
+ * std::cout << word << std::endl; // Prints: hello, world, example
+ * }
+ *
+ * // Use with STL algorithms
+ * auto count = std::distance(long_words.begin(), long_words.end());
+ * std::cout << "Found " << count << " long words." << std::endl;
+ * @endcode
+ *
+ * @note This function is preferred over direct construction of filter_range
+ * for most use cases due to automatic template parameter deduction.
+ */
+ template
+ filter_range make_filter(Predicate pred, Iterator begin, Iterator end)
+ {
+ return filter_range(pred, begin, end);
+ }
+
+ /**
+ * @brief Create a filter_range over an entire container with automatic template deduction.
+ *
+ * This convenience function creates a filtered view over an entire container without
+ * requiring explicit begin() and end() calls. It automatically handles both const and
+ * non-const containers, preserving constness in the resulting iterator types.
+ *
+ * @tparam Predicate Automatically deduced predicate type
+ * @tparam Container Automatically deduced container type (const or non-const)
+ *
+ * @param pred Predicate function/functor for filtering elements
+ * @param container The container to filter (can be const or non-const)
+ *
+ * @return filter_range with appropriate iterator type for the container
+ *
+ * Example usage:
+ * @code
+ * // Non-const container
+ * std::vector numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ * auto evens = LL::make_filter([](int n) { return n % 2 == 0; }, numbers);
+ *
+ * // Const container
+ * const std::list words = {"cat", "elephant", "dog", "hippopotamus"};
+ * auto long_words = LL::make_filter([](const std::string& s) { return s.size() > 3; }, words);
+ *
+ * // Works with any container that supports begin()/end()
+ * std::set values = {1.1, 2.2, 3.3, 4.4, 5.5};
+ * auto large_values = LL::make_filter([](double d) { return d > 3.0; }, values);
+ *
+ * // Use with range-based for loops
+ * for (const auto& word : long_words) {
+ * std::cout << word << " "; // Prints: elephant hippopotamus
+ * }
+ *
+ * // Chain with STL algorithms
+ * auto even_count = std::distance(evens.begin(), evens.end());
+ * std::cout << "Found " << even_count << " even numbers." << std::endl;
+ * @endcode
+ *
+ * @note This overload automatically calls begin() and end() on the container,
+ * making it more convenient than the iterator-based version.
+ * @note The container must remain valid for the lifetime of the returned filter_range.
+ * @note Constness of the container is preserved in the iterator type.
+ */
+ template
+ filter_range()))>
+ make_filter(Predicate pred, Container&& container)
+ {
+ return filter_range()))>(
+ pred, std::begin(container), std::end(container));
+ }
+
+} // namespace LL
#endif // LL_LLSTL_H
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 3f33ad61c54..21b11c53112 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -192,6 +192,9 @@ LLOSInfo::LLOSInfo() :
GetSystemInfo(&si); //if it fails get regular system info
//(Warning: If GetSystemInfo it may result in incorrect information in a WOW64 machine, if the kernel fails to load)
+#pragma warning(push)
+#pragma warning(disable : 4996) // ignore 'deprecated.' GetVersionEx is deprecated
+
// Try calling GetVersionEx using the OSVERSIONINFOEX structure.
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
@@ -210,6 +213,8 @@ LLOSInfo::LLOSInfo() :
}
}
+#pragma warning(pop)
+
S32 ubr = 0; // Windows 10 Update Build Revision, can be retrieved from a registry
if (mMajorVer == 10)
{
@@ -1323,7 +1328,7 @@ bool gunzip_file(const std::string& srcfile, const std::string& dstfile)
S32 bytes = 0;
tmpfile = dstfile + ".t";
#ifdef LL_WINDOWS
- llutf16string utf16filename = utf8str_to_utf16str(srcfile);
+ std::wstring utf16filename = ll_convert(srcfile);
src = gzopen_w(utf16filename.c_str(), "rb");
#else
src = gzopen(srcfile.c_str(), "rb");
@@ -1367,7 +1372,7 @@ bool gzip_file(const std::string& srcfile, const std::string& dstfile)
tmpfile = dstfile + ".t";
#ifdef LL_WINDOWS
- llutf16string utf16filename = utf8str_to_utf16str(tmpfile);
+ std::wstring utf16filename = ll_convert(tmpfile);
dst = gzopen_w(utf16filename.c_str(), "wb");
#else
dst = gzopen(tmpfile.c_str(), "wb");
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 034e3f78974..1a1d06a6fd7 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -452,7 +452,9 @@ ElementT LLThreadSafeQueue::pop(void)
// so we can finish draining the queue.
pop_result popped = pop_(lock1, value);
if (popped == POPPED)
- return std::move(value);
+ // don't use std::move when returning local value because
+ // it prevents the compiler from optimizing with copy elision
+ return value;
// Once the queue is DONE, there will never be any more coming.
if (popped == DONE)
diff --git a/indra/llcommon/tests/stringize_test.cpp b/indra/llcommon/tests/stringize_test.cpp
index a3ce7f8e3dd..3f990415924 100644
--- a/indra/llcommon/tests/stringize_test.cpp
+++ b/indra/llcommon/tests/stringize_test.cpp
@@ -110,6 +110,17 @@ namespace tut
void stringize_object::test<3>()
{
//Tests rely on validity of wstring_to_utf8str()
+#if LL_WINDOWS // Windows wstring is a 2byte UTF16 type
+ ensure_equals(ll_convert(wstringize(c)), ll_convert(std::wstring(L"c")));
+ ensure_equals(ll_convert(wstringize(s)), ll_convert(std::wstring(L"17")));
+ ensure_equals(ll_convert(wstringize(i)), ll_convert(std::wstring(L"34")));
+ ensure_equals(ll_convert(wstringize(l)), ll_convert(std::wstring(L"68")));
+ ensure_equals(ll_convert(wstringize(f)), ll_convert(std::wstring(L"3.14159")));
+ ensure_equals(ll_convert(wstringize(d)), ll_convert(std::wstring(L"3.14159")));
+ ensure_equals(ll_convert(wstringize(abc)), ll_convert(std::wstring(L"abc def")));
+ ensure_equals(ll_convert(wstringize(abc)), ll_convert(wstringize(abc.c_str())));
+ ensure_equals(ll_convert(wstringize(def)), ll_convert(std::wstring(L"def ghi")));
+#else
ensure_equals(wstring_to_utf8str(wstringize(c)), wstring_to_utf8str(L"c"));
ensure_equals(wstring_to_utf8str(wstringize(s)), wstring_to_utf8str(L"17"));
ensure_equals(wstring_to_utf8str(wstringize(i)), wstring_to_utf8str(L"34"));
@@ -119,6 +130,7 @@ namespace tut
ensure_equals(wstring_to_utf8str(wstringize(abc)), wstring_to_utf8str(L"abc def"));
ensure_equals(wstring_to_utf8str(wstringize(abc)), wstring_to_utf8str(wstringize(abc.c_str())));
ensure_equals(wstring_to_utf8str(wstringize(def)), wstring_to_utf8str(L"def ghi"));
+#endif
// ensure_equals(wstring_to_utf8str(wstringize(llsd)), wstring_to_utf8str(L"{'abc':'abc def','d':r3.14159,'i':i34}"));
}
} // namespace tut
diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt
index 05b788a4338..fa37d231263 100644
--- a/indra/llcorehttp/CMakeLists.txt
+++ b/indra/llcorehttp/CMakeLists.txt
@@ -12,6 +12,7 @@ include(LLAddBuildTest)
include(LLCommon)
include(Tut)
include(bugsplat)
+include(websocketpp)
set(llcorehttp_SOURCE_FILES
bufferarray.cpp
@@ -23,6 +24,8 @@ set(llcorehttp_SOURCE_FILES
httprequest.cpp
httpresponse.cpp
httpstats.cpp
+ llwebsocketmgr.cpp
+ lljsonrpcws.cpp
_httplibcurl.cpp
_httpopcancel.cpp
_httpoperation.cpp
@@ -51,6 +54,8 @@ set(llcorehttp_HEADER_FILES
httprequest.h
httpresponse.h
httpstats.h
+ llwebsocketmgr.h
+ lljsonrpcws.h
_httpinternal.h
_httplibcurl.h
_httpopcancel.h
@@ -85,6 +90,7 @@ target_link_libraries(
ll::libcurl
ll::openssl
ll::nghttp2
+ ll::websocketpp
)
target_include_directories( llcorehttp INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
# llmessage depends on llcorehttp, yet llcorehttp also depends on llmessage (at least for includes).
@@ -131,7 +137,7 @@ if (LL_TESTS AND LLCOREHTTP_TESTS)
${PYTHON_EXECUTABLE}
"${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llcorehttp_peer.py"
)
-
+
#
# Example Programs
#
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index 6186e7a308b..081a4d9bac9 100644
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -538,6 +538,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
long sslHostV(0L);
long dnsCacheTimeout(-1L);
long nobody(0L);
+ curl_off_t lastModified(0L);
if (mReqOptions)
{
@@ -546,6 +547,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
sslHostV = mReqOptions->getSSLVerifyHost() ? 2L : 0L;
dnsCacheTimeout = mReqOptions->getDNSCacheTimeout();
nobody = mReqOptions->getHeadersOnly() ? 1L : 0L;
+ lastModified = (curl_off_t)mReqOptions->getLastModified();
}
check_curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect);
@@ -554,6 +556,17 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
check_curl_easy_setopt(mCurlHandle, CURLOPT_NOBODY, nobody);
+ if (lastModified)
+ {
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
+#if (LIBCURL_VERSION_NUM >= 0x073B00)
+ // requires curl 7.59.0
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEVALUE_LARGE, lastModified);
+#else
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEVALUE, (long)lastModified);
+#endif
+ }
+
// The Linksys WRT54G V5 router has an issue with frequent
// DNS lookups from LAN machines. If they happen too often,
// like for every HTTP request, the router gets annoyed after
diff --git a/indra/llcorehttp/examples/http_texture_load.cpp b/indra/llcorehttp/examples/http_texture_load.cpp
index 72e0c29a243..986e675d00e 100644
--- a/indra/llcorehttp/examples/http_texture_load.cpp
+++ b/indra/llcorehttp/examples/http_texture_load.cpp
@@ -52,8 +52,6 @@
void init_curl();
void term_curl();
-void ssl_thread_id_callback(CRYPTO_THREADID*);
-void ssl_locking_callback(int mode, int type, const char * file, int line);
void usage(std::ostream & out);
// Default command line settings
@@ -606,63 +604,15 @@ void WorkingSet::loadAssetUuids(FILE * in)
}
-int ssl_mutex_count(0);
-LLCoreInt::HttpMutex ** ssl_mutex_list = NULL;
-
void init_curl()
{
curl_global_init(CURL_GLOBAL_ALL);
-
- ssl_mutex_count = CRYPTO_num_locks();
- if (ssl_mutex_count > 0)
- {
- ssl_mutex_list = new LLCoreInt::HttpMutex * [ssl_mutex_count];
-
- for (int i(0); i < ssl_mutex_count; ++i)
- {
- ssl_mutex_list[i] = new LLCoreInt::HttpMutex;
- }
-
- CRYPTO_set_locking_callback(ssl_locking_callback);
- CRYPTO_THREADID_set_callback(ssl_thread_id_callback);
- }
}
void term_curl()
{
- CRYPTO_set_locking_callback(NULL);
- for (int i(0); i < ssl_mutex_count; ++i)
- {
- delete ssl_mutex_list[i];
- }
- delete [] ssl_mutex_list;
-}
-
-
-void ssl_thread_id_callback(CRYPTO_THREADID* pthreadid)
-{
-#if defined(WIN32)
- CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread());
-#else
- CRYPTO_THREADID_set_pointer(pthreadid, pthread_self());
-#endif
-}
-
-
-void ssl_locking_callback(int mode, int type, const char * /* file */, int /* line */)
-{
- if (type >= 0 && type < ssl_mutex_count)
- {
- if (mode & CRYPTO_LOCK)
- {
- ssl_mutex_list[type]->lock();
- }
- else
- {
- ssl_mutex_list[type]->unlock();
- }
- }
+ curl_global_cleanup();
}
diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp
index d85f6039b1c..5abd28e2112 100644
--- a/indra/llcorehttp/httpoptions.cpp
+++ b/indra/llcorehttp/httpoptions.cpp
@@ -47,6 +47,7 @@ HttpOptions::HttpOptions() :
mVerifyPeer(sDefaultVerifyPeer),
mVerifyHost(false),
mDNSCacheTimeout(-1L),
+ mLastModified(0),
mNoBody(false)
{}
@@ -129,6 +130,11 @@ void HttpOptions::setHeadersOnly(bool nobody)
}
}
+void HttpOptions::setLastModified(time_t lastModified)
+{
+ mLastModified = lastModified;
+}
+
void HttpOptions::setDefaultSSLVerifyPeer(bool verify)
{
sDefaultVerifyPeer = verify;
diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h
index 56a28013cb4..fdb277c66ef 100644
--- a/indra/llcorehttp/httpoptions.h
+++ b/indra/llcorehttp/httpoptions.h
@@ -178,6 +178,13 @@ class HttpOptions : private boost::noncopyable
return mNoBody;
}
+ // Default: 0
+ void setLastModified(time_t lastModified);
+ time_t getLastModified() const
+ {
+ return mLastModified;
+ }
+
/// Sets default behavior for verifying that the name in the
/// security certificate matches the name of the host contacted.
/// Defaults false if not set, but should be set according to
@@ -199,6 +206,7 @@ class HttpOptions : private boost::noncopyable
bool mVerifyHost;
int mDNSCacheTimeout;
bool mNoBody;
+ time_t mLastModified;
static bool sDefaultVerifyPeer;
}; // end class HttpOptions
diff --git a/indra/llcorehttp/llhttpconstants.cpp b/indra/llcorehttp/llhttpconstants.cpp
index 40d6c7506c2..7a671543d93 100755
--- a/indra/llcorehttp/llhttpconstants.cpp
+++ b/indra/llcorehttp/llhttpconstants.cpp
@@ -100,6 +100,7 @@ const std::string HTTP_IN_HEADER_LOCATION("location");
const std::string HTTP_IN_HEADER_RETRY_AFTER("retry-after");
const std::string HTTP_IN_HEADER_SET_COOKIE("set-cookie");
const std::string HTTP_IN_HEADER_USER_AGENT("user-agent");
+const std::string HTTP_IN_HEADER_X_CONTENT_TYPE_OPTIONS("x-content-type-options");
const std::string HTTP_IN_HEADER_X_FORWARDED_FOR("x-forwarded-for");
const std::string HTTP_CONTENT_LLSD_XML("application/llsd+xml");
@@ -122,6 +123,7 @@ const std::string HTTP_CONTENT_IMAGE_BMP("image/bmp");
const std::string HTTP_NO_CACHE("no-cache");
const std::string HTTP_NO_CACHE_CONTROL("no-cache, max-age=0");
+const std::string HTTP_NOSNIFF("nosniff");
const std::string HTTP_VERB_INVALID("(invalid)");
const std::string HTTP_VERB_HEAD("HEAD");
diff --git a/indra/llcorehttp/llhttpconstants.h b/indra/llcorehttp/llhttpconstants.h
index 583f9fbcb77..71c1dfa1730 100755
--- a/indra/llcorehttp/llhttpconstants.h
+++ b/indra/llcorehttp/llhttpconstants.h
@@ -190,6 +190,7 @@ extern const std::string HTTP_IN_HEADER_LOCATION;
extern const std::string HTTP_IN_HEADER_RETRY_AFTER;
extern const std::string HTTP_IN_HEADER_SET_COOKIE;
extern const std::string HTTP_IN_HEADER_USER_AGENT;
+extern const std::string HTTP_IN_HEADER_X_CONTENT_TYPE_OPTIONS;
extern const std::string HTTP_IN_HEADER_X_FORWARDED_FOR;
//// HTTP Content Types ////
@@ -215,5 +216,6 @@ extern const std::string HTTP_CONTENT_IMAGE_BMP;
//// HTTP Cache Settings ////
extern const std::string HTTP_NO_CACHE;
extern const std::string HTTP_NO_CACHE_CONTROL;
+extern const std::string HTTP_NOSNIFF;
#endif
diff --git a/indra/llcorehttp/lljsonrpcws.cpp b/indra/llcorehttp/lljsonrpcws.cpp
new file mode 100644
index 00000000000..93e38a8397c
--- /dev/null
+++ b/indra/llcorehttp/lljsonrpcws.cpp
@@ -0,0 +1,628 @@
+/**
+ * @file lljsonrpcws.cpp
+ * @brief JSON-RPC 2.0 WebSocket server and connection implementation
+ *
+ * $LicenseInfo:firstyear=2025&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2025, 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 "lljsonrpcws.h"
+#include "llerror.h"
+#include "llsdjson.h"
+#include "lldate.h"
+
+#include
+
+//========================================================================
+// LLJSONRPCConnection Implementation
+//========================================================================
+
+void LLJSONRPCConnection::onOpen()
+{
+ LL_INFOS("JSONRPC") << "JSON-RPC connection opened" << LL_ENDL;
+}
+
+void LLJSONRPCConnection::onClose()
+{
+ LL_INFOS("JSONRPC") << "JSON-RPC connection closed, clearing "
+ << mPendingRequests.size() << " pending requests" << LL_ENDL;
+
+ // Cancel all pending requests
+ for (auto& [id, callback] : mPendingRequests)
+ {
+ if (callback)
+ {
+ LLSD error;
+ error["code"] = RPCError::CONNECTION_CLOSED; // Use named constant instead of magic number
+ error["message"] = "Connection closed";
+ callback(LLSD(), error);
+ }
+ }
+ mPendingRequests.clear();
+}
+
+void LLJSONRPCConnection::onMessage(const std::string& message)
+{
+ LL_DEBUGS("JSONRPC") << "Received JSON-RPC message: " << message << LL_ENDL;
+
+ try
+ {
+ // Parse JSON message
+ boost::system::error_code ec;
+ boost::json::value json_value = boost::json::parse(message, ec);
+
+ if (ec.failed())
+ {
+ LL_WARNS("JSONRPC") << "Failed to parse JSON: " << ec.message() << LL_ENDL;
+ sendError(LLSD(), ParseError(ec.message()));
+ return;
+ }
+
+ // Convert to LLSD
+ LLSD message_obj = LlsdFromJson(json_value);
+
+ // Handle batch vs single message
+ if (message_obj.isArray())
+ {
+ // Batch request
+ if (message_obj.size() == 0)
+ {
+ sendError(LLSD(), InvalidRequest("Empty batch"));
+ return;
+ }
+
+ // Process each message in the batch
+ for (S32 i = 0; i < message_obj.size(); ++i)
+ {
+ processMessage(message_obj[i]);
+ }
+ }
+ else
+ {
+ // Single message
+ processMessage(message_obj);
+ }
+ }
+ catch (const std::exception& e)
+ {
+ LL_WARNS("JSONRPC") << "Exception processing JSON-RPC message: " << e.what() << LL_ENDL;
+ sendError(LLSD(), InternalError(e.what()));
+ }
+}
+
+void LLJSONRPCConnection::processMessage(const LLSD& message_obj)
+{
+ try
+ {
+ // Determine if this is a request, notification, or response
+ if (message_obj.has("method"))
+ {
+ // This is a request or notification
+ if (validateMessage(message_obj, true))
+ {
+ processRequest(message_obj);
+ }
+ }
+ else if (message_obj.has("result") || message_obj.has("error"))
+ {
+ // This is a response
+ if (validateMessage(message_obj, false))
+ {
+ processResponse(message_obj);
+ }
+ }
+ else
+ {
+ LL_WARNS("JSONRPC") << "Message must contain 'method' or 'result'/'error'" << LL_ENDL;
+ }
+ }
+ catch (const RPCError& e)
+ {
+ LLSD id = message_obj.has("id") ? message_obj["id"] : LLSD();
+ sendError(id, e);
+ }
+}
+
+void LLJSONRPCConnection::processRequest(const LLSD& request)
+{
+ std::string method = request["method"].asString();
+ LLSD params = request.has("params") ? request["params"] : LLSD();
+ LLSD id = request.has("id") ? request["id"] : LLSD();
+ bool is_notification = !request.has("id");
+
+ LL_DEBUGS("JSONRPC") << "Processing " << (is_notification ? "notification" : "request")
+ << " for method: " << method << LL_ENDL;
+
+ // Find method handler
+ auto it = mMethodHandlers.find(method);
+ if (it == mMethodHandlers.end())
+ {
+ if (!is_notification)
+ {
+ sendError(id, MethodNotFound(method));
+ }
+ return;
+ }
+
+ try
+ {
+ // Call the method handler with method name, ID, and parameters
+ LLSD result = it->second(method, id, params);
+
+ if (!is_notification)
+ {
+ sendResponse(id, result);
+ }
+ }
+ catch (const RPCError& e)
+ {
+ if (!is_notification)
+ {
+ sendError(id, e);
+ }
+ else
+ {
+ LL_WARNS("JSONRPC") << "Error in notification handler for " << method
+ << ": " << e.what() << LL_ENDL;
+ }
+ }
+ catch (const std::exception& e)
+ {
+ if (!is_notification)
+ {
+ sendError(id, InternalError(e.what()));
+ }
+ else
+ {
+ LL_WARNS("JSONRPC") << "Exception in notification handler for " << method
+ << ": " << e.what() << LL_ENDL;
+ }
+ }
+}
+
+void LLJSONRPCConnection::processResponse(const LLSD& response)
+{
+ if (!response.has("id"))
+ {
+ LL_WARNS("JSONRPC") << "Response missing id field" << LL_ENDL;
+ return;
+ }
+
+ std::string id = response["id"].asString();
+ auto it = mPendingRequests.find(id);
+ if (it == mPendingRequests.end())
+ {
+ LL_WARNS("JSONRPC") << "Received response for unknown request id: " << id << LL_ENDL;
+ return;
+ }
+
+ ResponseCallback callback = it->second;
+ mPendingRequests.erase(it);
+
+ if (callback)
+ {
+ LLSD result = response.has("result") ? response["result"] : LLSD();
+ LLSD error = response.has("error") ? response["error"] : LLSD();
+
+ callback(result, error);
+ }
+}
+
+bool LLJSONRPCConnection::validateMessage(const LLSD& message, bool is_request)
+{
+ // Check JSON-RPC version
+ if (!message.has("jsonrpc") || message["jsonrpc"].asString() != "2.0")
+ {
+ LL_WARNS("JSONRPC") << "Missing or invalid jsonrpc version" << LL_ENDL;
+ return false;
+ }
+
+ if (is_request)
+ {
+ // Request/notification validation
+ if (!message.has("method"))
+ {
+ LL_WARNS("JSONRPC") << "Missing method field" << LL_ENDL;
+ return false;
+ }
+
+ if (!message["method"].isString())
+ {
+ LL_WARNS("JSONRPC") << "Method must be a string" << LL_ENDL;
+ return false;
+ }
+
+ // Params are optional but must be array or object if present
+ if (message.has("params"))
+ {
+ if (!message["params"].isArray() && !message["params"].isMap())
+ {
+ LL_WARNS("JSONRPC") << "Params must be array or object" << LL_ENDL;
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // Response validation
+ if (!message.has("id"))
+ {
+ LL_WARNS("JSONRPC") << "Response missing id field" << LL_ENDL;
+ return false;
+ }
+
+ // Must have either result or error, but not both
+ bool has_result = message.has("result");
+ bool has_error = message.has("error");
+
+ if (!has_result && !has_error)
+ {
+ LL_WARNS("JSONRPC") << "Response must have result or error" << LL_ENDL;
+ return false;
+ }
+
+ if (has_result && has_error)
+ {
+ LL_WARNS("JSONRPC") << "Response cannot have both result and error" << LL_ENDL;
+ return false;
+ }
+
+ // Error must be an object with code and message
+ if (has_error)
+ {
+ LLSD error = message["error"];
+ if (!error.isMap())
+ {
+ LL_WARNS("JSONRPC") << "Error must be an object" << LL_ENDL;
+ }
+ if (!error.has("code") || !error.has("message"))
+ {
+ LL_WARNS("JSONRPC") << "Error must have code and message" << LL_ENDL;
+ }
+ }
+ }
+ return true;
+}
+
+LLSD LLJSONRPCConnection::generateId()
+{
+ // Server-wide atomic counter for efficient unique ID generation
+ // Start from 1000 to avoid conflicts with any manual test IDs
+ static std::atomic sRequestIdCounter{1000};
+
+ // Generate server-unique sequential ID
+ U64 id = sRequestIdCounter.fetch_add(1);
+ return LLSD(llformat("rpc_%llu", id));
+}
+
+void LLJSONRPCConnection::registerMethod(const std::string& method, MethodHandler handler)
+{
+ mMethodHandlers[method] = handler;
+ LL_DEBUGS("JSONRPC") << "Registered method: " << method << LL_ENDL;
+}
+
+void LLJSONRPCConnection::unregisterMethod(const std::string& method)
+{
+ mMethodHandlers.erase(method);
+ LL_DEBUGS("JSONRPC") << "Unregistered method: " << method << LL_ENDL;
+}
+
+LLSD LLJSONRPCConnection::call(const std::string& method, const LLSD& params, ResponseCallback callback)
+{
+ LLSD request;
+ request["jsonrpc"] = "2.0";
+ request["method"] = method;
+
+ if (!params.isUndefined())
+ {
+ request["params"] = params;
+ }
+
+ LLSD id = generateId();
+ request["id"] = id;
+
+ // Store callback if provided
+ if (callback)
+ {
+ mPendingRequests[id.asString()] = callback;
+ }
+
+ // Send the request
+ if (!sendMessage(LlsdToJson(request)))
+ {
+ // Remove from pending if send failed
+ if (callback)
+ {
+ mPendingRequests.erase(id.asString());
+ }
+ LL_WARNS("JSONRPC") << "Failed to send request" << LL_ENDL;
+ return LLSD();
+ }
+
+ LL_DEBUGS("JSONRPC") << "Sent request: " << method << " with id: " << id.asString() << LL_ENDL;
+ return id;
+}
+
+bool LLJSONRPCConnection::notify(const std::string& method, const LLSD& params)
+{
+ LLSD notification;
+ notification["jsonrpc"] = "2.0";
+ notification["method"] = method;
+
+ if (!params.isUndefined())
+ {
+ notification["params"] = params;
+ }
+
+ // Notifications don't have an id
+
+ if (!sendMessage(LlsdToJson(notification)))
+ {
+ LL_WARNS("JSONRPC") << "Failed to send notification" << LL_ENDL;
+ return false;
+ }
+
+ LL_DEBUGS("JSONRPC") << "Sent notification: " << method << LL_ENDL;
+ return true;
+}
+
+bool LLJSONRPCConnection::sendResponse(const LLSD& id, const LLSD& result)
+{
+ LLSD response;
+ response["jsonrpc"] = "2.0";
+ response["result"] = result;
+ response["id"] = id;
+
+ if (!sendMessage(LlsdToJson(response)))
+ {
+ LL_WARNS("JSONRPC") << "Failed to send response for id: " << id.asString() << LL_ENDL;
+ return false;
+ }
+ LL_DEBUGS("JSONRPC") << "Sent response for id: " << id.asString() << LL_ENDL;
+ return true;
+}
+
+bool LLJSONRPCConnection::sendError(const LLSD& id, const RPCError& error)
+{
+ LLSD response;
+ response["jsonrpc"] = "2.0";
+
+ LLSD error_obj;
+ error_obj["code"] = error.getCode();
+ error_obj["message"] = error.what();
+
+ if (!error.getData().isUndefined())
+ {
+ error_obj["data"] = error.getData();
+ }
+
+ response["error"] = error_obj;
+ response["id"] = id.isUndefined() ? LLSD() : id; // null for parse errors
+
+ if (!sendMessage(LlsdToJson(response)))
+ {
+ LL_WARNS("JSONRPC") << "Failed to send error response" << LL_ENDL;
+ return false;
+ }
+ LL_DEBUGS("JSONRPC") << "Sent error response: " << error.what() << LL_ENDL;
+ return true;
+}
+
+bool LLJSONRPCConnection::sendBatch(const LLSD& batch, ResponseCallback callback)
+{
+ if (!batch.isArray() || batch.size() == 0)
+ {
+ LL_WARNS("JSONRPC") << "Batch must be non-empty array" << LL_ENDL;
+ return false;
+ }
+
+ // For batch requests with callbacks, we need to track multiple responses
+ // This is complex as we need to correlate all responses before calling callback
+ // For now, we'll send the batch but won't support batch response callbacks
+ if (callback)
+ {
+ LL_WARNS("JSONRPC") << "Batch response callbacks not yet implemented" << LL_ENDL;
+ }
+
+ if (!sendMessage(LlsdToJson(batch)))
+ {
+ LL_WARNS("JSONRPC") << "Failed to send batch" << LL_ENDL;
+ return false;
+ }
+
+ LL_DEBUGS("JSONRPC") << "Sent batch with " << batch.size() << " messages" << LL_ENDL;
+ return true;
+}
+
+//========================================================================
+// LLJSONRPCServer Implementation
+//========================================================================
+
+LLJSONRPCServer::LLJSONRPCServer(const std::string& name, U16 port, bool local_only)
+ : LLWebsocketMgr::WSServer(name, port, local_only), mServerName(name)
+{
+ LL_INFOS("JSONRPC") << "Created JSON-RPC server: " << name
+ << " on port " << port << LL_ENDL;
+
+ // Register standard JSON-RPC methods
+ registerGlobalMethod("system.listMethods", [this](const std::string& method, const LLSD& id, const LLSD& params) -> LLSD {
+ LL_DEBUGS("JSONRPC") << "System method " << method << " called" << LL_ENDL;
+ return getMethodList();
+ });
+
+ registerGlobalMethod("system.getStats", [this](const std::string& method, const LLSD& id, const LLSD& params) -> LLSD {
+ LL_DEBUGS("JSONRPC") << "System method " << method << " called" << LL_ENDL;
+ return getServerStats();
+ });
+
+ registerGlobalMethod("system.ping", [](const std::string& method, const LLSD& id, const LLSD& params) -> LLSD {
+ LL_DEBUGS("JSONRPC") << "System method " << method << " called" << LL_ENDL;
+ LLSD result;
+ result["pong"] = LLDate::now().asString();
+ result["params"] = params;
+ return result;
+ });
+}
+
+LLWebsocketMgr::WSConnection::ptr_t LLJSONRPCServer::connectionFactory(LLWebsocketMgr::WSServer::ptr_t server,
+ LLWebsocketMgr::connection_h handle)
+{
+ auto connection = std::make_shared(server, handle);
+ setupConnectionMethods(connection);
+ return connection;
+}
+
+void LLJSONRPCServer::onConnectionOpened(const LLWebsocketMgr::WSConnection::ptr_t& connection)
+{
+ LL_INFOS("JSONRPC") << "JSON-RPC client connected, total connections: "
+ << getConnectionCount() << LL_ENDL;
+}
+
+void LLJSONRPCServer::onConnectionClosed(const LLWebsocketMgr::WSConnection::ptr_t& connection)
+{
+ LL_INFOS("JSONRPC") << "JSON-RPC client disconnected, total connections: "
+ << getConnectionCount() << LL_ENDL;
+}
+
+void LLJSONRPCServer::setupConnectionMethods(LLJSONRPCConnection::ptr_t connection)
+{
+ LLMutexLock lock(&mGlobalMethodsMutex);
+
+ // Register all global methods on the new connection
+ for (const auto& [method, handler] : mGlobalMethods)
+ {
+ connection->registerMethod(method, handler);
+ }
+}
+
+void LLJSONRPCServer::registerGlobalMethod(const std::string& method, MethodHandler handler)
+{
+ {
+ LLMutexLock lock(&mGlobalMethodsMutex);
+ mGlobalMethods[method] = handler;
+ }
+
+ // Apply to all existing connections - we need to iterate through connections
+ // Since mConnections is private, we need to use broadcastMessage or find another approach
+ // For now, we'll only apply to new connections
+
+ LL_INFOS("JSONRPC") << "Registered global method: " << method << LL_ENDL;
+}
+
+void LLJSONRPCServer::unregisterGlobalMethod(const std::string& method)
+{
+ {
+ LLMutexLock lock(&mGlobalMethodsMutex);
+ mGlobalMethods.erase(method);
+ }
+
+ // For existing connections, we would need access to them
+ // This is a limitation of the current design - methods added after connection
+ // establishment won't be retroactively applied
+
+ LL_INFOS("JSONRPC") << "Unregistered global method: " << method << LL_ENDL;
+}
+
+LLSD LLJSONRPCServer::getMethodList() const
+{
+ LLMutexLock lock(&mGlobalMethodsMutex);
+
+ LLSD methods = LLSD::emptyArray();
+ for (const auto& [method, handler] : mGlobalMethods)
+ {
+ methods.append(method);
+ }
+
+ return methods;
+}
+
+void LLJSONRPCServer::broadcastNotification(const std::string& method, const LLSD& params)
+{
+ // Use custom broadcast logic since we need to call notify() on each JSON-RPC connection
+ // We can't use the base broadcastMessage() because we need structured JSON-RPC messages
+
+ // Create the notification message
+ LLSD notification;
+ notification["jsonrpc"] = "2.0";
+ notification["method"] = method;
+ if (!params.isUndefined())
+ {
+ notification["params"] = params;
+ }
+
+ // Use the base class broadcast functionality
+ broadcastMessage(boost::json::serialize(LlsdToJson(notification)));
+
+ mTotalNotificationsSent += getConnectionCount();
+ LL_DEBUGS("JSONRPC") << "Broadcast notification: " << method
+ << " to " << getConnectionCount() << " clients" << LL_ENDL;
+}
+
+void LLJSONRPCServer::broadcastCall(const std::string& method, const LLSD& params,
+ BatchResponseCallback callback)
+{
+ if (callback)
+ {
+ LL_WARNS("JSONRPC") << "Broadcast call response callbacks not yet implemented" << LL_ENDL;
+ }
+
+ // Create the request message with a server-unique ID
+ LLSD request;
+ request["jsonrpc"] = "2.0";
+ request["method"] = method;
+
+ // Use the same ID generation as connections for consistency
+ static std::atomic sBroadcastIdCounter{10000000}; // Start at 10M to clearly distinguish from regular requests
+ U64 id = sBroadcastIdCounter.fetch_add(1);
+ request["id"] = LLSD(llformat("broadcast_%llu", id));
+
+ if (!params.isUndefined())
+ {
+ request["params"] = params;
+ }
+
+ // Use the base class broadcast functionality
+ broadcastMessage(boost::json::serialize(LlsdToJson(request)));
+
+ LL_DEBUGS("JSONRPC") << "Broadcast call: " << method
+ << " to " << getConnectionCount() << " clients" << LL_ENDL;
+}
+
+LLSD LLJSONRPCServer::getServerStats() const
+{
+ LLSD stats;
+ stats["server_name"] = mServerName;
+ stats["connection_count"] = static_cast(getConnectionCount());
+ stats["is_running"] = isRunning();
+
+ {
+ LLMutexLock lock(&mGlobalMethodsMutex);
+ stats["global_method_count"] = static_cast(mGlobalMethods.size());
+ }
+
+ stats["total_requests_handled"] = static_cast(mTotalRequestsHandled.load());
+ stats["total_notifications_sent"] = static_cast(mTotalNotificationsSent.load());
+ stats["uptime"] = LLDate::now().asString();
+
+ return stats;
+}
diff --git a/indra/llcorehttp/lljsonrpcws.h b/indra/llcorehttp/lljsonrpcws.h
new file mode 100644
index 00000000000..bd9939aa339
--- /dev/null
+++ b/indra/llcorehttp/lljsonrpcws.h
@@ -0,0 +1,461 @@
+/**
+ * @file lljsonrpcws.h
+ * @brief JSON-RPC 2.0 WebSocket server and connection implementation
+ *
+ * $LicenseInfo:firstyear=2025&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2025, 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$
+ */
+
+#pragma once
+
+#include "llwebsocketmgr.h"
+#include "llsd.h"
+#include "lluuid.h"
+
+#include
+#include
+#include
+
+/**
+ * @class LLJSONRPCConnection
+ * @brief JSON-RPC 2.0 WebSocket connection implementation
+ *
+ * This class implements the JSON-RPC 2.0 protocol over WebSocket connections.
+ * It handles request/response patterns, notifications, method registration,
+ * and error handling according to the JSON-RPC 2.0 specification.
+ *
+ * ## JSON-RPC 2.0 Protocol Features
+ *
+ * - **Requests**: Method calls that expect a response
+ * - **Notifications**: Method calls that do not expect a response
+ * - **Batch Operations**: Multiple requests/notifications in a single message
+ * - **Error Handling**: Standardized error codes and messages
+ * - **ID Correlation**: Request/response correlation using unique identifiers
+ *
+ * ## Method Handler Registration
+ *
+ * Methods use an enhanced handler signature that provides method name and request ID context:
+ *
+ * @code
+ * connection->registerMethod("echo", [](const std::string& method, const LLSD& id, const LLSD& params) -> LLSD {
+ * LL_INFOS("JSONRPC") << "Method " << method << " called with ID " << id.asString() << LL_ENDL;
+ * return params; // Echo back the parameters
+ * });
+ *
+ * connection->registerMethod("add", [](const std::string& method, const LLSD& id, const LLSD& params) -> LLSD {
+ * if (params.isArray() && params.size() >= 2) {
+ * LL_INFOS("JSONRPC") << "Adding numbers via " << method << LL_ENDL;
+ * return params[0].asReal() + params[1].asReal();
+ * }
+ * throw LLJSONRPCConnection::InvalidParams("Expected array with 2 numbers");
+ * });
+ * @endcode
+ *
+ * The enhanced signature enables:
+ * - Method context awareness for shared handlers
+ * - Request correlation and distributed tracing
+ * - Distinction between notifications (id undefined) and requests
+ * - Enhanced logging and error reporting with context
+ *
+ * ## Making RPC Calls
+ *
+ * @code
+ * // Asynchronous request with callback
+ * LLSD params;
+ * params.append(5);
+ * params.append(3);
+ * connection->call("add", params, [](const LLSD& result, const LLSD& error) {
+ * if (error.isUndefined()) {
+ * LL_INFOS() << "Result: " << result.asReal() << LL_ENDL;
+ * } else {
+ * LL_WARNS() << "Error: " << error["message"].asString() << LL_ENDL;
+ * }
+ * });
+ *
+ * // Fire-and-forget notification
+ * connection->notify("log", LLSD("Server started"));
+ * @endcode
+ */
+class LLJSONRPCConnection : public LLWebsocketMgr::WSConnection
+{
+public:
+ using ptr_t = std::shared_ptr;
+
+ /// Method handler function signature
+ /// @param method The method name that was called
+ /// @param id The request ID (undefined for notifications)
+ /// @param params The parameters passed to the method
+ /// @return The result to return to the caller
+ /// @throw RPCError-derived exceptions for error responses
+ using MethodHandler = std::function;
+
+ /// Response callback function signature
+ /// @param result The result from a successful call (undefined if error occurred)
+ /// @param error The error object if call failed (undefined if successful)
+ using ResponseCallback = std::function;
+
+ /**
+ * @brief JSON-RPC error base class
+ */
+ class RPCError : public std::runtime_error
+ {
+ public:
+ // JSON-RPC 2.0 Standard Error Codes
+ static constexpr S32 PARSE_ERROR = -32700; ///< Invalid JSON was received by the server
+ static constexpr S32 INVALID_REQUEST = -32600; ///< The JSON sent is not a valid Request object
+ static constexpr S32 METHOD_NOT_FOUND = -32601; ///< The method does not exist / is not available
+ static constexpr S32 INVALID_PARAMS = -32602; ///< Invalid method parameter(s)
+ static constexpr S32 INTERNAL_ERROR = -32603; ///< Internal JSON-RPC error
+
+ // Server Error Range (-32000 to -32099)
+ static constexpr S32 SERVER_ERROR_MIN = -32099; ///< Server error range minimum
+ static constexpr S32 SERVER_ERROR_MAX = -32000; ///< Server error range maximum
+
+ // Common server-specific errors
+ static constexpr S32 CONNECTION_CLOSED = -32000; ///< Connection closed unexpectedly
+ static constexpr S32 REQUEST_TIMEOUT = -32001; ///< Request timed out
+ static constexpr S32 UNAUTHORIZED = -32002; ///< Authentication required
+ static constexpr S32 FORBIDDEN = -32003; ///< Access denied
+ static constexpr S32 RATE_LIMITED = -32004; ///< Too many requests
+ static constexpr S32 SERVICE_UNAVAILABLE = -32005; ///< Service temporarily unavailable
+ static constexpr S32 MESSAGE_TOO_LARGE = -32006; ///< Message exceeds maximum size
+ static constexpr S32 INVALID_SESSION = -32007; ///< Session expired or invalid
+
+ RPCError(S32 code, const std::string& message, const LLSD& data = LLSD())
+ : std::runtime_error(message), mCode(code), mData(data) {}
+
+ S32 getCode() const { return mCode; }
+ const LLSD& getData() const { return mData; }
+
+ protected:
+ S32 mCode;
+ LLSD mData;
+ };
+
+ /// Standard JSON-RPC error classes using named constants
+ class ParseError : public RPCError {
+ public:
+ ParseError(const std::string& details = "")
+ : RPCError(PARSE_ERROR, "Parse error" + (details.empty() ? "" : ": " + details)) {}
+ };
+
+ class InvalidRequest : public RPCError {
+ public:
+ InvalidRequest(const std::string& details = "")
+ : RPCError(INVALID_REQUEST, "Invalid Request" + (details.empty() ? "" : ": " + details)) {}
+ };
+
+ class MethodNotFound : public RPCError {
+ public:
+ MethodNotFound(const std::string& method = "")
+ : RPCError(METHOD_NOT_FOUND, "Method not found" + (method.empty() ? "" : ": " + method)) {}
+ };
+
+ class InvalidParams : public RPCError {
+ public:
+ InvalidParams(const std::string& details = "")
+ : RPCError(INVALID_PARAMS, "Invalid params" + (details.empty() ? "" : ": " + details)) {}
+ };
+
+ class InternalError : public RPCError {
+ public:
+ InternalError(const std::string& details = "")
+ : RPCError(INTERNAL_ERROR, "Internal error" + (details.empty() ? "" : ": " + details)) {}
+ };
+
+ /// Server-specific errors (in the -32000 to -32099 range)
+ class ConnectionClosedError : public RPCError {
+ public:
+ ConnectionClosedError(const std::string& details = "Connection closed")
+ : RPCError(CONNECTION_CLOSED, details) {}
+ };
+
+ class RequestTimeoutError : public RPCError {
+ public:
+ RequestTimeoutError(const std::string& details = "Request timed out")
+ : RPCError(REQUEST_TIMEOUT, details) {}
+ };
+
+ class UnauthorizedError : public RPCError {
+ public:
+ UnauthorizedError(const std::string& details = "Authentication required")
+ : RPCError(UNAUTHORIZED, details) {}
+ };
+
+ class ForbiddenError : public RPCError {
+ public:
+ ForbiddenError(const std::string& details = "Access denied")
+ : RPCError(FORBIDDEN, details) {}
+ };
+
+ class RateLimitedError : public RPCError {
+ public:
+ RateLimitedError(const std::string& details = "Too many requests")
+ : RPCError(RATE_LIMITED, details) {}
+ };
+
+ class ServiceUnavailableError : public RPCError {
+ public:
+ ServiceUnavailableError(const std::string& details = "Service temporarily unavailable")
+ : RPCError(SERVICE_UNAVAILABLE, details) {}
+ };
+
+ class MessageTooLargeError : public RPCError {
+ public:
+ MessageTooLargeError(const std::string& details = "Message exceeds maximum size")
+ : RPCError(MESSAGE_TOO_LARGE, details) {}
+ };
+
+ class InvalidSessionError : public RPCError {
+ public:
+ InvalidSessionError(const std::string& details = "Session expired or invalid")
+ : RPCError(INVALID_SESSION, details) {}
+ };
+
+
+ LLJSONRPCConnection(const LLWebsocketMgr::WSServer::ptr_t server,
+ const LLWebsocketMgr::connection_h& handle)
+ : LLWebsocketMgr::WSConnection(server, handle) {}
+
+ virtual ~LLJSONRPCConnection() = default;
+
+ // WebSocket connection lifecycle
+ void onOpen() override;
+ void onClose() override;
+ void onMessage(const std::string& message) override;
+
+ /**
+ * @brief Register a method handler
+ * @param method The method name to register
+ * @param handler The function to call when this method is invoked
+ */
+ void registerMethod(const std::string& method, MethodHandler handler);
+
+ /**
+ * @brief Unregister a method handler
+ * @param method The method name to unregister
+ */
+ void unregisterMethod(const std::string& method);
+
+ /**
+ * @brief Make an asynchronous JSON-RPC call
+ * @param method The method name to call
+ * @param params The parameters to pass
+ * @param callback Callback for the response (optional)
+ * @return The request ID for correlation
+ */
+ LLSD call(const std::string& method, const LLSD& params = LLSD(),
+ ResponseCallback callback = nullptr);
+
+ /**
+ * @brief Send a JSON-RPC notification (no response expected)
+ * @param method The method name
+ * @param params The parameters to pass
+ */
+ bool notify(const std::string& method, const LLSD& params = LLSD());
+
+ /**
+ * @brief Send a successful response to a request
+ * @param id The request ID from the original request
+ * @param result The result to return
+ */
+ bool sendResponse(const LLSD& id, const LLSD& result);
+
+ /**
+ * @brief Send an error response to a request
+ * @param id The request ID from the original request (can be null)
+ * @param error The RPCError to send
+ */
+ bool sendError(const LLSD& id, const RPCError& error);
+
+ /**
+ * @brief Send a batch of requests/notifications
+ * @param batch Array of request/notification objects
+ * @param callback Callback for batch response (optional)
+ */
+ bool sendBatch(const LLSD& batch, ResponseCallback callback = nullptr);
+
+protected:
+ /**
+ * @brief Process a single JSON-RPC message
+ * @param message_obj The parsed JSON message
+ */
+ void processMessage(const LLSD& message_obj);
+
+ /**
+ * @brief Process a JSON-RPC request
+ * @param request The request object
+ */
+ void processRequest(const LLSD& request);
+
+ /**
+ * @brief Process a JSON-RPC response
+ * @param response The response object
+ */
+ void processResponse(const LLSD& response);
+
+ /**
+ * @brief Validate a JSON-RPC message structure
+ * @param message The message to validate
+ * @param is_request True if validating a request, false for response
+ */
+ bool validateMessage(const LLSD& message, bool is_request = true);
+
+ /**
+ * @brief Generate the next unique request ID
+ * @return A server-unique request ID
+ *
+ * Generates a server-wide unique identifier using an atomic counter.
+ * This ensures request IDs are unique across all connections within the
+ * server instance, providing efficient ID generation with guaranteed uniqueness.
+ *
+ * IDs follow the format "rpc_{counter}" where counter is a monotonically
+ * increasing 64-bit value starting from 1. This approach provides:
+ * - Guaranteed uniqueness within server scope
+ * - High performance (atomic increment operation)
+ * - Predictable, sequential ordering for debugging
+ * - Thread-safe generation across multiple connections
+ */
+ LLSD generateId();
+
+private:
+ std::unordered_map mMethodHandlers;
+ std::unordered_map mPendingRequests;
+};
+
+/**
+ * @class LLJSONRPCServer
+ * @brief JSON-RPC 2.0 WebSocket server implementation
+ *
+ * This server extends the basic WebSocket server to provide JSON-RPC 2.0
+ * protocol support. It manages JSON-RPC connections and provides server-wide
+ * method registration and broadcasting capabilities.
+ *
+ * ## Server-Wide Method Registration
+ *
+ * Methods can be registered at the server level and will be available
+ * on all connections:
+ *
+ * @code
+ * auto server = std::make_shared("rpc_server", 8080);
+ *
+ * server->registerGlobalMethod("getServerInfo", [](const std::string& method, const LLSD& id, const LLSD& params) -> LLSD {
+ * LL_INFOS("JSONRPC") << "Server info requested via " << method << LL_ENDL;
+ * LLSD info;
+ * info["name"] = "My RPC Server";
+ * info["version"] = "1.0.0";
+ * info["uptime"] = LLDate::now().secondsSinceEpoch();
+ * return info;
+ * });
+ *
+ * server->registerGlobalMethod("listMethods", [server](const std::string& method, const LLSD& id, const LLSD& params) -> LLSD {
+ * return server->getMethodList();
+ * });
+ * @endcode
+ *
+ * ## Broadcasting and Multi-client Operations
+ *
+ * @code
+ * // Broadcast notification to all connected clients
+ * server->broadcastNotification("serverAlert", LLSD("Server will restart in 5 minutes"));
+ *
+ * // Call a method on all clients and collect responses
+ * server->broadcastCall("getClientStatus", LLSD(), [](const LLSD& responses) {
+ * for (const auto& response : llsd::inArray(responses)) {
+ * LL_INFOS() << "Client status: " << response << LL_ENDL;
+ * }
+ * });
+ * @endcode
+ */
+class LLJSONRPCServer : public LLWebsocketMgr::WSServer
+{
+public:
+ using ptr_t = std::shared_ptr;
+ using MethodHandler = LLJSONRPCConnection::MethodHandler;
+ using ResponseCallback = LLJSONRPCConnection::ResponseCallback;
+ using BatchResponseCallback = std::function;
+
+ LLJSONRPCServer(const std::string& name, U16 port, bool local_only = true);
+ virtual ~LLJSONRPCServer() = default;
+
+ // Server lifecycle callbacks
+ void onConnectionOpened(const LLWebsocketMgr::WSConnection::ptr_t& connection) override;
+ void onConnectionClosed(const LLWebsocketMgr::WSConnection::ptr_t& connection) override;
+
+ /**
+ * @brief Register a global method available on all connections
+ * @param method The method name to register
+ * @param handler The function to call when this method is invoked
+ */
+ void registerGlobalMethod(const std::string& method, MethodHandler handler);
+
+ /**
+ * @brief Unregister a global method
+ * @param method The method name to unregister
+ */
+ void unregisterGlobalMethod(const std::string& method);
+
+ /**
+ * @brief Get list of registered global methods
+ * @return Array of method names
+ */
+ LLSD getMethodList() const;
+
+ /**
+ * @brief Broadcast a notification to all connected clients
+ * @param method The method name
+ * @param params The parameters to pass
+ */
+ void broadcastNotification(const std::string& method, const LLSD& params = LLSD());
+
+ /**
+ * @brief Call a method on all connected clients
+ * @param method The method name
+ * @param params The parameters to pass
+ * @param callback Callback to receive aggregated responses
+ */
+ void broadcastCall(const std::string& method, const LLSD& params = LLSD(),
+ BatchResponseCallback callback = nullptr);
+
+ /**
+ * @brief Get server statistics
+ * @return Statistics object with connection count, method count, etc.
+ */
+ LLSD getServerStats() const;
+
+protected:
+ LLWebsocketMgr::WSConnection::ptr_t connectionFactory(LLWebsocketMgr::WSServer::ptr_t server,
+ LLWebsocketMgr::connection_h handle) override;
+
+ /**
+ * @brief Apply global method handlers to a new connection
+ * @param connection The connection to configure
+ */
+ virtual void setupConnectionMethods(LLJSONRPCConnection::ptr_t connection);
+
+private:
+ std::unordered_map mGlobalMethods;
+ mutable LLMutex mGlobalMethodsMutex;
+
+ std::string mServerName; // Store server name for stats
+ std::atomic mTotalRequestsHandled{0};
+ std::atomic mTotalNotificationsSent{0};
+};
diff --git a/indra/llcorehttp/llwebsocketmgr.cpp b/indra/llcorehttp/llwebsocketmgr.cpp
new file mode 100644
index 00000000000..addd108b71b
--- /dev/null
+++ b/indra/llcorehttp/llwebsocketmgr.cpp
@@ -0,0 +1,660 @@
+/**
+ * @file llwebsocketmgr.cpp
+ * @brief WebSocket manager singleton implementation
+ *
+ * $LicenseInfo:firstyear=2025&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2025, 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 "llwebsocketmgr.h"
+#include "llerror.h"
+#include "llsdserialize.h"
+#include "llhost.h"
+#include "llsdjson.h"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+//------------------------------------------------------------------------
+namespace
+{
+ using Server_t = websocketpp::server;
+ using Client_t = websocketpp::client;
+ using Connection_t = websocketpp::connection;
+}
+
+//------------------------------------------------------------------------
+
+//------------------------------------------------------------------------
+// LLWebsocketMgr Implementation
+//
+
+void LLWebsocketMgr::initSingleton()
+{ }
+
+void LLWebsocketMgr::cleanupSingleton()
+{
+ stopAllServers();
+}
+
+void LLWebsocketMgr::update()
+{
+ std::vector stops;
+
+ for (auto &[name, server] : mServers)
+ {
+ if (server && server->isRunning())
+ {
+ if (!server->update())
+ {
+ stops.push_back(server);
+ }
+ }
+ }
+
+ for (const auto& server : stops)
+ {
+ if (server)
+ {
+ LL_DEBUGS("WebSocket") << "Stopping server: " << server->mServerName << LL_ENDL;
+ removeServer(server->mServerName);
+ }
+ }
+}
+
+
+LLWebsocketMgr::WSServer::ptr_t LLWebsocketMgr::findServerByName(const std::string &name) const
+{
+ auto it = mServers.find(std::string(name));
+ if (it != mServers.end())
+ {
+ return it->second;
+ }
+ return nullptr;
+}
+
+bool LLWebsocketMgr::addServer(const LLWebsocketMgr::WSServer::ptr_t& server)
+{
+ if (!server)
+ {
+ LL_WARNS("WebSocket") << "Attempted to add a null server" << LL_ENDL;
+ return false;
+ }
+
+ auto it = mServers.find(server->mServerName);
+ if (it != mServers.end())
+ {
+ LL_WARNS("WebSocket") << "Server with name " << server->mServerName << " already exists" << LL_ENDL;
+ return false;
+ }
+ mServers[server->mServerName] = server;
+ LL_INFOS("WebSocket") << "Added WebSocket server: " << server->mServerName << LL_ENDL;
+ return true;
+}
+
+bool LLWebsocketMgr::removeServer(const std::string& name)
+{
+ auto it = mServers.find(name);
+ if (it == mServers.end())
+ {
+ LL_WARNS("WebSocket") << "No server found with name " << name << " to remove" << LL_ENDL;
+ return false;
+ }
+ if (it->second && it->second->isRunning())
+ it->second->stop();
+ mServers.erase(it);
+ LL_INFOS("WebSocket") << "Removed WebSocket server: " << name << LL_ENDL;
+ return true;
+}
+
+
+bool LLWebsocketMgr::startServer(const std::string &name) const
+{
+ LLWebsocketMgr::WSServer::ptr_t server = findServerByName(name);
+ if (!server)
+ {
+ LL_WARNS("WebSocket") << "No server found with name " << name << " to start" << LL_ENDL;
+ return false;
+ }
+ if (server->isRunning())
+ {
+ LL_WARNS("WebSocket") << "Server " << name << " is already running" << LL_ENDL;
+ return false;
+ }
+ return server->start();
+}
+
+void LLWebsocketMgr::stopServer(const std::string& name) const
+{
+ LLWebsocketMgr::WSServer::ptr_t server = findServerByName(name);
+ if (!server)
+ {
+ LL_WARNS("WebSocket") << "No server found with name " << name << " to stop" << LL_ENDL;
+ return;
+ }
+ if (!server->isRunning())
+ {
+ LL_WARNS("WebSocket") << "Server " << name << " is not running" << LL_ENDL;
+ return;
+ }
+ server->stop();
+}
+
+void LLWebsocketMgr::stopAllServers()
+{
+ for (auto &[name, server] : mServers)
+ {
+ if (server && server->isRunning())
+ {
+ LL_INFOS("WebSocket") << "Stopping server: " << name << LL_ENDL;
+ server->stop();
+ }
+ }
+
+ mServers.clear();
+}
+
+//------------------------------------------------------------------------
+struct Server_impl
+{
+ Server_impl(LLWebsocketMgr::WSServer *owner, U16 port, bool local_only) :
+ mOwner(owner),
+ mPort(port),
+ mLocalOnly(local_only)
+ {
+
+ mServer.set_open_handler([this](websocketpp::connection_hdl hdl) { this->onOpen(hdl); });
+ mServer.set_close_handler([this](websocketpp::connection_hdl hdl) { this->onClose(hdl); });
+ mServer.set_message_handler([this](websocketpp::connection_hdl hdl, Server_t::message_ptr msg) { this->onMessage(hdl, msg); });
+ }
+
+ ~Server_impl() = default;
+
+ /**
+ * @brief Initialize the websocketpp server and configure listening
+ *
+ * Performs the initial setup of the websocketpp server by calling init_asio()
+ * to initialize the ASIO networking layer, then configures the server to listen
+ * on the specified port. The binding behavior depends on the mLocalOnly flag:
+ * - If mLocalOnly is true: binds to "127.0.0.1" (localhost only)
+ * - If mLocalOnly is false: binds to all available network interfaces
+ */
+ void init()
+ {
+ mServer.init_asio();
+ if (mLocalOnly)
+ {
+ std::stringstream port_str;
+ port_str << mPort;
+ mServer.listen("127.0.0.1", port_str.str());
+ }
+ else
+ {
+ mServer.listen(mPort);
+ }
+ }
+
+ /**
+ * @brief Start the websocket server and begin accepting connections
+ * @return true if server started successfully, false on error
+ */
+ bool start()
+ {
+ //if (!mServer.stopped())
+ //{
+ // LL_WARNS("WebSocket") << "WebSocket server is already running" << LL_ENDL;
+ // return false;
+ //}
+
+ try
+ {
+ LL_INFOS("WebSocket") << "Starting WebSocket server on port " << mPort
+ << (mLocalOnly ? " (localhost only)" : " (all interfaces)") << LL_ENDL;
+ mServer.start_accept();
+
+ // Run controlled event loop with periodic stop flag checking
+ while (!mOwner->mShouldStop && !mServer.stopped())
+ {
+ // Process events for up to 100ms, then check the stop flag
+ std::chrono::milliseconds timeout(100);
+ std::size_t handlers_run = mServer.get_io_service().run_for(timeout);
+
+ // If no handlers were run and the server isn't stopped,
+ // reset the io_service for the next iteration
+ if (handlers_run == 0 && !mServer.stopped() && !mOwner->mShouldStop)
+ {
+ mServer.get_io_service().restart();
+ }
+ }
+
+ LL_INFOS("WebSocket") << "WebSocket server event loop exited cleanly" << LL_ENDL;
+ return true;
+ }
+ catch (const websocketpp::exception& e)
+ {
+ LL_WARNS("WebSocket") << "WebSocket server exception: " << e.what() << LL_ENDL;
+ return false;
+ }
+ catch (const std::exception& e)
+ {
+ LL_WARNS("WebSocket") << "WebSocket server std::exception: " << e.what() << LL_ENDL;
+ return false;
+ }
+ catch (...)
+ {
+ LL_WARNS("WebSocket") << "WebSocket server unknown exception" << LL_ENDL;
+ return false;
+ }
+ }
+
+ void stop()
+ {
+ if (mServer.stopped())
+ {
+ return;
+ }
+ try
+ {
+ mServer.stop_listening();
+ mServer.stop();
+ }
+ catch (const std::exception&)
+ {
+ LL_WARNS("WebSocket") << "Error stopping WebSocket server" << LL_ENDL;
+ }
+ }
+
+ /**
+ * @brief Handle new connection establishment event
+ * @param hdl WebSocket connection handle from websocketpp
+ *
+ * Called automatically by the websocketpp library when a new client connection
+ * is successfully established. This method serves as a bridge between the
+ * low-level websocketpp callback and the high-level WSServer interface.
+ */
+ void onOpen(websocketpp::connection_hdl hdl) const
+ {
+ LL_ERRS_IF(!mOwner, "WebSocket") << "mOwner should never be null. If it is, something is very wrong!" << LL_ENDL;
+
+ mOwner->handleOpenConnection(hdl);
+ }
+
+ /**
+ * @brief Handle connection closure event
+ * @param hdl WebSocket connection handle from websocketpp
+ */
+ void onClose(websocketpp::connection_hdl hdl) const
+ {
+ LL_ERRS_IF(!mOwner, "WebSocket") << "mOwner should never be null" << LL_ENDL;
+ mOwner->handleCloseConnection(hdl);
+ }
+
+ /**
+ * @brief Handle incoming message from client
+ * @param hdl WebSocket connection handle identifying the sender
+ * @param msg Shared pointer to the message object containing payload and metadata
+ *
+ * Called automatically by the websocketpp library when a complete message is
+ * received from a client. This method validates the connection exists, extracts
+ * the message payload, and forwards it to the appropriate connection handler.
+ *
+ * Currently handles text messages only.
+ */
+ void onMessage(websocketpp::connection_hdl hdl, Server_t::message_ptr msg) const
+ {
+ LL_ERRS_IF(!mOwner, "WebSocket") << "mOwner should never be null" << LL_ENDL;
+ LLWebsocketMgr::WSConnection::ptr_t connection = mOwner->getConnection(hdl);
+ if (!connection)
+ {
+ LL_WARNS("WebSocket") << "Received message for unknown connection" << LL_ENDL;
+ return;
+ }
+
+ // TODO: check the FIN bit and handle fragmented messages if needed
+ // TODO: check terminal and close codes and handle connection closure if needed
+ mOwner->handleMessage(hdl, msg->get_payload());
+ }
+
+ //-------------------------------------------
+ Server_t mServer; ///< The underlying websocketpp server instance
+ LLWebsocketMgr::WSServer* mOwner{ nullptr }; ///< Back-reference to the owning WSServer instance (guaranteed non-null)
+ U16 mPort{ 0 }; ///< TCP port number the server listens on
+ bool mLocalOnly{ true }; ///< Whether to bind to localhost only (true) or all interfaces (false)
+};
+
+//------------------------------------------------------------------------
+LLWebsocketMgr::WSServer::WSServer(std::string_view name, U16 port, bool local_only):
+ mServerName(name),
+ mImpl(std::make_unique(this, port, local_only))
+{
+ mImpl->init();
+
+ // Initialize the server with the given name and host
+ LL_INFOS("WebSocket") << "Creating WebSocket server: " << name <<
+ " listening " << (mImpl->mLocalOnly ? "locally" : "ON ALL INTERFACES") <<
+ " on port " << mImpl->mPort << LL_ENDL;
+}
+
+LLWebsocketMgr::WSServer::~WSServer()
+{
+ // Ensure the server is stopped before destruction
+ stop();
+}
+
+LLWebsocketMgr::WSConnection::ptr_t LLWebsocketMgr::WSServer::connectionFactory(LLWebsocketMgr::WSServer::ptr_t server,
+ LLWebsocketMgr::connection_h handle)
+{
+ return std::make_shared(server, handle);
+}
+
+bool LLWebsocketMgr::WSServer::start()
+{
+ LL_ERRS_IF(!mImpl, "WebSocket") << "WebSocket server " << mServerName << " implementation is null !" << LL_ENDL;
+
+ LLMutexLock lock(&mThreadMutex);
+
+ // Check if already running
+ if (isRunning())
+ {
+ LL_WARNS("WebSocket") << "Server " << mServerName << " is already running" << LL_ENDL;
+ return false;
+ }
+
+ // Reset the stop flag
+ mShouldStop = false;
+
+ // Start the server thread
+ mServerThread = std::thread([this]() {
+ LL_INFOS("WebSocket") << "WebSocket server thread starting for: " << mServerName << LL_ENDL;
+
+ // Run the controlled server loop that checks the stop flag
+ // Server_impl accesses mShouldStop through the mOwner pointer
+ bool success = mImpl->start();
+
+ if (!success)
+ {
+ LL_WARNS("WebSocket") << "WebSocket server thread failed to start for: " << mServerName << LL_ENDL;
+ }
+
+ LL_INFOS("WebSocket") << "WebSocket server thread exiting for: " << mServerName << LL_ENDL;
+ });
+
+ onStarted();
+ LL_INFOS("WebSocket") << "Started WebSocket server thread: " << mServerName << LL_ENDL;
+ return true;
+}
+
+void LLWebsocketMgr::WSServer::stop()
+{
+ LL_ERRS_IF(!mImpl, "WebSocket") << "WebSocket server " << mServerName << " implementation is null !" << LL_ENDL;
+
+ {
+ LLMutexLock lock(&mThreadMutex);
+
+ // Check if already stopped
+ if (!isRunning())
+ {
+ return;
+ }
+
+ LL_INFOS("WebSocket") << "Stopping WebSocket server: " << mServerName << LL_ENDL;
+
+ mShouldStop = true;
+
+ // Stop the websocket server (this will cause the controlled run loop to exit)
+ mImpl->stop();
+ } // Release the lock here
+
+ if (mServerThread.joinable())
+ {
+ mServerThread.join();
+ LL_INFOS("WebSocket") << "WebSocket server thread joined for: " << mServerName << LL_ENDL;
+ }
+ onStopped();
+}
+
+bool LLWebsocketMgr::WSServer::isRunning() const
+{
+ LL_ERRS_IF(!mImpl, "WebSocket") << "WebSocket server " << mServerName << " implementation is null !" << LL_ENDL;
+
+ // Check both the thread state, websocket server state, and the stop flag
+ return mServerThread.joinable() && !mImpl->mServer.stopped() && !mShouldStop;
+}
+
+void LLWebsocketMgr::WSServer::broadcastMessage(const std::string& message)
+{
+ LL_ERRS_IF(!mImpl, "WebSocket") << "WebSocket server " << mServerName << " implementation is null !" << LL_ENDL;
+ LLMutexLock lock(&mConnectionMutex);
+ for (const auto& [handle, conn] : mConnections)
+ {
+ sendMessageTo(handle, message);
+ }
+}
+
+bool LLWebsocketMgr::WSServer::sendMessageTo(const connection_h& handle, const std::string& message)
+{
+ LL_ERRS_IF(!mImpl, "WebSocket") << "WebSocket server " << mServerName << " implementation is null !" << LL_ENDL;
+ websocketpp::lib::error_code ec;
+ mImpl->mServer.send(handle, message, websocketpp::frame::opcode::text, ec);
+ if (ec)
+ {
+ LL_WARNS("WebSocket") << mServerName << " failed to send message: " << ec.message() << LL_ENDL;
+ return false;
+ }
+ return true;
+}
+
+bool LLWebsocketMgr::WSServer::closeConnection(const connection_h& handle, U16 code, const std::string& reason)
+{
+ LL_ERRS_IF(!mImpl, "WebSocket") << "WebSocket server " << mServerName << " implementation is null !" << LL_ENDL;
+
+ try
+ {
+ websocketpp::lib::error_code ec;
+ mImpl->mServer.close(handle, code, reason, ec);
+ if (ec)
+ {
+ LL_WARNS("WebSocket") << mServerName << " failed to close connection: " << ec.message() << LL_ENDL;
+ return false;
+ }
+
+ LL_INFOS("WebSocket") << mServerName << " initiated close for connection with code "
+ << code << " and reason: " << reason << LL_ENDL;
+ return true;
+ }
+ catch (const websocketpp::exception& e)
+ {
+ LL_WARNS("WebSocket") << mServerName << " exception closing connection: " << e.what() << LL_ENDL;
+ return false;
+ }
+ catch (const std::exception& e)
+ {
+ LL_WARNS("WebSocket") << mServerName << " std::exception closing connection: " << e.what() << LL_ENDL;
+ return false;
+ }
+ catch (...)
+ {
+ LL_WARNS("WebSocket") << mServerName << " unknown exception closing connection" << LL_ENDL;
+ return false;
+ }
+}
+
+LLWebsocketMgr::WSConnection::ptr_t LLWebsocketMgr::WSServer::getConnection(const connection_h& handle)
+{
+ LLMutexLock lock(&mConnectionMutex);
+ auto it = mConnections.find(handle);
+ if (it != mConnections.end())
+ {
+ return it->second;
+ }
+ return nullptr;
+}
+
+LLWebsocketMgr::connection_state_t LLWebsocketMgr::WSServer::getConnectionState(const connection_h& handle) const
+{
+ websocketpp::lib::error_code ec;
+ auto con = mImpl->mServer.get_con_from_hdl(handle, ec);
+ if (ec)
+ {
+ LL_WARNS("WebSocket") << mServerName << " failed to get connection state: " << ec.message() << LL_ENDL;
+ websocketpp::session::state::value state = websocketpp::session::state::closed;
+ return connection_closed;
+ }
+ return static_cast(con->get_state());
+}
+
+
+void LLWebsocketMgr::WSServer::handleOpenConnection(const connection_h& handle)
+{
+ WSConnection::ptr_t connection;
+ size_t size(0);
+ {
+ LLMutexLock lock(&mConnectionMutex);
+ auto it = mConnections.find(handle);
+ if (it == mConnections.end())
+ {
+ connection = connectionFactory(shared_from_this(), handle);
+ if (!connection)
+ {
+ LL_WARNS("WebSocket") << "Failed to create connection for websocket server " << mServerName << LL_ENDL;
+ return;
+ }
+ mConnections[handle] = connection;
+ }
+ else
+ {
+ connection = it->second;
+ }
+
+ if (!connection)
+ {
+ LL_WARNS("WebSocket") << mServerName << " failed to create connection object" << LL_ENDL;
+ return;
+ }
+ // Removed redundant assignment to mConnections[handle]
+ size = mConnections.size();
+ }
+
+ onConnectionOpened(connection); // TODO: consider letting the server reject the connection here
+ connection->onOpen();
+ LL_INFOS("WebSocket") << mServerName << " opened new connection, total connections: " << size << LL_ENDL;
+}
+
+void LLWebsocketMgr::WSServer::handleCloseConnection(const connection_h& handle)
+{
+ size_t size(0);
+ WSConnection::ptr_t connection;
+ {
+ LLMutexLock lock(&mConnectionMutex);
+ auto it = mConnections.find(handle);
+ if (it != mConnections.end())
+ {
+ connection = it->second;
+ mConnections.erase(it);
+ }
+ size = mConnections.size();
+ }
+ if (connection)
+ {
+ connection->onClose();
+ onConnectionClosed(connection);
+ LL_INFOS("WebSocket") << mServerName << " closed connection, total connections: " << size << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS("WebSocket") << mServerName << " attempted to close unknown connection" << LL_ENDL;
+ }
+}
+
+void LLWebsocketMgr::WSServer::handleMessage(const connection_h& handle, const std::string& message)
+{
+ WSConnection::ptr_t connection = getConnection(handle);
+ if (connection)
+ {
+ connection->onMessage(message);
+ }
+ else
+ {
+ LL_WARNS("WebSocket") << mServerName << " received message for unknown connection" << LL_ENDL;
+ }
+}
+
+//------------------------------------------------------------------------
+bool LLWebsocketMgr::WSConnection::sendMessage(const std::string& message) const
+{
+ if (mOwningServer.expired())
+ {
+ LL_WARNS("WebSocket") << "Attempted to send message on connection with null server reference" << LL_ENDL;
+ return false;
+ }
+ return mOwningServer.lock()->sendMessageTo(mConnectionHandle, message);
+}
+
+bool LLWebsocketMgr::WSConnection::sendMessage(const boost::json::value& json) const
+{
+ std::string message = boost::json::serialize(json);
+ return sendMessage(message);
+}
+
+bool LLWebsocketMgr::WSConnection::sendMessage(const LLSD& data) const
+{
+ return sendMessage(LlsdToJson(data));
+}
+
+void LLWebsocketMgr::WSConnection::closeConnection(U16 code, const std::string& reason)
+{
+ if (mOwningServer.expired())
+ {
+ LL_WARNS("WebSocket") << "Attempted to close connection with null server reference" << LL_ENDL;
+ return;
+ }
+
+ LL_INFOS("WebSocket") << "WSConnection closing connection with code " << code
+ << " and reason: " << (reason.empty() ? "(no reason)" : reason) << LL_ENDL;
+
+ if (!mOwningServer.lock()->closeConnection(mConnectionHandle, code, reason))
+ {
+ LL_WARNS("WebSocket") << "Failed to close connection through server" << LL_ENDL;
+ }
+}
+
+bool LLWebsocketMgr::WSConnection::isConnected() const
+{
+ if (mOwningServer.expired())
+ {
+ return false;
+ }
+
+ LLWebsocketMgr::WSServer::ptr_t server = mOwningServer.lock();
+ if (!server)
+ {
+ return false;
+ }
+ return server->getConnectionState(mConnectionHandle) == connection_open;
+}
diff --git a/indra/llcorehttp/llwebsocketmgr.h b/indra/llcorehttp/llwebsocketmgr.h
new file mode 100644
index 00000000000..4165b3cecc4
--- /dev/null
+++ b/indra/llcorehttp/llwebsocketmgr.h
@@ -0,0 +1,305 @@
+/**
+ * @file llwebsocketmgr.h
+ * @brief WebSocket manager singleton for managing WebSocket servers and connections
+ *
+ * $LicenseInfo:firstyear=2025&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2025, 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$
+ */
+
+#pragma once
+
+#include "llsingleton.h"
+#include "llsd.h"
+#include "lluuid.h"
+#include "llhost.h"
+#include "llmutex.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+struct Server_impl;
+
+/**
+ * @class LLWebsocketMgr
+ * @brief Singleton manager for WebSocket connections and servers
+ *
+ * This class provides a high-level interface for managing WebSocket connections
+ * and servers using websocketpp library. It handles both client and server
+ * connections, provides thread-safe operations, and integrates with the
+ * existing Linden Lab infrastructure.
+ */
+class LLWebsocketMgr: public LLSingleton
+{
+ LLSINGLETON(LLWebsocketMgr) = default;
+ virtual ~LLWebsocketMgr() = default;
+ LOG_CLASS(LLWebsocketMgr);
+
+public:
+ using connection_h = websocketpp::connection_hdl;
+ class WSServer;
+
+ enum connection_state_t
+ { // must map to websocketpp::session::state
+ connection_connecting = 0,
+ connection_open = 1,
+ connection_closing = 2,
+ connection_closed = 3
+ };
+
+ class WSConnection
+ {
+ friend class LLWebsocketMgr;
+
+ public:
+ using ptr_t = std::shared_ptr;
+
+ /**
+ * @brief Constructor for WSConnection
+ * @param server Shared pointer to the parent WSServer
+ * @param handle WebSocket connection handle from websocketpp
+ */
+ WSConnection(const std::shared_ptr &server, const connection_h& handle):
+ mConnectionHandle(handle),
+ mOwningServer(server)
+ {}
+
+ virtual ~WSConnection() = default;
+
+ /**
+ * Override this method in derived classes to handle connection establishment.
+ * This is called after the WebSocket handshake is complete and the connection
+ * is ready to send/receive messages.
+ */
+ virtual void onOpen() {}
+
+ /**
+ * Override this method in derived classes to handle connection closure.
+ * This is called when the connection has been terminated, either normally
+ * or due to an error condition.
+ */
+ virtual void onClose() {}
+
+ /**
+ * @brief Called when a message is received
+ * @param message The received message as a string
+ *
+ * Override this method in derived classes to handle incoming messages.
+ * Currently only text messages are supported.
+ */
+ virtual void onMessage(const std::string& message) {}
+
+ /**
+ * @brief Send a message to the connected client
+ * @param message The message string to send
+ * @return true if the message was queued successfully, false on error
+ *
+ * Sends a text message to the remote endpoint. The message is queued
+ * asynchronously and may not be sent immediately.
+ */
+ bool sendMessage(const std::string& message) const;
+ bool sendMessage(const boost::json::value& json) const;
+ bool sendMessage(const LLSD& data) const;
+
+ /**
+ * @brief Close the WebSocket connection gracefully
+ * @param code Optional close code (default: normal closure)
+ * @param reason Optional reason string (default: empty)
+ *
+ * Initiates a graceful WebSocket close handshake. The connection will
+ * send a close frame with the specified code and reason, then wait for
+ * the remote endpoint to respond with its own close frame before
+ * actually closing the underlying TCP connection.
+ *
+ * Common close codes:
+ * - 1000: Normal closure (default)
+ * - 1001: Going away (server shutting down, page navigating away)
+ * - 1002: Protocol error
+ * - 1003: Unsupported data type
+ * - 1008: Policy violation
+ * - 1009: Message too big
+ *
+ * @note After calling this method, no further messages should be sent
+ * @note The onClose() callback will be invoked when the close handshake completes
+ */
+ void closeConnection(U16 code = 1000, const std::string& reason = std::string());
+
+ bool isConnected() const;
+
+ protected:
+ connection_h mConnectionHandle;
+ std::weak_ptr mOwningServer; // Back-reference to the server this connection belongs to
+ };
+
+ /**
+ * @class WSServer
+ * @brief Base class for WebSocket servers with customizable connection handling
+ *
+ * WSServer provides a high-level abstraction over websocketpp servers, handling
+ * threading, connection management, and event dispatching. Derive from this class
+ * to create custom WebSocket servers with application-specific logic.
+ *
+ * ## Basic Usage
+ *
+ * @code
+ * class MyServer : public LLWebsocketMgr::WSServer
+ * {
+ * public:
+ * MyServer(const std::string& name, U16 port)
+ * : WSServer(name, port, false) // Listen on all interfaces
+ * {}
+ *
+ * void onConnectionOpened(const WSConnection::ptr_t& connection) override
+ * {
+ * LL_INFOS("MyServer") << "New client connected" << LL_ENDL;
+ * // Send welcome message
+ * connection->sendMessage("Welcome to the server!");
+ * }
+ *
+ * void onConnectionClosed(const WSConnection::ptr_t& connection) override
+ * {
+ * LL_INFOS("MyServer") << "Client disconnected" << LL_ENDL;
+ * }
+ *
+ * protected:
+ * // Use custom connection class
+ * WSConnection::ptr_t connectionFactory(WSServer::ptr_t server, connection_h handle) override
+ * {
+ * return std::make_shared(server, handle);
+ * }
+ * };
+ * @endcode
+ *
+ * ## Connection Management
+ *
+ * The server automatically manages connection lifetimes and provides several ways
+ * to interact with connections:
+ *
+ * - `broadcastMessage()` - Send message to all connected clients
+ * - `sendMessageTo()` - Send message to specific connection
+ * - `closeConnection()` - Close specific connection with code/reason
+ * - `getConnection()` - Get connection object by handle
+ *
+ * ## Thread Safety
+ *
+ * All public methods are thread-safe and can be called from any thread. The server
+ * runs its own background thread for handling WebSocket events, while connection
+ * callbacks are also executed on this background thread.
+ */
+ class WSServer: public std::enable_shared_from_this
+ {
+ friend struct Server_impl;
+ friend class WSConnection;
+ friend class LLWebsocketMgr;
+
+ public:
+ using ptr_t = std::shared_ptr;
+
+ WSServer(std::string_view name, U16 port, bool local_only = true);
+ virtual ~WSServer();
+
+ virtual void onStarted() {}
+ virtual void onStopped() {}
+
+ virtual void onConnectionOpened(const WSConnection::ptr_t& connection) { }
+ virtual void onConnectionClosed(const WSConnection::ptr_t& connection) { }
+
+ bool isRunning() const;
+ size_t getConnectionCount() const
+ {
+ LLMutexLock lock(&mConnectionMutex);
+ return mConnections.size();
+ }
+
+ void broadcastMessage(const std::string& message);
+ virtual bool update() { return true; }
+
+ connection_state_t getConnectionState(const connection_h& handle) const;
+
+ protected:
+ virtual WSConnection::ptr_t connectionFactory(WSServer::ptr_t server, connection_h handle);
+
+ bool start();
+ void stop();
+
+ bool sendMessageTo(const connection_h& handle, const std::string& message);
+
+ /**
+ * @brief Close a specific connection gracefully
+ * @param handle The connection handle to close
+ * @param code Close code (default: normal closure)
+ * @param reason Close reason string (default: empty)
+ * @return true if close was initiated successfully, false on error
+ *
+ * Internal method used by WSConnection to close individual connections.
+ * This method is thread-safe and can be called from any thread.
+ */
+ bool closeConnection(const connection_h& handle, U16 code = 1000, const std::string& reason = std::string());
+
+ private:
+ using connection_map_t = std::map >;
+
+ WSConnection::ptr_t getConnection(const connection_h& handle);
+
+ void handleOpenConnection(const connection_h& handle);
+ void handleCloseConnection(const connection_h& handle);
+ void handleMessage(const connection_h& handle, const std::string& message);
+
+ std::string mServerName;
+ std::unique_ptr mImpl;
+ connection_map_t mConnections;
+ mutable LLMutex mConnectionMutex;
+
+ // Threading support
+ std::thread mServerThread; ///< Thread running the ASIO event loop
+ std::atomic mShouldStop{ false }; ///< Thread-safe stop flag
+ mutable LLMutex mThreadMutex; ///< Mutex for thread synchronization
+ };
+
+ // Server and Connection Management
+ WSServer::ptr_t findServerByName(const std::string &name) const;
+
+ bool addServer(const WSServer::ptr_t& server);
+ bool removeServer(const std::string &name);
+
+ bool startServer(const std::string &name) const;
+ void stopServer(const std::string &name) const;
+
+ void update();
+
+protected:
+ void initSingleton() override;
+ void cleanupSingleton() override;
+
+private:
+ using server_map_t = std::map;
+
+ void stopAllServers();
+
+ server_map_t mServers;
+};
diff --git a/indra/llcorehttp/tests/llcorehttp_test.cpp b/indra/llcorehttp/tests/llcorehttp_test.cpp
index c0cc2c80301..c7c50e61664 100755
--- a/indra/llcorehttp/tests/llcorehttp_test.cpp
+++ b/indra/llcorehttp/tests/llcorehttp_test.cpp
@@ -41,11 +41,7 @@
#include "test_httpstatus.hpp"
#include "test_refcounted.hpp"
#include "test_httpoperation.hpp"
-// As of 2019-06-28, test_httprequest.hpp consistently crashes on Mac Release
-// builds for reasons not yet diagnosed.
-#if ! (LL_DARWIN && LL_RELEASE)
#include "test_httprequest.hpp"
-#endif
#include "test_httpheaders.hpp"
#include "test_httprequestqueue.hpp"
#include "_httpservice.h"
@@ -53,9 +49,6 @@
#include "llproxy.h"
#include "llcleanup.h"
-void ssl_thread_id_callback(CRYPTO_THREADID*);
-void ssl_locking_callback(int mode, int type, const char * file, int line);
-
#if 0 // lltut provides main and runner
namespace tut
@@ -80,27 +73,10 @@ int main()
#endif // 0
-int ssl_mutex_count(0);
-LLCoreInt::HttpMutex ** ssl_mutex_list = NULL;
-
void init_curl()
{
curl_global_init(CURL_GLOBAL_ALL);
- ssl_mutex_count = CRYPTO_num_locks();
- if (ssl_mutex_count > 0)
- {
- ssl_mutex_list = new LLCoreInt::HttpMutex * [ssl_mutex_count];
-
- for (int i(0); i < ssl_mutex_count; ++i)
- {
- ssl_mutex_list[i] = new LLCoreInt::HttpMutex;
- }
-
- CRYPTO_set_locking_callback(ssl_locking_callback);
- CRYPTO_THREADID_set_callback(ssl_thread_id_callback);
- }
-
LLProxy::getInstance();
}
@@ -108,39 +84,6 @@ void init_curl()
void term_curl()
{
SUBSYSTEM_CLEANUP(LLProxy);
-
- CRYPTO_set_locking_callback(NULL);
- for (int i(0); i < ssl_mutex_count; ++i)
- {
- delete ssl_mutex_list[i];
- }
- delete [] ssl_mutex_list;
-}
-
-
-void ssl_thread_id_callback(CRYPTO_THREADID* pthreadid)
-{
-#if defined(WIN32)
- CRYPTO_THREADID_set_pointer(pthreadid, GetCurrentThread());
-#else
- CRYPTO_THREADID_set_pointer(pthreadid, pthread_self());
-#endif
-}
-
-
-void ssl_locking_callback(int mode, int type, const char * /* file */, int /* line */)
-{
- if (type >= 0 && type < ssl_mutex_count)
- {
- if (mode & CRYPTO_LOCK)
- {
- ssl_mutex_list[type]->lock();
- }
- else
- {
- ssl_mutex_list[type]->unlock();
- }
- }
}
diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp
index aed906bb8fa..77ed8df066a 100644
--- a/indra/llcorehttp/tests/test_httprequest.hpp
+++ b/indra/llcorehttp/tests/test_httprequest.hpp
@@ -454,6 +454,10 @@ void HttpRequestTestObjectType::test<4>()
template <> template <>
void HttpRequestTestObjectType::test<5>()
{
+#ifndef LL_WINDOWS
+ skip("Skip due to issues with testing pthread cancellation");
+#endif
+
ScopedCurlInit ready;
set_test_name("HttpRequest Spin (soft) + NoOp + hard termination");
@@ -517,6 +521,9 @@ void HttpRequestTestObjectType::test<5>()
template <> template <>
void HttpRequestTestObjectType::test<6>()
{
+#ifndef LL_WINDOWS
+ skip("Skip due to issues with testing pthread cancellation");
+#endif
ScopedCurlInit ready;
set_test_name("HttpRequest Spin + NoOp + hard termination");
@@ -2779,7 +2786,7 @@ void HttpRequestTestObjectType::test<22>()
for (int i(0); i < test_count; ++i)
{
char buffer[128];
- sprintf(buffer, "/bug2295/%d/", i);
+ snprintf(buffer, sizeof(buffer), "/bug2295/%d/", i);
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
url_base + buffer,
0,
@@ -2810,7 +2817,7 @@ void HttpRequestTestObjectType::test<22>()
for (int i(0); i < test2_count; ++i)
{
char buffer[128];
- sprintf(buffer, "/bug2295/00000012/%d/", i);
+ snprintf(buffer, sizeof(buffer), "/bug2295/00000012/%d/", i);
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
url_base + buffer,
0,
@@ -2841,7 +2848,7 @@ void HttpRequestTestObjectType::test<22>()
for (int i(0); i < test3_count; ++i)
{
char buffer[128];
- sprintf(buffer, "/bug2295/inv_cont_range/%d/", i);
+ snprintf(buffer, sizeof(buffer), "/bug2295/inv_cont_range/%d/", i);
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
url_base + buffer,
0,
diff --git a/indra/llcorehttp/tests/test_refcounted.hpp b/indra/llcorehttp/tests/test_refcounted.hpp
index c0c8e784130..eb23a25545a 100644
--- a/indra/llcorehttp/tests/test_refcounted.hpp
+++ b/indra/llcorehttp/tests/test_refcounted.hpp
@@ -28,8 +28,6 @@
#include "_refcounted.h"
-// disable all of this because it's hanging win64 builds?
-#if ! (LL_WINDOWS && ADDRESS_SIZE == 64)
using namespace LLCoreInt;
namespace tut
@@ -122,5 +120,4 @@ namespace tut
ensure(rc->getRefCount() == RefCounted::NOT_REF_COUNTED);
}
}
-#endif // disabling on Win64
#endif // TEST_LLCOREINT_REF_COUNTED_H_
diff --git a/indra/llcrashlogger/llcrashlock.cpp b/indra/llcrashlogger/llcrashlock.cpp
index ecd197b2c13..bc34f6798fd 100644
--- a/indra/llcrashlogger/llcrashlock.cpp
+++ b/indra/llcrashlogger/llcrashlock.cpp
@@ -189,7 +189,7 @@ LLSD LLCrashLock::getProcessList()
bool LLCrashLock::fileExists(std::string filename)
{
#ifdef LL_WINDOWS // or BOOST_WINDOWS_API
- boost::filesystem::path file_path(utf8str_to_utf16str(filename));
+ boost::filesystem::path file_path(ll_convert(filename));
#else
boost::filesystem::path file_path(filename);
#endif
@@ -199,7 +199,7 @@ bool LLCrashLock::fileExists(std::string filename)
void LLCrashLock::cleanupProcess(std::string proc_dir)
{
#ifdef LL_WINDOWS // or BOOST_WINDOWS_API
- boost::filesystem::path dir_path(utf8str_to_utf16str(proc_dir));
+ boost::filesystem::path dir_path(ll_convert(proc_dir));
#else
boost::filesystem::path dir_path(proc_dir);
#endif
diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp
index b80243c22e5..ea33a3bb906 100644
--- a/indra/llfilesystem/lldir.cpp
+++ b/indra/llfilesystem/lldir.cpp
@@ -103,7 +103,7 @@ std::vector LLDir::getFilesInDir(const std::string &dirname)
//Returns a vector of fullpath filenames.
#ifdef LL_WINDOWS // or BOOST_WINDOWS_API
- boost::filesystem::path p(utf8str_to_utf16str(dirname));
+ boost::filesystem::path p(ll_convert(dirname));
#else
boost::filesystem::path p(dirname);
#endif
@@ -197,7 +197,7 @@ U32 LLDir::deleteDirAndContents(const std::string& dir_name)
try
{
#ifdef LL_WINDOWS // or BOOST_WINDOWS_API
- boost::filesystem::path dir_path(utf8str_to_utf16str(dir_name));
+ boost::filesystem::path dir_path(ll_convert(dir_name));
#else
boost::filesystem::path dir_path(dir_name);
#endif
diff --git a/indra/llfilesystem/lldir_mac.cpp b/indra/llfilesystem/lldir_mac.cpp
index b9be75c528f..2db1b6ec5d4 100644
--- a/indra/llfilesystem/lldir_mac.cpp
+++ b/indra/llfilesystem/lldir_mac.cpp
@@ -149,7 +149,7 @@ LLDir_Mac::LLDir_Mac()
mWorkingDir = getCurPath();
- mLLPluginDir = mAppRODataDir + mDirDelimiter + "llplugin";
+ mLLPluginDir = mAppRODataDir + mDirDelimiter + "SLPlugin.app" + mDirDelimiter + "Contents" + mDirDelimiter + "Frameworks";
}
}
diff --git a/indra/llfilesystem/lldir_win32.cpp b/indra/llfilesystem/lldir_win32.cpp
index a607c70b449..58c080c9823 100644
--- a/indra/llfilesystem/lldir_win32.cpp
+++ b/indra/llfilesystem/lldir_win32.cpp
@@ -172,7 +172,7 @@ LLDir_Win32::LLDir_Win32()
{
w_str[wcslen(w_str)-1] = '\0'; /* Flawfinder: ignore */ // remove trailing slash
}
- mTempDir = utf16str_to_utf8str(llutf16string(w_str));
+ mTempDir = ll_convert(std::wstring(w_str));
if (mOSUserDir.empty())
{
@@ -225,14 +225,14 @@ LLDir_Win32::LLDir_Win32()
// Set working directory, for LLDir::getWorkingDir()
GetCurrentDirectory(MAX_PATH, w_str);
- mWorkingDir = utf16str_to_utf8str(llutf16string(w_str));
+ mWorkingDir = ll_convert(std::wstring(w_str));
// Set the executable directory
S32 size = GetModuleFileName(NULL, w_str, MAX_PATH);
if (size)
{
w_str[size] = '\0';
- mExecutablePathAndName = utf16str_to_utf8str(llutf16string(w_str));
+ mExecutablePathAndName = ll_convert(std::wstring(w_str));
auto path_end = mExecutablePathAndName.find_last_of('\\');
if (path_end != std::string::npos)
{
@@ -347,8 +347,8 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string &
WIN32_FIND_DATA FileData;
- llutf16string pathname = utf8str_to_utf16str(dirname);
- pathname += utf8str_to_utf16str(mask);
+ std::wstring pathname = ll_convert(dirname);
+ pathname += ll_convert(mask);
if ((count_search_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE)
{
@@ -370,7 +370,7 @@ std::string LLDir_Win32::getCurPath()
WCHAR w_str[MAX_PATH];
GetCurrentDirectory(MAX_PATH, w_str);
- return utf16str_to_utf8str(llutf16string(w_str));
+ return ll_convert(std::wstring(w_str));
}
diff --git a/indra/llfilesystem/lldir_win32.h b/indra/llfilesystem/lldir_win32.h
index ab2726f1a04..21a3f1213b2 100644
--- a/indra/llfilesystem/lldir_win32.h
+++ b/indra/llfilesystem/lldir_win32.h
@@ -51,7 +51,7 @@ class LLDir_Win32 : public LLDir
private:
void* mDirSearch_h{ nullptr };
- llutf16string mCurrentDir;
+ std::wstring mCurrentDir;
};
#endif // LL_LLDIR_WIN32_H
diff --git a/indra/llfilesystem/lldirguard.h b/indra/llfilesystem/lldirguard.h
index fcb179bbc80..c6ce13efb49 100644
--- a/indra/llfilesystem/lldirguard.h
+++ b/indra/llfilesystem/lldirguard.h
@@ -31,6 +31,9 @@
#include "llerror.h"
#if LL_WINDOWS
+
+#include "llwin32headers.h"
+
class LLDirectoryGuard
{
public:
@@ -46,8 +49,8 @@ class LLDirectoryGuard
(wcsncmp(mOrigDir,mFinalDir,mOrigDirLen)!=0))
{
// Dir has changed
- std::string mOrigDirUtf8 = utf16str_to_utf8str(llutf16string(mOrigDir));
- std::string mFinalDirUtf8 = utf16str_to_utf8str(llutf16string(mFinalDir));
+ std::string mOrigDirUtf8 = ll_convert(std::wstring(mOrigDir));
+ std::string mFinalDirUtf8 = ll_convert(std::wstring(mFinalDir));
LL_INFOS() << "Resetting working dir from " << mFinalDirUtf8 << " to " << mOrigDirUtf8 << LL_ENDL;
SetCurrentDirectory(mOrigDir);
}
diff --git a/indra/llfilesystem/lldiriterator.cpp b/indra/llfilesystem/lldiriterator.cpp
index 61f768c512d..e8c37389d2a 100644
--- a/indra/llfilesystem/lldiriterator.cpp
+++ b/indra/llfilesystem/lldiriterator.cpp
@@ -52,7 +52,7 @@ LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask)
: mIsValid(false)
{
#ifdef LL_WINDOWS // or BOOST_WINDOWS_API
- fs::path dir_path(utf8str_to_utf16str(dirname));
+ fs::path dir_path(ll_convert(dirname));
#else
fs::path dir_path(dirname);
#endif
diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp
index 49904911a91..e971e1885a2 100644
--- a/indra/llfilesystem/lldiskcache.cpp
+++ b/indra/llfilesystem/lldiskcache.cpp
@@ -103,7 +103,7 @@ void LLDiskCache::purge()
std::vector file_info;
#if LL_WINDOWS
- std::wstring cache_path(utf8str_to_utf16str(sCacheDir));
+ std::wstring cache_path(ll_convert(sCacheDir));
#else
std::string cache_path(sCacheDir);
#endif
@@ -226,7 +226,7 @@ void LLDiskCache::clearCache()
*/
boost::system::error_code ec;
#if LL_WINDOWS
- std::wstring cache_path(utf8str_to_utf16str(sCacheDir));
+ std::wstring cache_path(ll_convert(sCacheDir));
#else
std::string cache_path(sCacheDir);
#endif
@@ -259,7 +259,7 @@ void LLDiskCache::removeOldVFSFiles()
boost::system::error_code ec;
#if LL_WINDOWS
- std::wstring cache_path(utf8str_to_utf16str(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "")));
+ std::wstring cache_path(ll_convert(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "")));
#else
std::string cache_path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""));
#endif
@@ -300,7 +300,7 @@ uintmax_t LLDiskCache::dirFileSize(const std::string& dir)
*/
boost::system::error_code ec;
#if LL_WINDOWS
- std::wstring dir_path(utf8str_to_utf16str(dir));
+ std::wstring dir_path(ll_convert(dir));
#else
std::string dir_path(dir);
#endif
diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp
index c8ce9531c28..5ce5244107d 100644
--- a/indra/llfilesystem/llfilesystem.cpp
+++ b/indra/llfilesystem/llfilesystem.cpp
@@ -316,7 +316,7 @@ void LLFileSystem::updateFileAccessTime(const std::string& file_path)
boost::system::error_code ec;
#if LL_WINDOWS
// file last write time
- const std::time_t last_write_time = boost::filesystem::last_write_time(utf8str_to_utf16str(file_path), ec);
+ const std::time_t last_write_time = boost::filesystem::last_write_time(ll_convert(file_path), ec);
if (ec.failed())
{
LL_WARNS() << "Failed to read last write time for cache file " << file_path << ": " << ec.message() << LL_ENDL;
@@ -330,7 +330,7 @@ void LLFileSystem::updateFileAccessTime(const std::string& file_path)
// before the last one
if (delta_time > time_threshold)
{
- boost::filesystem::last_write_time(utf8str_to_utf16str(file_path), cur_time, ec);
+ boost::filesystem::last_write_time(ll_convert(file_path), cur_time, ec);
}
#else
// file last write time
diff --git a/indra/llfilesystem/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp
index 6e191ad096d..d7d57fa86fb 100644
--- a/indra/llfilesystem/tests/lldir_test.cpp
+++ b/indra/llfilesystem/tests/lldir_test.cpp
@@ -435,7 +435,7 @@ namespace tut
for (counter=0, foundUnused=false; !foundUnused; counter++ )
{
char counterStr[3];
- sprintf(counterStr, "%02d", counter);
+ snprintf(counterStr, sizeof(counterStr), "%02d", counter);
uniqueDir = dirbase + counterStr;
foundUnused = ! ( LLFile::isdir(uniqueDir) || LLFile::isfile(uniqueDir) );
}
diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp
index effd33b410a..ab6c593fc2d 100644
--- a/indra/llimage/llimagejpeg.cpp
+++ b/indra/llimage/llimagejpeg.cpp
@@ -31,7 +31,9 @@
#include "llerror.h"
#include "llexception.h"
+#if !LL_ARM64
jmp_buf LLImageJPEG::sSetjmpBuffer ;
+#endif
LLImageJPEG::LLImageJPEG(S32 quality)
: LLImageFormatted(IMG_CODEC_JPEG),
mOutputBuffer( NULL ),
@@ -78,12 +80,15 @@ bool LLImageJPEG::updateData()
//
//try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error
//so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao
+ //except in the case of AARCH64/ARM64 where setjmp will crash
//
+#if !LL_ARM64
if(setjmp(sSetjmpBuffer))
{
jpeg_destroy_decompress(&cinfo);
return false;
}
+#endif
try
{
// Now we can initialize the JPEG decompression object.
@@ -223,11 +228,13 @@ bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
//try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error
//so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao
//
+#if !LL_ARM64
if(setjmp(sSetjmpBuffer))
{
jpeg_destroy_decompress(&cinfo);
return true; // done
}
+#endif
try
{
// Now we can initialize the JPEG decompression object.
@@ -431,9 +438,10 @@ void LLImageJPEG::errorExit( j_common_ptr cinfo )
// Let the memory manager delete any temp files
jpeg_destroy(cinfo);
-
+#if !LL_ARM64
// Return control to the setjmp point
longjmp(sSetjmpBuffer, 1) ;
+#endif
}
// Decide whether to emit a trace or warning message.
@@ -551,6 +559,7 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
//try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error
//so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao
//
+#if !LL_ARM64
if( setjmp(sSetjmpBuffer) )
{
// If we get here, the JPEG code has signaled an error.
@@ -561,7 +570,7 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
mOutputBufferSize = 0;
return false;
}
-
+#endif
try
{
diff --git a/indra/llimage/llimagejpeg.h b/indra/llimage/llimagejpeg.h
index 012b87a42dd..ee0a8815e8d 100644
--- a/indra/llimage/llimagejpeg.h
+++ b/indra/llimage/llimagejpeg.h
@@ -78,7 +78,9 @@ class LLImageJPEG : public LLImageFormatted
S32 mEncodeQuality; // on a scale from 1 to 100
private:
+#if !LL_ARM64
static jmp_buf sSetjmpBuffer; // To allow the library to abort.
+#endif
};
#endif // LL_LLIMAGEJPEG_H
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp
index 431f5aa0016..7cfadb889dd 100644
--- a/indra/llimagej2coj/llimagej2coj.cpp
+++ b/indra/llimagej2coj/llimagej2coj.cpp
@@ -29,8 +29,6 @@
// this is defined so that we get static linking.
#include "openjpeg.h"
-#include "event.h"
-#include "cio.h"
// Factory function: see declaration in llimagej2c.cpp
LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
@@ -48,6 +46,7 @@ std::string LLImageJ2COJ::getEngineInfo() const
#endif
}
+#if WANT_VERBOSE_OPJ_SPAM
// Return string from message, eliminating final \n if present
static std::string chomp(const char* msg)
{
@@ -63,27 +62,34 @@ static std::string chomp(const char* msg)
}
return message;
}
+#endif
/**
sample error callback expecting a LLFILE* client object
*/
void error_callback(const char* msg, void*)
{
- LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+#if WANT_VERBOSE_OPJ_SPAM
+ LL_WARNS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+#endif
}
/**
sample warning callback expecting a LLFILE* client object
*/
void warning_callback(const char* msg, void*)
{
- LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+#if WANT_VERBOSE_OPJ_SPAM
+ LL_WARNS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+#endif
}
/**
sample debug callback expecting no client object
*/
void info_callback(const char* msg, void*)
{
- LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+#if WANT_VERBOSE_OPJ_SPAM
+ LL_INFOS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;
+#endif
}
// Divide a by 2 to the power of b and round upwards
@@ -95,39 +101,13 @@ int ceildivpow2(int a, int b)
class JPEG2KBase
{
public:
- JPEG2KBase() {}
+ JPEG2KBase() = default;
U8* buffer = nullptr;
OPJ_SIZE_T size = 0;
OPJ_OFF_T offset = 0;
};
-#define WANT_VERBOSE_OPJ_SPAM LL_DEBUG
-
-static void opj_info(const char* msg, void* user_data)
-{
- llassert(user_data);
-#if WANT_VERBOSE_OPJ_SPAM
- LL_INFOS("OpenJPEG") << msg << LL_ENDL;
-#endif
-}
-
-static void opj_warn(const char* msg, void* user_data)
-{
- llassert(user_data);
-#if WANT_VERBOSE_OPJ_SPAM
- LL_WARNS("OpenJPEG") << msg << LL_ENDL;
-#endif
-}
-
-static void opj_error(const char* msg, void* user_data)
-{
- llassert(user_data);
-#if WANT_VERBOSE_OPJ_SPAM
- LL_WARNS("OpenJPEG") << msg << LL_ENDL;
-#endif
-}
-
static OPJ_SIZE_T opj_read(void * buffer, OPJ_SIZE_T bytes, void* user_data)
{
llassert(user_data && buffer);
@@ -283,11 +263,7 @@ class JPEG2KDecode : public JPEG2KBase
JPEG2KDecode(S8 discardLevel)
{
- memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
memset(¶meters, 0, sizeof(opj_dparameters_t));
- event_mgr.error_handler = error_callback;
- event_mgr.warning_handler = warning_callback;
- event_mgr.info_handler = info_callback;
opj_set_default_decoder_parameters(¶meters);
parameters.cp_reduce = discardLevel;
}
@@ -331,6 +307,11 @@ class JPEG2KDecode : public JPEG2KBase
decoder = opj_create_decompress(OPJ_CODEC_J2K);
+ /* catch events using our callbacks and give a local context */
+ opj_set_error_handler(decoder, error_callback, nullptr);
+ opj_set_warning_handler(decoder, warning_callback, nullptr);
+ opj_set_info_handler(decoder, info_callback, nullptr);
+
if (!opj_setup_decoder(decoder, ¶meters))
{
return false;
@@ -401,9 +382,9 @@ class JPEG2KDecode : public JPEG2KBase
decoder = opj_create_decompress(OPJ_CODEC_J2K);
opj_setup_decoder(decoder, ¶meters);
- opj_set_info_handler(decoder, opj_info, this);
- opj_set_warning_handler(decoder, opj_warn, this);
- opj_set_error_handler(decoder, opj_error, this);
+ opj_set_info_handler(decoder, info_callback, this);
+ opj_set_warning_handler(decoder, warning_callback, this);
+ opj_set_error_handler(decoder, error_callback, this);
if (stream)
{
@@ -469,7 +450,6 @@ class JPEG2KDecode : public JPEG2KBase
private:
opj_dparameters_t parameters;
- opj_event_mgr_t event_mgr;
opj_image_t* image = nullptr;
opj_codec_t* decoder = nullptr;
opj_stream_t* stream = nullptr;
@@ -484,10 +464,6 @@ class JPEG2KEncode : public JPEG2KBase
JPEG2KEncode(const char* comment_text_in, bool reversible)
{
memset(¶meters, 0, sizeof(opj_cparameters_t));
- memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
- event_mgr.error_handler = error_callback;
- event_mgr.warning_handler = warning_callback;
- event_mgr.info_handler = info_callback;
opj_set_default_encoder_parameters(¶meters);
parameters.cod_format = OPJ_CODEC_J2K;
@@ -555,6 +531,11 @@ class JPEG2KEncode : public JPEG2KBase
encoder = opj_create_compress(OPJ_CODEC_J2K);
+ /* catch events using our callbacks and give a local context */
+ opj_set_error_handler(encoder, error_callback, nullptr);
+ opj_set_warning_handler(encoder, warning_callback, nullptr);
+ opj_set_info_handler(encoder, info_callback, nullptr);
+
parameters.tcp_mct = (image->numcomps >= 3) ? 1 : 0; // no color transform for RGBA images
@@ -573,15 +554,6 @@ class JPEG2KEncode : public JPEG2KBase
}
- if (!opj_setup_encoder(encoder, ¶meters, image))
- {
- return false;
- }
-
- opj_set_info_handler(encoder, opj_info, this);
- opj_set_warning_handler(encoder, opj_warn, this);
- opj_set_error_handler(encoder, opj_error, this);
-
U32 width_tiles = (rawImageIn.getWidth() >> 6);
U32 height_tiles = (rawImageIn.getHeight() >> 6);
@@ -595,6 +567,19 @@ class JPEG2KEncode : public JPEG2KBase
height_tiles = 1;
}
+ if (width_tiles == 1 || height_tiles == 1)
+ {
+ // Images with either dimension less than 32 need less number of resolutions otherwise they error
+ int min_dim = rawImageIn.getWidth() < rawImageIn.getHeight() ? rawImageIn.getWidth() : rawImageIn.getHeight();
+ int max_res = 1 + (int)floor(log2(min_dim));
+ parameters.numresolution = max_res;
+ }
+
+ if (!opj_setup_encoder(encoder, ¶meters, image))
+ {
+ return false;
+ }
+
U32 tile_count = width_tiles * height_tiles;
U32 data_size_guess = tile_count * TILE_SIZE;
@@ -786,7 +771,6 @@ class JPEG2KEncode : public JPEG2KBase
private:
opj_cparameters_t parameters;
- opj_event_mgr_t event_mgr;
opj_image_t* image = nullptr;
opj_codec_t* encoder = nullptr;
opj_stream_t* stream = nullptr;
diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp
index ebf7445c65c..b17e22e4650 100644
--- a/indra/llinventory/llpermissions.cpp
+++ b/indra/llinventory/llpermissions.cpp
@@ -774,6 +774,7 @@ void LLPermissions::importLLSD(const LLSD& sd_perm)
}
}
+ fixOwnership();
fix();
}
diff --git a/indra/llkdu/CMakeLists.txt b/indra/llkdu/CMakeLists.txt
index 7cd9f5eb247..411fff34ae0 100644
--- a/indra/llkdu/CMakeLists.txt
+++ b/indra/llkdu/CMakeLists.txt
@@ -27,14 +27,6 @@ set(llkdu_HEADER_FILES
list(APPEND llkdu_SOURCE_FILES ${llkdu_HEADER_FILES})
-# Our KDU package is built with KDU_X86_INTRINSICS in its .vcxproj file.
-# Unless that macro is also set for every consumer build, KDU freaks out,
-# spamming the viewer log with alignment FUD.
-set_source_files_properties(${llkdu_SOURCE_FILES}
- PROPERTIES
- COMPILE_DEFINITIONS
- "KDU_X86_INTRINSICS")
-
if (USE_KDU)
add_library (llkdu ${llkdu_SOURCE_FILES})
@@ -42,10 +34,7 @@ if (USE_KDU)
target_include_directories( llkdu INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
# Add tests
- # ND: llkdu tests are very strange as they include stubs for KDU classes/methods
- # if not having access to the right KDU version this test will fail to compile, incidentally I do not
- # have access to a matching version of KDU and thus cannot get this tests to compile
- if (LL_TESTS_KDU)
+ if (LL_TESTS)
include(LLAddBuildTest)
include(Tut)
SET(llkdu_TEST_SOURCE_FILES
@@ -62,6 +51,6 @@ if (USE_KDU)
set_property( SOURCE ${llkdu_TEST_SOURCE_FILES} PROPERTY LL_TEST_ADDITIONAL_INCLUDE_DIRS ${llimage_include_dir})
LL_ADD_PROJECT_UNIT_TESTS(llkdu "${llkdu_TEST_SOURCE_FILES}")
- endif (LL_TESTS_KDU)
+ endif (LL_TESTS)
endif (USE_KDU)
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index b824fd83851..7eba9494a62 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -163,6 +163,7 @@ class LLKDUDecodeState
S32 mNumComponents;
bool mUseYCC;
kdu_dims mDims;
+ kdu_push_pull_params mParams;
kdu_sample_allocator mAllocator;
kdu_tile_comp mComps[4];
kdu_line_buf mLines[4];
@@ -255,7 +256,7 @@ LLImageJ2CKDU::LLImageJ2CKDU() : LLImageJ2CImpl(),
mCodeStreamp(),
mTPosp(),
mTileIndicesp(),
- mRawImagep(NULL),
+ mRawImagep(nullptr),
mDecodeState(),
mBlocksSize(-1),
mPrecinctsSize(-1),
@@ -295,17 +296,17 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod
// two U32s and a pointer, so it's not as if it would be a huge overhead
// to allocate a new one every time.
// Also -- why is base.getData() tested specifically here? If that returns
- // NULL, shouldn't we bail out of the whole method?
+ // nullptr, shouldn't we bail out of the whole method?
if (!mInputp && base.getData())
{
// The compressed data has been loaded
// Setup the source for the codestream
- mInputp.reset(new LLKDUMemSource(base.getData(), data_size));
+ mInputp = std::make_unique(base.getData(), data_size);
}
if (mInputp)
{
- // This is LLKDUMemSource::reset(), not boost::scoped_ptr::reset().
+ // This is LLKDUMemSource::reset(), not std::unique_ptr::reset().
mInputp->reset();
}
@@ -315,7 +316,7 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod
// *TODO: This seems to be wrong. The base class should have no idea of
// how j2c compression works so no good way of computing what's the byte
// range to be used.
- mCodeStreamp->set_max_bytes(max_bytes, true);
+ mCodeStreamp->set_max_bytes(max_bytes);
// If you want to flip or rotate the image for some reason, change
// the resolution, or identify a restricted region of interest, this is
@@ -461,8 +462,8 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
mCodeStreamp->change_appearance(false, true, false);
// Apply loading discard level and cropping if required
- kdu_dims* region_kdu = NULL;
- if (region != NULL)
+ kdu_dims* region_kdu = nullptr;
+ if (region != nullptr)
{
region_kdu = new kdu_dims;
region_kdu->pos.x = region[0];
@@ -479,7 +480,7 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
if (region_kdu)
{
delete region_kdu;
- region_kdu = NULL;
+ region_kdu = nullptr;
}
// Resize raw_image according to the image to be decoded
@@ -490,12 +491,12 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
if (!mTileIndicesp)
{
- mTileIndicesp.reset(new kdu_dims);
+ mTileIndicesp = std::make_unique();
}
mCodeStreamp->get_valid_tiles(*mTileIndicesp);
if (!mTPosp)
{
- mTPosp.reset(new kdu_coords);
+ mTPosp = std::make_unique();
mTPosp->y = 0;
mTPosp->x = 0;
}
@@ -505,7 +506,7 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
base.setLastError(msg.what());
return false;
}
- catch (kdu_exception kdu_value)
+ catch (const kdu_exception& kdu_value)
{
// KDU internally throws kdu_exception. It's possible that such an
// exception might leak out into our code. Catch kdu_exception
@@ -596,8 +597,7 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
kdu_coords offset = tile_dims.pos - dims.pos;
int row_gap = channels*dims.size.x; // inter-row separation
kdu_byte *buf = buffer + offset.y*row_gap + offset.x*channels;
- mDecodeState.reset(new LLKDUDecodeState(tile, buf, row_gap,
- mCodeStreamp.get()));
+ mDecodeState = std::make_unique(tile, buf, row_gap, mCodeStreamp.get());
}
// Do the actual processing
F32 remaining_time = limit_time ? decode_time - decode_timer.getElapsedTimeF32().value() : 0.0f;
@@ -622,7 +622,7 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
cleanupCodeStream();
return true; // done
}
- catch (kdu_exception kdu_value)
+ catch (const kdu_exception& kdu_value)
{
// KDU internally throws kdu_exception. It's possible that such an
// exception might leak out into our code. Catch kdu_exception
@@ -831,7 +831,7 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
base.setLastError(msg.what());
return false;
}
- catch (kdu_exception kdu_value)
+ catch (const kdu_exception& kdu_value)
{
// KDU internally throws kdu_exception. It's possible that such an
// exception might leak out into our code. Catch kdu_exception
@@ -865,7 +865,7 @@ bool LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
base.setLastError(msg.what());
return false;
}
- catch (kdu_exception kdu_value)
+ catch (const kdu_exception& kdu_value)
{
// KDU internally throws kdu_exception. It's possible that such an
// exception might leak out into our code. Catch kdu_exception
@@ -997,8 +997,8 @@ void LLImageJ2CKDU::findDiscardLevelsBoundaries(LLImageJ2C &base)
//std::cout << "Parsing discard level = " << discard_level << std::endl;
// Create the input codestream object.
setupCodeStream(base, true, MODE_FAST);
- mCodeStreamp->apply_input_restrictions(0, 4, discard_level, 0, NULL);
- mCodeStreamp->set_max_bytes(KDU_LONG_MAX,true);
+ mCodeStreamp->apply_input_restrictions(0, 4, discard_level, 0, nullptr);
+ mCodeStreamp->set_max_bytes(KDU_LONG_MAX,false);
siz_params *siz_in = mCodeStreamp->access_siz();
// Create the output codestream object.
@@ -1094,8 +1094,10 @@ void LLImageJ2CKDU::findDiscardLevelsBoundaries(LLImageJ2C &base)
void set_default_colour_weights(kdu_params *siz)
{
+ kdu_params *enc = siz->access_cluster(ENC_params);
+ assert(enc != nullptr);
kdu_params *cod = siz->access_cluster(COD_params);
- assert(cod != NULL);
+ assert(cod != nullptr);
bool can_use_ycc = true;
bool rev0 = false;
@@ -1132,7 +1134,7 @@ void set_default_colour_weights(kdu_params *siz)
return;
}
float weight;
- if (cod->get(Clev_weights,0,0,weight) || cod->get(Cband_weights,0,0,weight))
+ if (enc->get(Clev_weights,0,0,weight) || enc->get(Cband_weights,0,0,weight))
{
// Weights already specified explicitly -> nothing to do
return;
@@ -1141,17 +1143,16 @@ void set_default_colour_weights(kdu_params *siz)
// These example weights are adapted from numbers generated by Marcus Nadenau
// at EPFL, for a viewing distance of 15 cm and a display resolution of
// 300 DPI.
-
- cod->parse_string("Cband_weights:C0="
+ enc->parse_string("Cband_weights:C0="
"{0.0901},{0.2758},{0.2758},"
"{0.7018},{0.8378},{0.8378},{1}");
- cod->parse_string("Cband_weights:C1="
+ enc->parse_string("Cband_weights:C1="
"{0.0263},{0.0863},{0.0863},"
"{0.1362},{0.2564},{0.2564},"
"{0.3346},{0.4691},{0.4691},"
"{0.5444},{0.6523},{0.6523},"
"{0.7078},{0.7797},{0.7797},{1}");
- cod->parse_string("Cband_weights:C2="
+ enc->parse_string("Cband_weights:C2="
"{0.0773},{0.1835},{0.1835},"
"{0.2598},{0.4130},{0.4130},"
"{0.5040},{0.6464},{0.6464},"
@@ -1170,7 +1171,7 @@ byte buffer, spacing successive output samples apart by `gap' bytes
all necessary level shifting, type conversion, rounding and truncation. */
{
int width = src.get_width();
- if (src.get_buf32() != NULL)
+ if (src.get_buf32() != nullptr)
{ // Decompressed samples have a 32-bit representation (integer or float)
assert(precision >= 8); // Else would have used 16 bit representation
kdu_sample32 *sp = src.get_buf32();
@@ -1333,11 +1334,11 @@ LLKDUDecodeState::LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap,
mLines[c].pre_create(&mAllocator,mDims.size.x,mReversible[c],use_shorts,0,0);
if (res.which() == 0) // No DWT levels used
{
- mEngines[c] = kdu_decoder(res.access_subband(LL_BAND),&mAllocator,use_shorts);
+ mEngines[c] = kdu_decoder(res.access_subband(LL_BAND), &mAllocator, mParams, use_shorts);
}
else
{
- mEngines[c] = kdu_synthesis(res,&mAllocator,use_shorts);
+ mEngines[c] = kdu_synthesis(res, &mAllocator, mParams, use_shorts);
}
}
mAllocator.finalize(*codestreamp); // Actually creates buffering resources
@@ -1415,7 +1416,7 @@ kdc_flow_control::kdc_flow_control (kdu_supp::kdu_image_in_base *img_in, kdu_cod
this->codestream = codestream;
codestream.get_valid_tiles(valid_tile_indices);
tile_idx = valid_tile_indices.pos;
- tile = codestream.open_tile(tile_idx,NULL);
+ tile = codestream.open_tile(tile_idx, nullptr);
// Set up the individual components
num_components = codestream.get_num_components(true);
@@ -1424,7 +1425,7 @@ kdc_flow_control::kdc_flow_control (kdu_supp::kdu_image_in_base *img_in, kdu_cod
kdc_component_flow_control *comp = components;
for (n = 0; n < num_components; n++, comp++)
{
- comp->line = NULL;
+ comp->line = nullptr;
comp->reader = img_in;
kdu_coords subsampling;
codestream.get_subsampling(n,subsampling,true);
@@ -1441,12 +1442,12 @@ kdc_flow_control::kdc_flow_control (kdu_supp::kdu_image_in_base *img_in, kdu_cod
assert(num_components >= 0);
tile.set_components_of_interest(num_components);
- max_buffer_memory = engine.create(codestream,tile,false,NULL,false,1,NULL,NULL,false);
+ max_buffer_memory = engine.create(codestream, tile, false, nullptr, false, 1, nullptr, nullptr,false);
}
kdc_flow_control::~kdc_flow_control()
{
- if (components != NULL)
+ if (components != nullptr)
{
delete[] components;
}
@@ -1473,8 +1474,8 @@ bool kdc_flow_control::advance_components()
if (comp->ratio_counter < 0)
{
found_line = true;
- comp->line = engine.exchange_line(n,NULL,NULL);
- assert(comp->line != NULL);
+ comp->line = engine.exchange_line(n,nullptr,nullptr);
+ assert(comp->line != nullptr);
if (comp->line->get_width())
{
comp->reader->get(n,*(comp->line),0);
@@ -1501,9 +1502,9 @@ void kdc_flow_control::process_components()
assert(comp->ratio_counter >= 0);
assert(comp->remaining_lines > 0);
comp->remaining_lines--;
- assert(comp->line != NULL);
- engine.exchange_line(n,comp->line,NULL);
- comp->line = NULL;
+ assert(comp->line != nullptr);
+ engine.exchange_line(n,comp->line,nullptr);
+ comp->line = nullptr;
}
}
}
diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h
index 8037c818687..c9aa0c52508 100644
--- a/indra/llkdu/llimagej2ckdu.h
+++ b/indra/llkdu/llimagej2ckdu.h
@@ -27,12 +27,13 @@
#ifndef LL_LLIMAGEJ2CKDU_H
#define LL_LLIMAGEJ2CKDU_H
+#include "llpreprocessor.h"
+
#include "llimagej2c.h"
//
// KDU core header files
//
-#define KDU_NO_THREADS
#include "kdu_elementary.h"
#include "kdu_messaging.h"
#include "kdu_params.h"
@@ -41,7 +42,6 @@
#include "include_kdu_xxxx.h"
#include "kdu_sample_processing.h"
-#include
#include
class LLKDUDecodeState;
diff --git a/indra/llkdu/llkdumem.h b/indra/llkdu/llkdumem.h
index 177a8ea9763..56aff13c765 100644
--- a/indra/llkdu/llkdumem.h
+++ b/indra/llkdu/llkdumem.h
@@ -27,9 +27,9 @@
#ifndef LL_LLKDUMEM_H
#define LL_LLKDUMEM_H
-// Support classes for reading and writing from memory buffers in KDU
-#define KDU_NO_THREADS
+#include "llpreprocessor.h"
+// Support classes for reading and writing from memory buffers in KDU
#define kdu_xxxx "kdu_image.h"
#include "include_kdu_xxxx.h"
@@ -54,9 +54,7 @@ class LLKDUMemSource: public kdu_core::kdu_compressed_source
mCurPos = 0;
}
- ~LLKDUMemSource()
- {
- }
+ ~LLKDUMemSource() = default;
int read(kdu_core::kdu_byte *buf, int num_bytes)
{
@@ -94,9 +92,7 @@ class LLKDUMemTarget: public kdu_core::kdu_compressed_target
mOutputSize = &output_size;
}
- ~LLKDUMemTarget()
- {
- }
+ ~LLKDUMemTarget() = default;
bool write(const kdu_core::kdu_byte *buf, int num_bytes)
{
diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp
index db81d60d9e7..bc52a15c4af 100644
--- a/indra/llkdu/tests/llimagej2ckdu_test.cpp
+++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp
@@ -80,6 +80,7 @@ U8* LLImageBase::getData() { return NULL; }
U8* LLImageBase::reallocateData(S32 ) { return NULL; }
void LLImageBase::sanityCheck() { }
void LLImageBase::setSize(S32 , S32 , S32 ) { }
+bool LLImageBase::isBufferInvalid() const { return false; }
LLImageJ2CImpl::~LLImageJ2CImpl() { }
@@ -139,18 +140,19 @@ int kdu_tile_comp::get_bit_depth(bool ) { return 8; }
bool kdu_tile_comp::get_reversible() { return false; }
int kdu_tile_comp::get_num_resolutions() { return 1; }
kdu_subband kdu_resolution::access_subband(int ) { kdu_subband a; return a; }
-void kdu_resolution::get_dims(kdu_dims& ) { }
-int kdu_resolution::which() { return 0; }
-int kdu_resolution::get_valid_band_indices(int &) { return 1; }
-kdu_synthesis::kdu_synthesis(kdu_resolution, kdu_sample_allocator*, bool, float, kdu_thread_env*, kdu_thread_queue*) { }
+void kdu_resolution::get_dims(kdu_dims& ) const { }
+int kdu_resolution::which() const { return 0; }
+int kdu_resolution::get_valid_band_indices(int &) const { return 1; }
+kdu_synthesis::kdu_synthesis(kdu_resolution, kdu_sample_allocator*, kdu_push_pull_params&, bool, float, kdu_thread_env*, kdu_thread_queue*) { }
//kdu_params::kdu_params(const char*, bool, bool, bool, bool, bool) { }
-kdu_params::kdu_params(const char*, bool, bool, bool, bool, bool, kd_core_local::kd_coremem*) {}
+kdu_params::kdu_params(const char*, bool, bool, bool, bool, bool) {}
kdu_params::~kdu_params() { }
+void kdu_params::destroy() { }
void kdu_params::set(const char* , int , int , bool ) { }
void kdu_params::set(const char* , int , int , int ) { }
void kdu_params::finalize_all(bool ) { }
void kdu_params::finalize_all(int, bool ) { }
-void kdu_params::copy_from(kdu_params*, int, int, int, int, int, bool, bool, bool) { }
+void kdu_params::copy_from(kdu_params*, int, int, int, int, int, bool, bool, bool, bool) { }
bool kdu_params::parse_string(const char*) { return false; }
bool kdu_params::get(const char*, int, int, bool&, bool, bool, bool) { return false; }
bool kdu_params::get(const char*, int, int, float&, bool, bool, bool) { return false; }
@@ -159,13 +161,13 @@ kdu_params* kdu_params::access_relation(int, int, int, bool) { return NULL; }
kdu_params* kdu_params::access_cluster(const char*) { return NULL; }
void kdu_codestream::set_fast() { }
void kdu_codestream::set_fussy() { }
-void kdu_codestream::get_dims(int, kdu_dims&, bool ) { }
+void kdu_codestream::get_dims(int, kdu_dims&, bool ) const { }
int kdu_codestream::get_min_dwt_levels() { return 5; }
int kdu_codestream::get_max_tile_layers() { return 1; }
void kdu_codestream::change_appearance(bool, bool, bool, kdu_thread_env *) {}
void kdu_codestream::get_tile_dims(kdu_coords, int, kdu_dims&, bool ) { }
void kdu_codestream::destroy() { }
-void kdu_codestream::collect_timing_stats(int ) { }
+void kdu_codestream::collect_timing_stats(int ) const { }
void kdu_codestream::set_max_bytes(kdu_long, bool, bool ) { }
void kdu_codestream::get_valid_tiles(kdu_dims& ) { }
void kdu_codestream::create(
@@ -182,19 +184,21 @@ void kdu_codestream::get_subsampling(int , kdu_coords&, bool ) { }
void kdu_codestream::flush(kdu_long *, int, kdu_uint16 *, bool, bool, double, kdu_thread_env*, int) { }
void kdu_codestream::set_resilient(bool ) { }
int kdu_codestream::get_num_components(bool ) { return 0; }
-kdu_long kdu_codestream::get_total_bytes(bool ) { return 0; }
+kdu_long kdu_codestream::get_total_bytes(bool ) const { return 0; }
kdu_long kdu_codestream::get_compressed_data_memory(bool ) const {return 0; }
void kdu_codestream::share_buffering(kdu_codestream ) { }
-int kdu_codestream::get_num_tparts() { return 0; }
+int kdu_codestream::get_num_tparts() const { return 0; }
int kdu_codestream::trans_out(kdu_long, kdu_long*, int, bool, kdu_thread_env* ) { return 0; }
bool kdu_codestream::ready_for_flush(kdu_thread_env*) { return false; }
siz_params* kdu_codestream::access_siz() { return NULL; }
kdu_tile kdu_codestream::open_tile(kdu_coords , kdu_thread_env* ) { kdu_tile a; return a; }
kdu_codestream_comment kdu_codestream::add_comment(kdu_thread_env*) { kdu_codestream_comment a; return a; }
+kdu_codestream_comment kdu_codestream::get_comment(kdu_codestream_comment) { kdu_codestream_comment a; return a; };
void kdu_subband::close_block(kdu_block*, kdu_thread_env*) { }
void kdu_subband::get_valid_blocks(kdu_dims &indices) const { }
kdu_block * kdu_subband::open_block(kdu_coords, int *, kdu_thread_env *, int, bool) { return NULL; }
bool kdu_codestream_comment::put_text(const char*) { return false; }
+const char *kdu_codestream_comment::get_text() { return nullptr; };
void kdu_customize_warnings(kdu_message*) { }
void kdu_customize_errors(kdu_message*) { }
kdu_long kdu_multi_analysis::create(
@@ -209,16 +213,18 @@ kdu_long kdu_multi_analysis::create(
const kdu_push_pull_params*,
kdu_membroker*) { return kdu_long(0); }
void kdu_multi_analysis::destroy(kdu_thread_env *) {}
+siz_params::siz_params() : kdu_params(NULL, false, false, false, false, false) { }
siz_params::siz_params(kd_core_local::kd_coremem*) : kdu_params(NULL, false, false, false, false, false) { }
siz_params::~siz_params() {}
void siz_params::finalize(bool ) { }
void siz_params::copy_with_xforms(kdu_params*, int, int, bool, bool, bool) { }
-int siz_params::write_marker_segment(kdu_output*, kdu_params*, int) { return 0; }
+int siz_params::write_marker_segment(kdu_output*, kdu_params*, int, int&) { return 0; }
bool siz_params::check_marker_segment(kdu_uint16, int, kdu_byte a[], int&) { return false; }
-bool siz_params::read_marker_segment(kdu_uint16, int, kdu_byte a[], int) { return false; }
+int siz_params::read_marker_segment(kdu_uint16 code, int num_bytes, kdu_byte bytes[], int tpart_idx) { return false; }
kdu_decoder::kdu_decoder(
kdu_subband subband,
kdu_sample_allocator*,
+ kdu_push_pull_params&,
bool, float, int,
kdu_thread_env*,
kdu_thread_queue*,
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index eb29df245a6..bd860adc319 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -6,6 +6,7 @@ include(00-Common)
include(LLCommon)
include(bugsplat)
include(Boost)
+include(SSE2NEON)
set(llmath_SOURCE_FILES
llbbox.cpp
@@ -59,6 +60,7 @@ set(llmath_HEADER_FILES
llmath.h
llmatrix3a.h
llmatrix3a.inl
+ llmatrix4a.h
llmodularmath.h
lloctree.h
llperlin.h
@@ -99,7 +101,7 @@ list(APPEND llmath_SOURCE_FILES ${llmath_HEADER_FILES})
add_library (llmath ${llmath_SOURCE_FILES})
-target_link_libraries(llmath llcommon llmeshoptimizer)
+target_link_libraries(llmath llcommon llmeshoptimizer ll::sse2neon)
target_include_directories( llmath INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
# Add tests
diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h
index 5617eaebde0..3a4e09a5989 100644
--- a/indra/llmath/llbbox.h
+++ b/indra/llmath/llbbox.h
@@ -95,6 +95,10 @@ class LLBBox
bool mEmpty; // Nothing has been added to this bbox yet
};
+static_assert(std::is_trivially_copyable::value, "LLBBox must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLBBox must be trivial move");
+static_assert(std::is_standard_layout::value, "LLBBox must be a standard layout type");
+
//LLBBox operator*(const LLBBox &a, const LLMatrix4 &b);
diff --git a/indra/llmath/llbboxlocal.h b/indra/llmath/llbboxlocal.h
index e215e554608..f743bc0ee41 100644
--- a/indra/llmath/llbboxlocal.h
+++ b/indra/llmath/llbboxlocal.h
@@ -61,5 +61,8 @@ class LLBBoxLocal
LLBBoxLocal operator*(const LLBBoxLocal &a, const LLMatrix4 &b);
+static_assert(std::is_trivially_copyable::value, "LLBBoxLocal must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLBBoxLocal must be trivial move");
+static_assert(std::is_standard_layout::value, "LLBBoxLocal must be a standard layout type");
#endif // LL_BBOXLOCAL_H
diff --git a/indra/llmath/llline.h b/indra/llmath/llline.h
index e98e173d1f7..fa151f8b20b 100644
--- a/indra/llmath/llline.h
+++ b/indra/llmath/llline.h
@@ -40,7 +40,7 @@ class LLLine
public:
LLLine();
LLLine( const LLVector3& first_point, const LLVector3& second_point );
- virtual ~LLLine() {};
+ ~LLLine() = default;
void setPointDirection( const LLVector3& first_point, const LLVector3& second_point );
void setPoints( const LLVector3& first_point, const LLVector3& second_point );
@@ -76,5 +76,8 @@ class LLLine
LLVector3 mDirection;
};
+static_assert(std::is_trivially_copyable::value, "LLLine must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLLine must be trivial move");
+static_assert(std::is_standard_layout::value, "LLLine must be a standard layout type");
#endif
diff --git a/indra/llmath/llmatrix3a.h b/indra/llmath/llmatrix3a.h
index dff6604ae5b..9b173c22edd 100644
--- a/indra/llmath/llmatrix3a.h
+++ b/indra/llmath/llmatrix3a.h
@@ -56,7 +56,7 @@ class LLMatrix3a
//////////////////////////
// Ctor
- LLMatrix3a() {}
+ LLMatrix3a() = default;
// Ctor for setting by columns
inline LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 );
@@ -115,14 +115,18 @@ class LLMatrix3a
};
+static_assert(std::is_trivial::value, "LLMatrix3a must be a trivial type");
+
class LLRotation : public LLMatrix3a
{
public:
- LLRotation() {}
+ LLRotation() = default;
// Returns true if this rotation is orthonormal with det ~= 1
inline bool isOkRotation() const;
};
+static_assert(std::is_trivial::value, "LLRotation must be a trivial type");
+
#endif
diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h
index 3b423f783a0..377203098e2 100644
--- a/indra/llmath/llmatrix4a.h
+++ b/indra/llmath/llmatrix4a.h
@@ -36,10 +36,7 @@ class LLMatrix4a
public:
LL_ALIGN_16(LLVector4a mMatrix[4]);
- LLMatrix4a()
- {
-
- }
+ LLMatrix4a() = default;
explicit LLMatrix4a(const LLMatrix4& val)
{
@@ -228,6 +225,8 @@ class LLMatrix4a
const LLVector4a& getTranslation() const { return mMatrix[3]; }
};
+static_assert(std::is_trivial::value, "LLMatrix4a must be a trivial type");
+
inline LLVector4a rowMul(const LLVector4a &row, const LLMatrix4a &mat)
{
LLVector4a result;
diff --git a/indra/llmath/llplane.h b/indra/llmath/llplane.h
index 4e8546e32b0..832004bb644 100644
--- a/indra/llmath/llplane.h
+++ b/indra/llmath/llplane.h
@@ -43,7 +43,7 @@ class LLPlane
public:
// Constructors
- LLPlane() {}; // no default constructor
+ LLPlane() = default;
LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); }
LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); }
inline void setVec(const LLVector3 &p0, F32 d) { mV.set(p0[0], p0[1], p0[2], d); }
@@ -104,6 +104,7 @@ class LLPlane
LLVector4a mV;
} LL_ALIGN_POSTFIX(16);
+static_assert(std::is_trivial::value, "LLPlane must be a trivial type");
#endif // LL_LLPLANE_H
diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h
index 762d13eded7..472d7ca62dc 100644
--- a/indra/llmath/llquaternion.h
+++ b/indra/llmath/llquaternion.h
@@ -174,6 +174,10 @@ class LLQuaternion
//static U32 mMultCount;
};
+static_assert(std::is_trivially_copyable::value, "LLQuaternion must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLQuaternion must be trivial move");
+static_assert(std::is_standard_layout::value, "LLQuaternion must be a standard layout type");
+
inline LLSD LLQuaternion::getValue() const
{
LLSD ret;
diff --git a/indra/llmath/llquaternion2.h b/indra/llmath/llquaternion2.h
index 902bfb71342..c9dcc4573fa 100644
--- a/indra/llmath/llquaternion2.h
+++ b/indra/llmath/llquaternion2.h
@@ -49,7 +49,7 @@ class LLQuaternion2
//////////////////////////
// Ctor
- LLQuaternion2() {}
+ LLQuaternion2() = default;
// Ctor from LLQuaternion
explicit LLQuaternion2( const class LLQuaternion& quat );
@@ -102,4 +102,6 @@ class LLQuaternion2
};
+static_assert(std::is_trivial::value, "LLQuaternion2 must be a trivial type");
+
#endif
diff --git a/indra/llmath/llrect.h b/indra/llmath/llrect.h
index 317578da06d..0a3da2fee0c 100644
--- a/indra/llmath/llrect.h
+++ b/indra/llmath/llrect.h
@@ -51,10 +51,6 @@ template class LLRectBase
LLRectBase(): mLeft(0), mTop(0), mRight(0), mBottom(0)
{}
- LLRectBase(const LLRectBase &r):
- mLeft(r.mLeft), mTop(r.mTop), mRight(r.mRight), mBottom(r.mBottom)
- {}
-
LLRectBase(Type left, Type top, Type right, Type bottom):
mLeft(left), mTop(top), mRight(right), mBottom(bottom)
{}
@@ -295,4 +291,8 @@ template LLRectBase LLRectBase::null(0,0,0,0);
typedef LLRectBase LLRect;
typedef LLRectBase LLRectf;
+static_assert(std::is_trivially_copyable::value, "LLRect must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLRect must be trivial move");
+static_assert(std::is_standard_layout::value, "LLRect must be a standard layout type");
+
#endif
diff --git a/indra/llmath/llsimdmath.h b/indra/llmath/llsimdmath.h
index 40953dc2e81..b27b034cf3c 100644
--- a/indra/llmath/llsimdmath.h
+++ b/indra/llmath/llsimdmath.h
@@ -31,16 +31,26 @@
#error "Please include llmath.h before this file."
#endif
-#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 && ADDRESS_SIZE == 32 ) )
-#error SSE2 not enabled. LLVector4a and related class will not compile.
+// the check for this error case must be split into multiple parts
+// because some versions of VS complain about '__SSE2__'
+#if ( ( LL_DARWIN || LL_LINUX ) )
+ #if !(__SSE2__) && !(__arm64__) && !(__aarch64__)
+ #error SSE2 not enabled. LLVector4a and related class will not compile.
+ #endif
+#elif ( LL_WINDOWS && ( _M_IX86_FP < 2 && ADDRESS_SIZE == 32 ) )
+ #error SSE2 not enabled. LLVector4a and related class will not compile.
#endif
#if !LL_WINDOWS
#include
#endif
+#if defined(__arm64__) || defined(__aarch64__)
+#include "sse2neon.h"
+#else
#include
#include
+#endif
#include "llmemory.h"
#include "llsimdtypes.h"
diff --git a/indra/llmath/llsimdtypes.h b/indra/llmath/llsimdtypes.h
index a407f51029e..6c4f55b0c08 100644
--- a/indra/llmath/llsimdtypes.h
+++ b/indra/llmath/llsimdtypes.h
@@ -36,7 +36,7 @@ typedef __m128 LLQuad;
class LLBool32
{
public:
- inline LLBool32() {}
+ inline LLBool32() = default;
inline LLBool32(int rhs) : m_bool(rhs) {}
inline LLBool32(unsigned int rhs) : m_bool(rhs) {}
inline LLBool32(bool rhs) { m_bool = static_cast(rhs); }
@@ -46,13 +46,15 @@ class LLBool32
inline operator bool() const { return static_cast(m_bool); }
private:
- int m_bool{ 0 };
+ int m_bool;
};
+static_assert(std::is_trivial::value, "LLBool32 must be a standard layout type");
+
class LLSimdScalar
{
public:
- inline LLSimdScalar() {}
+ inline LLSimdScalar() = default;
inline LLSimdScalar(LLQuad q)
{
mQ = q;
@@ -100,7 +102,9 @@ class LLSimdScalar
}
private:
- LLQuad mQ{};
+ LLQuad mQ;
};
+static_assert(std::is_trivial::value, "LLSimdScalar must be a standard layout type");
+
#endif //LL_SIMD_TYPES_H
diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h
index 4004852e065..764a3b94e6a 100644
--- a/indra/llmath/llvector4a.h
+++ b/indra/llmath/llvector4a.h
@@ -95,10 +95,7 @@ class alignas(16) LLVector4a
////////////////////////////////////
//LLVector4a is plain data which should never have a default constructor or destructor(malloc&free won't trigger it)
- LLVector4a()
- { //DO NOT INITIALIZE -- The overhead is completely unnecessary
- ll_assert_aligned(this,16);
- }
+ LLVector4a() = default;
LLVector4a(F32 x, F32 y, F32 z, F32 w = 0.f)
{
@@ -361,8 +358,6 @@ class alignas(16) LLVector4a
////////////////////////////////////
// Do NOT add aditional operators without consulting someone with SSE experience
- inline const LLVector4a& operator= ( const LLVector4a& rhs );
-
inline const LLVector4a& operator= ( const LLQuad& rhs );
inline operator LLQuad() const;
@@ -378,9 +373,11 @@ class alignas(16) LLVector4a
};
private:
- LLQuad mQ{};
+ LLQuad mQ;
};
+static_assert(std::is_trivial::value, "LLVector4a must be a trivial type");
+
inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p)
{
min.setMin(min, p);
diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl
index 36dbec078cb..443a46c317f 100644
--- a/indra/llmath/llvector4a.inl
+++ b/indra/llmath/llvector4a.inl
@@ -115,7 +115,7 @@ inline void LLVector4a::set(F32 x, F32 y, F32 z, F32 w)
// Set to all zeros
inline void LLVector4a::clear()
{
- mQ = LLVector4a::getZero().mQ;
+ mQ = _mm_setzero_ps();
}
inline void LLVector4a::splat(const F32 x)
@@ -272,6 +272,9 @@ inline void LLVector4a::setCross3(const LLVector4a& a, const LLVector4a& b)
// Set all elements to the dot product of the x, y, and z elements in a and b
inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b)
{
+#if (defined(__arm64__) || defined(__aarch64__))
+ mQ = _mm_dp_ps(a.mQ, b.mQ, 0x7f);
+#else
// ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] }
const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ );
// yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] }
@@ -284,11 +287,15 @@ inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b)
const __m128i zSplat = _mm_shuffle_epi32(_mm_castps_si128(ab), _MM_SHUFFLE( 2, 2, 2, 2 ));
// mQ = { a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same }
mQ = _mm_add_ps(_mm_castsi128_ps(zSplat), xPlusYSplat);
+#endif
}
// Set all elements to the dot product of the x, y, z, and w elements in a and b
inline void LLVector4a::setAllDot4(const LLVector4a& a, const LLVector4a& b)
{
+#if (defined(__arm64__) || defined(__aarch64__))
+ mQ = _mm_dp_ps(a.mQ, b.mQ, 0xff);
+#else
// ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] }
const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ );
// yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] }
@@ -301,21 +308,29 @@ inline void LLVector4a::setAllDot4(const LLVector4a& a, const LLVector4a& b)
// mQ = { a[W]*b[W] + a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same }
mQ = _mm_add_ps(xPlusYSplat, zPlusWSplat);
+#endif
}
// Return the 3D dot product of this vector and b
inline LLSimdScalar LLVector4a::dot3(const LLVector4a& b) const
{
+#if (defined(__arm64__) || defined(__aarch64__))
+ return _mm_dp_ps(mQ, b.mQ, 0x7f);
+#else
const LLQuad ab = _mm_mul_ps( mQ, b.mQ );
const LLQuad splatY = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128(ab), _MM_SHUFFLE(1, 1, 1, 1) ) );
const LLQuad splatZ = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128(ab), _MM_SHUFFLE(2, 2, 2, 2) ) );
const LLQuad xPlusY = _mm_add_ps( ab, splatY );
return _mm_add_ps( xPlusY, splatZ );
+#endif
}
// Return the 4D dot product of this vector and b
inline LLSimdScalar LLVector4a::dot4(const LLVector4a& b) const
{
+#if (defined(__arm64__) || defined(__aarch64__))
+ return _mm_dp_ps(mQ, b.mQ, 0xff);
+#else
// ab = { w, z, y, x }
const LLQuad ab = _mm_mul_ps( mQ, b.mQ );
// upperProdsInLowerElems = { y, x, y, x }
@@ -325,6 +340,7 @@ inline LLSimdScalar LLVector4a::dot4(const LLVector4a& b) const
// shuffled = { z+x, z+x, z+x, z+x }
const LLQuad shuffled = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( sumOfPairs ), _MM_SHUFFLE(1, 1, 1, 1) ) );
return _mm_add_ss( sumOfPairs, shuffled );
+#endif
}
// Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed
@@ -593,12 +609,6 @@ inline bool LLVector4a::equals3(const LLVector4a& rhs, F32 tolerance ) const
////////////////////////////////////
// Do NOT add aditional operators without consulting someone with SSE experience
-inline const LLVector4a& LLVector4a::operator= ( const LLVector4a& rhs )
-{
- mQ = rhs.mQ;
- return *this;
-}
-
inline const LLVector4a& LLVector4a::operator= ( const LLQuad& rhs )
{
mQ = rhs;
diff --git a/indra/llmath/llvector4logical.h b/indra/llmath/llvector4logical.h
index 70759eef5c9..77cb5862e56 100644
--- a/indra/llmath/llvector4logical.h
+++ b/indra/llmath/llvector4logical.h
@@ -61,7 +61,7 @@ class LLVector4Logical
};
// Empty default ctor
- LLVector4Logical() {}
+ LLVector4Logical() = default;
LLVector4Logical( const LLQuad& quad )
{
@@ -120,7 +120,9 @@ class LLVector4Logical
private:
- LLQuad mQ{};
+ LLQuad mQ;
};
+static_assert(std::is_trivial::value, "LLVector4Logical must be a standard layout type");
+
#endif //LL_VECTOR4ALOGICAL_H
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 7c602536186..b3cb278d599 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -5713,6 +5713,8 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
{
try
{
+ // providing mIndices should help avoid unused vertices
+ // but those should have been filtered out on upload
vert_count = static_cast(meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count));
}
catch (std::bad_alloc&)
@@ -5722,10 +5724,16 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
}
}
- if (vert_count < 65535 && vert_count != 0)
+ // Probably should be using meshopt_remapVertexBuffer instead of remaping manually
+ if (vert_count < 65535 && vert_count > 0)
{
//copy results back into volume
resizeVertices(vert_count);
+ if (mNumVertices == 0)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("LLCoros") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL;
+ }
if (!data.w.empty())
{
@@ -5738,13 +5746,27 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
{
U32 src_idx = i;
U32 dst_idx = remap[i];
- if (dst_idx >= (U32)mNumVertices)
+ if (dst_idx == U32_MAX)
+ {
+ // Unused indices? Probably need to resize mIndices
+ dst_idx = mNumVertices - 1;
+ llassert(false);
+ LL_DEBUGS_ONCE("LLVOLUME") << "U32_MAX destination index, substituting" << LL_ENDL;
+ }
+ else if (dst_idx >= (U32)mNumVertices)
{
dst_idx = mNumVertices - 1;
// Shouldn't happen, figure out what gets returned in remap and why.
llassert(false);
LL_DEBUGS_ONCE("LLVOLUME") << "Invalid destination index, substituting" << LL_ENDL;
}
+ if (src_idx >= (U32)data.p.size())
+ {
+ // data.p.size() is supposed to be equal to mNumIndices
+ src_idx = (U32)(data.p.size() - 1);
+ llassert(false);
+ LL_DEBUGS_ONCE("LLVOLUME") << "Invalid source index, substituting" << LL_ENDL;
+ }
mIndices[i] = dst_idx;
mPositions[dst_idx].load3(data.p[src_idx].mV);
@@ -5778,7 +5800,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
}
else
{
- if (vert_count == 0)
+ if (vert_count <= 0)
{
LL_WARNS_ONCE("LLVOLUME") << "meshopt_generateVertexRemapMulti failed to process a model or model was invalid" << LL_ENDL;
}
diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h
index cd14290246a..36661d2cb0d 100644
--- a/indra/llmath/m3math.h
+++ b/indra/llmath/m3math.h
@@ -142,6 +142,10 @@ class LLMatrix3
friend std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a); // Stream a
};
+static_assert(std::is_trivially_copyable::value, "LLMatrix3 must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLMatrix3 must be trivial move");
+static_assert(std::is_standard_layout::value, "LLMatrix3 must be a standard layout type");
+
inline LLMatrix3::LLMatrix3(void)
{
mMatrix[0][0] = 1.f;
diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp
index a9853fe7e92..1724a50601e 100644
--- a/indra/llmath/m4math.cpp
+++ b/indra/llmath/m4math.cpp
@@ -156,10 +156,6 @@ LLMatrix4::LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw)
mMatrix[3][3] = 1.f;
}
-LLMatrix4::~LLMatrix4(void)
-{
-}
-
// Clear and Assignment Functions
const LLMatrix4& LLMatrix4::setZero()
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h
index b0f8c90cdfd..f164779283a 100644
--- a/indra/llmath/m4math.h
+++ b/indra/llmath/m4math.h
@@ -119,8 +119,6 @@ class LLMatrix4
const LLVector4 &pos); // Initializes Matrix with Euler angles
LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw); // Initializes Matrix with Euler angles
- ~LLMatrix4(void); // Destructor
-
LLSD getValue() const;
void setValue(const LLSD&);
@@ -242,6 +240,10 @@ class LLMatrix4
friend std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a); // Stream a
};
+static_assert(std::is_trivially_copyable::value, "LLMatrix4 must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLMatrix4 must be trivial move");
+static_assert(std::is_standard_layout::value, "LLMatrix4 must be a standard layout type");
+
inline const LLMatrix4& LLMatrix4::setIdentity()
{
mMatrix[0][0] = 1.f;
diff --git a/indra/llmath/tests/llquaternion_test.cpp b/indra/llmath/tests/llquaternion_test.cpp
index aa3c0ad8431..ba18d54d559 100644
--- a/indra/llmath/tests/llquaternion_test.cpp
+++ b/indra/llmath/tests/llquaternion_test.cpp
@@ -349,9 +349,9 @@ namespace tut
ensure(
"2. LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot) failed",
is_approx_equal(-58153.5390f, result.mV[0]) &&
- (183787.8125f == result.mV[1]) &&
- (116864.164063f == result.mV[2]) &&
- (78.099998f == result.mV[3]));
+ is_approx_equal(183787.8125f, result.mV[1]) &&
+ is_approx_equal(116864.164063f, result.mV[2]) &&
+ is_approx_equal(78.099998f, result.mV[3]));
}
//test case for LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot) fn.
diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h
index 6b9d37535b2..b31e4056a38 100644
--- a/indra/llmath/v2math.h
+++ b/indra/llmath/v2math.h
@@ -110,6 +110,9 @@ class LLVector2
friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a
};
+static_assert(std::is_trivially_copyable::value, "LLVector2 must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLVector2 must be trivial move");
+static_assert(std::is_standard_layout::value, "LLVector2 must be a standard layout type");
// Non-member functions
diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h
index 48b36e7c8a1..7357d935996 100644
--- a/indra/llmath/v3color.h
+++ b/indra/llmath/v3color.h
@@ -144,8 +144,11 @@ class LLColor3
inline void exp(); // Do an exponential on the color
};
-LLColor3 lerp(const LLColor3& a, const LLColor3& b, F32 u);
+static_assert(std::is_trivially_copyable::value, "LLColor3 must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLColor3 must be trivial move");
+static_assert(std::is_standard_layout::value, "LLColor3 must be a standard layout type");
+LLColor3 lerp(const LLColor3& a, const LLColor3& b, F32 u);
void LLColor3::clamp()
{
// Clamp the color...
diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h
index fcce2c30eb8..7c56cf138d5 100644
--- a/indra/llmath/v3dmath.h
+++ b/indra/llmath/v3dmath.h
@@ -129,6 +129,10 @@ class LLVector3d
static bool parseVector3d(const std::string& buf, LLVector3d* value);
};
+static_assert(std::is_trivially_copyable::value, "LLVector3d must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLVector3d must be trivial move");
+static_assert(std::is_standard_layout::value, "LLVector3d must be a standard layout type");
+
typedef LLVector3d LLGlobalVec;
inline const LLVector3d &LLVector3d::set(const LLVector3 &vec)
diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h
index 098ca5218c9..196ecdcf7d9 100644
--- a/indra/llmath/v3math.h
+++ b/indra/llmath/v3math.h
@@ -164,6 +164,10 @@ class LLVector3
static bool parseVector3(const std::string& buf, LLVector3* value);
};
+static_assert(std::is_trivially_copyable::value, "LLVector3 must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLVector3 must be trivial move");
+static_assert(std::is_standard_layout::value, "LLVector3 must be a standard layout type");
+
typedef LLVector3 LLSimLocalVec;
// Non-member functions
diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h
index 2f1cb21113b..d48020c2233 100644
--- a/indra/llmath/v4color.h
+++ b/indra/llmath/v4color.h
@@ -231,6 +231,10 @@ class LLColor4
inline void clamp();
};
+static_assert(std::is_trivially_copyable::value, "LLColor4 must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLColor4 must be trivial move");
+static_assert(std::is_standard_layout::value, "LLColor4 must be a standard layout type");
+
// Non-member functions
F32 distVec(const LLColor4& a, const LLColor4& b); // Returns distance between a and b
F32 distVec_squared(const LLColor4& a, const LLColor4& b); // Returns distance squared between a and b
diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h
index bfa998bc58a..e495fd3eea5 100644
--- a/indra/llmath/v4coloru.h
+++ b/indra/llmath/v4coloru.h
@@ -123,6 +123,10 @@ class LLColor4U
static LLColor4U blue;
};
+static_assert(std::is_trivially_copyable::value, "LLColor4U must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLColor4U must be trivial move");
+static_assert(std::is_standard_layout::value, "LLColor4U must be a standard layout type");
+
// Non-member functions
F32 distVec(const LLColor4U& a, const LLColor4U& b); // Returns distance between a and b
F32 distVec_squared(const LLColor4U& a, const LLColor4U& b); // Returns distance squared between a and b
diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h
index 1cbd0d9a783..edfc2f8592b 100644
--- a/indra/llmath/v4math.h
+++ b/indra/llmath/v4math.h
@@ -146,6 +146,10 @@ class LLVector4
friend LLVector4 operator-(const LLVector4 &a); // Return vector -a
};
+static_assert(std::is_trivially_copyable::value, "LLVector4 must be trivial copy");
+static_assert(std::is_trivially_move_assignable::value, "LLVector4 must be trivial move");
+static_assert(std::is_standard_layout::value, "LLVector4 must be a standard layout type");
+
// Non-member functions
F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b
bool are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon = F_APPROXIMATELY_ZERO); // Returns true if a and b are very close to parallel
diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp
index 6a663a8e97c..5c7b1c42350 100644
--- a/indra/llmessage/llcoproceduremanager.cpp
+++ b/indra/llmessage/llcoproceduremanager.cpp
@@ -50,7 +50,7 @@ static const U32 DEFAULT_POOL_SIZE = 5;
// SL-14399: When we teleport to a brand-new simulator, the coprocedure queue
// gets absolutely slammed with fetch requests. Make this queue effectively
// unlimited.
-const U32 LLCoprocedureManager::DEFAULT_QUEUE_SIZE = 1024*1024;
+const U32 LLCoprocedureManager::DEFAULT_QUEUE_SIZE = 1024*512;
//=========================================================================
class LLCoprocedurePool: private boost::noncopyable
@@ -58,7 +58,7 @@ class LLCoprocedurePool: private boost::noncopyable
public:
typedef LLCoprocedureManager::CoProcedure_t CoProcedure_t;
- LLCoprocedurePool(const std::string &name, size_t size);
+ LLCoprocedurePool(const std::string &name, size_t size, size_t queue_size);
~LLCoprocedurePool();
/// Places the coprocedure on the queue for processing.
@@ -118,7 +118,7 @@ class LLCoprocedurePool: private boost::noncopyable
typedef std::shared_ptr CoprocQueuePtr;
std::string mPoolName;
- size_t mPoolSize, mActiveCoprocsCount, mPending;
+ size_t mPoolSize, mQueueSize, mActiveCoprocsCount, mPending;
CoprocQueuePtr mPendingCoprocs;
LLTempBoundListener mStatusListener;
@@ -138,10 +138,25 @@ LLCoprocedureManager::LLCoprocedureManager()
LLCoprocedureManager::~LLCoprocedureManager()
{
- close();
+ try
+ {
+ close();
+ }
+ catch (const boost::fibers::fiber_error&)
+ {
+ LL_WARNS() << "Fiber error during ~LLCoprocedureManager()" << LL_ENDL;
+ }
+ catch (const std::exception& e)
+ {
+ // Shutting down, just log it
+ LL_WARNS() << "Exception during ~LLCoprocedureManager(): " << e.what() << LL_ENDL;
+ }
+ mPropertyQueryFn.clear();
+ mPropertyDefineFn.clear();
+ mPoolMap.clear();
}
-void LLCoprocedureManager::initializePool(const std::string &poolName)
+void LLCoprocedureManager::initializePool(const std::string &poolName, size_t queue_size)
{
poolMap_t::iterator it = mPoolMap.find(poolName);
@@ -180,7 +195,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName)
LL_WARNS("CoProcMgr") << "LLCoprocedureManager: No setting for \"" << keyName << "\" setting pool size to default of " << size << LL_ENDL;
}
- poolPtr_t pool(new LLCoprocedurePool(poolName, size));
+ poolPtr_t pool(new LLCoprocedurePool(poolName, size, queue_size));
LL_ERRS_IF(!pool, "CoprocedureManager") << "Unable to create pool named \"" << poolName << "\" FATAL!" << LL_ENDL;
bool inserted = mPoolMap.emplace(poolName, pool).second;
@@ -212,7 +227,8 @@ void LLCoprocedureManager::setPropertyMethods(SettingQuery_t queryfn, SettingUpd
mPropertyQueryFn = queryfn;
mPropertyDefineFn = updatefn;
- initializePool("Upload");
+ constexpr size_t UPLOAD_QUEUE_SIZE = 2048;
+ initializePool("Upload", UPLOAD_QUEUE_SIZE);
initializePool("AIS"); // it might be better to have some kind of on-demand initialization for AIS
// "ExpCache" pool gets initialized in LLExperienceCache
// asset storage pool gets initialized in LLViewerAssetStorage
@@ -296,17 +312,19 @@ void LLCoprocedureManager::close(const std::string &pool)
}
//=========================================================================
-LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
+LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size, size_t queue_size):
mPoolName(poolName),
mPoolSize(size),
+ mQueueSize(queue_size),
mActiveCoprocsCount(0),
mPending(0),
mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mCoroMapping()
{
+ llassert_always(mQueueSize > mPoolSize); // queue should be able to fit pool
try
{
- mPendingCoprocs = std::make_shared(LLCoprocedureManager::DEFAULT_QUEUE_SIZE);
+ mPendingCoprocs = std::make_shared(mQueueSize);
// store in our LLTempBoundListener so that when the LLCoprocedurePool is
// destroyed, we implicitly disconnect from this LLEventPump
// Monitores application status
@@ -357,11 +375,27 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
mCoroMapping.insert(CoroAdapterMap_t::value_type(pooledCoro, httpAdapter));
}
- LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << LLCoprocedureManager::DEFAULT_QUEUE_SIZE << LL_ENDL;
+ LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << mQueueSize << LL_ENDL;
}
LLCoprocedurePool::~LLCoprocedurePool()
{
+ try
+ {
+ close(); // should have been closed already, but shouldn't hurt
+ mStatusListener.disconnect();
+ mPendingCoprocs.reset();
+ mCoroMapping.clear();
+ }
+ catch (const boost::fibers::fiber_error&)
+ {
+ LL_WARNS() << "Fiber error during ~LLCoprocedurePool() " << mPoolName << LL_ENDL;
+ }
+ catch (const std::exception& e)
+ {
+ // Shutting down, just log it
+ LL_WARNS() << "Exception " << e.what() << " during ~LLCoprocedurePool() in " << mPoolName << LL_ENDL;
+ }
}
//-------------------------------------------------------------------------
@@ -376,7 +410,7 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced
<< "\" at "
<< mPending << LL_ENDL;
- if (mPending >= (LLCoprocedureManager::DEFAULT_QUEUE_SIZE - 1))
+ if (mPending >= (mQueueSize - 1))
{
// If it's all used up (not supposed to happen,
// fetched should cap it), we are going to crash
diff --git a/indra/llmessage/llcoproceduremanager.h b/indra/llmessage/llcoproceduremanager.h
index 6c6e5066545..485333657ca 100644
--- a/indra/llmessage/llcoproceduremanager.h
+++ b/indra/llmessage/llcoproceduremanager.h
@@ -79,7 +79,7 @@ class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager >
void close();
void close(const std::string &pool);
- void initializePool(const std::string &poolName);
+ void initializePool(const std::string &poolName, size_t queue_size = DEFAULT_QUEUE_SIZE);
private:
diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp
index 83a070df320..78cca47456e 100644
--- a/indra/llmessage/llexperiencecache.cpp
+++ b/indra/llmessage/llexperiencecache.cpp
@@ -110,7 +110,8 @@ void LLExperienceCache::initSingleton()
cache_stream >> (*this);
}
- LLCoprocedureManager::instance().initializePool("ExpCache");
+ constexpr size_t CORO_QUEUE_SIZE = 2048;
+ LLCoprocedureManager::instance().initializePool("ExpCache", CORO_QUEUE_SIZE);
LLCoros::instance().launch("LLExperienceCache::idleCoro",
boost::bind(&LLExperienceCache::idleCoro, this));
diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp
index f6ed43a4e4c..a2d09f4f365 100644
--- a/indra/llmessage/llxfermanager.cpp
+++ b/indra/llmessage/llxfermanager.cpp
@@ -1051,7 +1051,7 @@ void LLXferManager::retransmitUnackedPackets()
// Re-build mOutgoingHosts data
updateHostStatus();
- F32 et;
+ F32 et = 0.f;
iter = mSendList.begin();
while (iter != mSendList.end())
{
diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp
index 21dbf35783a..f42cbfdac7a 100644
--- a/indra/llmessage/message_prehash.cpp
+++ b/indra/llmessage/message_prehash.cpp
@@ -714,6 +714,9 @@ char const* const _PREHASH_FirstName = LLMessageStringTable::getInstance()->getS
char const* const _PREHASH_AttachedSoundGainChange = LLMessageStringTable::getInstance()->getString("AttachedSoundGainChange");
char const* const _PREHASH_LocationID = LLMessageStringTable::getInstance()->getString("LocationID");
char const* const _PREHASH_Running = LLMessageStringTable::getInstance()->getString("Running");
+char const* const _PREHASH_Mono = LLMessageStringTable::getInstance()->getString("Mono");
+char const* const _PREHASH_Luau = LLMessageStringTable::getInstance()->getString("Luau");
+char const* const _PREHASH_LuauLanguage = LLMessageStringTable::getInstance()->getString("LuauLanguage");
char const* const _PREHASH_AgentThrottle = LLMessageStringTable::getInstance()->getString("AgentThrottle");
char const* const _PREHASH_NeighborList = LLMessageStringTable::getInstance()->getString("NeighborList");
char const* const _PREHASH_PathTaperX = LLMessageStringTable::getInstance()->getString("PathTaperX");
diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h
index 8a2ad1587c8..53f8123b353 100644
--- a/indra/llmessage/message_prehash.h
+++ b/indra/llmessage/message_prehash.h
@@ -714,6 +714,9 @@ extern char const* const _PREHASH_FirstName;
extern char const* const _PREHASH_AttachedSoundGainChange;
extern char const* const _PREHASH_LocationID;
extern char const* const _PREHASH_Running;
+extern char const* const _PREHASH_Mono;
+extern char const* const _PREHASH_Luau;
+extern char const* const _PREHASH_LuauLanguage;
extern char const* const _PREHASH_AgentThrottle;
extern char const* const _PREHASH_NeighborList;
extern char const* const _PREHASH_PathTaperX;
diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt
index 14a69afe6eb..e008a4093ee 100644
--- a/indra/llplugin/CMakeLists.txt
+++ b/indra/llplugin/CMakeLists.txt
@@ -31,18 +31,10 @@ set(llplugin_HEADER_FILES
llpluginsharedmemory.h
)
-if(NOT ADDRESS_SIZE EQUAL 32)
- if(WINDOWS)
- ##add_definitions(/FIXED:NO)
- else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
- add_definitions(-fPIC)
- endif(WINDOWS)
-endif(NOT ADDRESS_SIZE EQUAL 32)
-
list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES})
add_library (llplugin ${llplugin_SOURCE_FILES})
target_include_directories( llplugin INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
-target_link_libraries( llplugin llcommon llmath llrender llmessage )
+target_link_libraries( llplugin llcommon llmath llmessage llxml )
add_subdirectory(slplugin)
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 8a356da93a9..77a4b08af55 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -132,9 +132,13 @@ void LLPluginClassMedia::reset()
mLastMouseY = 0;
mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
mSleepTime = 1.0f / 100.0f;
+ mCanUndo = false;
+ mCanRedo = false;
mCanCut = false;
mCanCopy = false;
mCanPaste = false;
+ mCanDoDelete = false;
+ mCanSelectAll = false;
mMediaName.clear();
mMediaDescription.clear();
mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
@@ -907,6 +911,18 @@ void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username,
sendMessage(message);
}
+void LLPluginClassMedia::undo()
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_undo");
+ sendMessage(message);
+}
+
+void LLPluginClassMedia::redo()
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_redo");
+ sendMessage(message);
+}
+
void LLPluginClassMedia::cut()
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut");
@@ -925,6 +941,24 @@ void LLPluginClassMedia::paste()
sendMessage(message);
}
+void LLPluginClassMedia::doDelete()
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_delete");
+ sendMessage(message);
+}
+
+void LLPluginClassMedia::selectAll()
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_select_all");
+ sendMessage(message);
+}
+
+void LLPluginClassMedia::showPageSource()
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_show_source");
+ sendMessage(message);
+}
+
void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path_cache,
const std::string &username,
const std::string &user_data_path_cef_log)
@@ -1178,6 +1212,14 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
}
else if(message_name == "edit_state")
{
+ if(message.hasValue("undo"))
+ {
+ mCanUndo = message.getValueBoolean("undo");
+ }
+ if(message.hasValue("redo"))
+ {
+ mCanRedo = message.getValueBoolean("redo");
+ }
if(message.hasValue("cut"))
{
mCanCut = message.getValueBoolean("cut");
@@ -1190,6 +1232,14 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
mCanPaste = message.getValueBoolean("paste");
}
+ if (message.hasValue("delete"))
+ {
+ mCanDoDelete = message.getValueBoolean("delete");
+ }
+ if (message.hasValue("select_all"))
+ {
+ mCanSelectAll = message.getValueBoolean("select_all");
+ }
}
else if(message_name == "name_text")
{
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index d74b790d8f7..71522bcd7d5 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -29,7 +29,6 @@
#ifndef LL_LLPLUGINCLASSMEDIA_H
#define LL_LLPLUGINCLASSMEDIA_H
-#include "llgltypes.h"
#include "llpluginprocessparent.h"
#include "llrect.h"
#include "llpluginclassmediaowner.h"
@@ -201,6 +200,12 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; }
+ void undo();
+ bool canUndo() const { return mCanUndo; };
+
+ void redo();
+ bool canRedo() const { return mCanRedo; };
+
void cut();
bool canCut() const { return mCanCut; };
@@ -210,6 +215,14 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
void paste();
bool canPaste() const { return mCanPaste; };
+ void doDelete();
+ bool canDoDelete() const { return mCanDoDelete; };
+
+ void selectAll();
+ bool canSelectAll() const { return mCanSelectAll; };
+
+ void showPageSource();
+
// These can be called before init(), and they will be queued and sent before the media init message.
void setUserDataPath(const std::string &user_data_path_cache, const std::string &username, const std::string &user_data_path_cef_log);
void setLanguageCode(const std::string &language_code);
@@ -351,9 +364,9 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true
S32 mRequestedTextureDepth;
- LLGLenum mRequestedTextureInternalFormat;
- LLGLenum mRequestedTextureFormat;
- LLGLenum mRequestedTextureType;
+ U32 mRequestedTextureInternalFormat;
+ U32 mRequestedTextureFormat;
+ U32 mRequestedTextureType;
bool mRequestedTextureSwapBytes;
bool mRequestedTextureCoordsOpenGL;
@@ -419,9 +432,13 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
F64 mSleepTime;
+ bool mCanUndo;
+ bool mCanRedo;
bool mCanCut;
bool mCanCopy;
bool mCanPaste;
+ bool mCanDoDelete;
+ bool mCanSelectAll;
std::string mMediaName;
std::string mMediaDescription;
diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt
index 0ea6495eaca..4df3e306cbf 100644
--- a/indra/llplugin/slplugin/CMakeLists.txt
+++ b/indra/llplugin/slplugin/CMakeLists.txt
@@ -30,18 +30,6 @@ add_executable(SLPlugin
${SLPlugin_SOURCE_FILES}
)
-if (WINDOWS)
-set_target_properties(SLPlugin
- PROPERTIES
- LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMTD\""
- )
-else ()
-set_target_properties(SLPlugin
- PROPERTIES
- MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist
- )
-endif ()
-
target_link_libraries(SLPlugin
llplugin
llmessage
@@ -49,7 +37,20 @@ target_link_libraries(SLPlugin
ll::pluginlibraries
)
-if (DARWIN)
+if (WINDOWS)
+ set_target_properties(SLPlugin
+ PROPERTIES
+ LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMTD\""
+ )
+elseif (DARWIN)
+ set_target_properties(SLPlugin
+ PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1
+ INSTALL_RPATH "@executable_path/../../../../Frameworks;@executable_path/../Frameworks;@executable_path/../Frameworks/plugins"
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist
+ XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym"
+ )
+
# Make sure the app bundle has a Resources directory (it will get populated by viewer-manifest.py later)
add_custom_command(
TARGET SLPlugin POST_BUILD
@@ -58,7 +59,7 @@ if (DARWIN)
-p
${CMAKE_CURRENT_BINARY_DIR}/$,$,>/SLPlugin.app/Contents/Resources
)
-endif (DARWIN)
+endif ()
if (LL_TESTS)
ll_deploy_sharedlibs_command(SLPlugin)
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index bfcd84a43df..81ebe631c5a 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -1319,7 +1319,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
{
//Build a joint for the resolver to work with
char str[64]={0};
- sprintf(str,"./%s",(*jointIt).first.c_str() );
+ snprintf(str, sizeof(str), "./%s",(*jointIt).first.c_str() );
//LL_WARNS()<<"Joint "<< str <& object, const char* key, const LLVector2& default_value);
static F32 floatFromJson(const std::map& object, const char* key, const F32 default_value);
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index 5f046642673..d37b16ce0ca 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -56,9 +56,9 @@
FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL;
-LLFontManager *gFontManagerp = NULL;
+LLFontManager *gFontManagerp = nullptr;
-FT_Library gFTLibrary = NULL;
+FT_Library gFTLibrary = nullptr;
//static
void LLFontManager::initClass()
@@ -73,7 +73,7 @@ void LLFontManager::initClass()
void LLFontManager::cleanupClass()
{
delete gFontManagerp;
- gFontManagerp = NULL;
+ gFontManagerp = nullptr;
}
LLFontManager::LLFontManager()
@@ -101,6 +101,7 @@ LLFontManager::LLFontManager()
LLFontManager::~LLFontManager()
{
FT_Done_FreeType(gFTLibrary);
+ unloadAllFonts();
}
@@ -139,12 +140,8 @@ LLFontFreetype::LLFontFreetype()
mAscender(0.f),
mDescender(0.f),
mLineHeight(0.f),
-#ifdef LL_WINDOWS
- pFileStream(NULL),
- pFtStream(NULL),
-#endif
mIsFallback(false),
- mFTFace(NULL),
+ mFTFace(nullptr),
mRenderGlyphCount(0),
mStyle(0),
mPointSize(0)
@@ -157,35 +154,16 @@ LLFontFreetype::~LLFontFreetype()
// Clean up freetype libs.
if (mFTFace)
FT_Done_Face(mFTFace);
- mFTFace = NULL;
+ mFTFace = nullptr;
// Delete glyph info
std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer());
mCharGlyphInfoMap.clear();
-#ifdef LL_WINDOWS
- delete pFileStream; // closed by FT_Done_Face
- delete pFtStream;
-#endif
delete mFontBitmapCachep;
// mFallbackFonts cleaned up by LLPointer destructor
}
-#ifdef LL_WINDOWS
-unsigned long ft_read_cb(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) {
- if (count <= 0) return count;
- llifstream *file_stream = static_cast(stream->descriptor.pointer);
- file_stream->seekg(offset, std::ios::beg);
- file_stream->read((char*)buffer, count);
- return (unsigned long)file_stream->gcount();
-}
-
-void ft_close_cb(FT_Stream stream) {
- llifstream *file_stream = static_cast(stream->descriptor.pointer);
- file_stream->close();
-}
-#endif
-
bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n)
{
// Don't leak face objects. This is also needed to deal with
@@ -193,26 +171,21 @@ bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
if (mFTFace)
{
FT_Done_Face(mFTFace);
- mFTFace = NULL;
+ mFTFace = nullptr;
}
- int error;
-#ifdef LL_WINDOWS
- error = ftOpenFace(filename, face_n);
-#else
- error = FT_New_Face( gFTLibrary,
- filename.c_str(),
- 0,
- &mFTFace);
-#endif
+ FT_Open_Args openArgs;
+ memset( &openArgs, 0, sizeof( openArgs ) );
+ openArgs.memory_base = gFontManagerp->loadFont( filename, openArgs.memory_size );
+
+ if( !openArgs.memory_base )
+ return false;
+
+ openArgs.flags = FT_OPEN_MEMORY;
+ int error = FT_Open_Face( gFTLibrary, &openArgs, 0, &mFTFace );
if (error)
- {
-#ifdef LL_WINDOWS
- clearFontStreams();
-#endif
return false;
- }
mIsFallback = is_fallback;
F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi
@@ -227,10 +200,8 @@ bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
{
// Clean up freetype libs.
FT_Done_Face(mFTFace);
-#ifdef LL_WINDOWS
- clearFontStreams();
-#endif
- mFTFace = NULL;
+
+ mFTFace = nullptr;
return false;
}
@@ -286,73 +257,30 @@ S32 LLFontFreetype::getNumFaces(const std::string& filename)
if (mFTFace)
{
FT_Done_Face(mFTFace);
- mFTFace = NULL;
+ mFTFace = nullptr;
}
S32 num_faces = 1;
-#ifdef LL_WINDOWS
- int error = ftOpenFace(filename, 0);
+ FT_Open_Args openArgs;
+ memset( &openArgs, 0, sizeof( openArgs ) );
+ openArgs.memory_base = gFontManagerp->loadFont( filename, openArgs.memory_size );
+ if( !openArgs.memory_base )
+ return 0;
+ openArgs.flags = FT_OPEN_MEMORY;
+ int error = FT_Open_Face( gFTLibrary, &openArgs, 0, &mFTFace );
if (error)
- {
return 0;
- }
else
- {
num_faces = mFTFace->num_faces;
- }
FT_Done_Face(mFTFace);
- clearFontStreams();
- mFTFace = NULL;
-#endif
+ mFTFace = nullptr;
return num_faces;
}
-#ifdef LL_WINDOWS
-S32 LLFontFreetype::ftOpenFace(const std::string& filename, S32 face_n)
-{
- S32 error = -1;
- pFileStream = new llifstream(filename, std::ios::binary);
- if (pFileStream->is_open())
- {
- std::streampos beg = pFileStream->tellg();
- pFileStream->seekg(0, std::ios::end);
- std::streampos end = pFileStream->tellg();
- std::size_t file_size = end - beg;
- pFileStream->seekg(0, std::ios::beg);
-
- pFtStream = new LLFT_Stream();
- pFtStream->base = 0;
- pFtStream->pos = 0;
- pFtStream->size = static_cast(file_size);
- pFtStream->descriptor.pointer = pFileStream;
- pFtStream->read = ft_read_cb;
- pFtStream->close = ft_close_cb;
-
- FT_Open_Args args;
- args.flags = FT_OPEN_STREAM;
- args.stream = (FT_StreamRec*)pFtStream;
- error = FT_Open_Face(gFTLibrary, &args, face_n, &mFTFace);
- }
- return error;
-}
-
-void LLFontFreetype::clearFontStreams()
-{
- if (pFileStream)
- {
- pFileStream->close();
- }
- delete pFileStream;
- delete pFtStream;
- pFileStream = NULL;
- pFtStream = NULL;
-}
-#endif
-
void LLFontFreetype::addFallbackFont(const LLPointer& fallback_font,
const char_functor_t& functor)
{
@@ -376,7 +304,7 @@ F32 LLFontFreetype::getDescenderHeight() const
F32 LLFontFreetype::getXAdvance(llwchar wch) const
{
- if (mFTFace == NULL)
+ if (mFTFace == nullptr)
return 0.0;
// Return existing info only if it is current
@@ -400,7 +328,7 @@ F32 LLFontFreetype::getXAdvance(llwchar wch) const
F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const
{
- if (mFTFace == NULL)
+ if (mFTFace == nullptr)
return 0.0;
return glyph->mXAdvance;
@@ -408,7 +336,7 @@ F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const
F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const
{
- if (mFTFace == NULL)
+ if (mFTFace == nullptr)
return 0.0;
//llassert(!mIsFallback);
@@ -427,7 +355,7 @@ F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const
F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const
{
- if (mFTFace == NULL)
+ if (mFTFace == nullptr)
return 0.0;
U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0;
@@ -450,7 +378,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type
{
if (!mFTFace)
{
- return NULL;
+ return nullptr;
}
llassert(!mIsFallback);
@@ -541,14 +469,14 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type
{
return addGlyphFromFont(this, wch, glyph_index, glyph_type);
}
- return NULL;
+ return nullptr;
}
LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType requested_glyph_type) const
{
LL_PROFILE_ZONE_SCOPED;
- if (mFTFace == NULL)
- return NULL;
+ if (mFTFace == nullptr)
+ return nullptr;
llassert(!mIsFallback);
fontp->renderGlyph(requested_glyph_type, glyph_index, wch);
@@ -600,7 +528,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
{
U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer;
S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch;
- U8 *tmp_graydata = NULL;
+ U8 *tmp_graydata = nullptr;
if (fontp->mFTFace->glyph->bitmap.pixel_mode
== FT_PIXEL_MODE_MONO)
@@ -704,7 +632,7 @@ void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, llwchar wch) const
{
- if (mFTFace == NULL)
+ if (mFTFace == nullptr)
return;
FT_Int32 load_flags = FT_LOAD_FORCE_AUTOHINT;
@@ -918,3 +846,58 @@ void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32
}
}
+
+namespace ll
+{
+ namespace fonts
+ {
+ class LoadedFont
+ {
+ public:
+ LoadedFont( std::string aName , std::string const &aAddress, std::size_t aSize )
+ : mAddress( aAddress )
+ {
+ mName = aName;
+ mSize = aSize;
+ mRefs = 1;
+ }
+ std::string mName;
+ std::string mAddress;
+ std::size_t mSize;
+ U32 mRefs;
+ };
+ }
+}
+
+U8 const* LLFontManager::loadFont( std::string const &aFilename, long &a_Size)
+{
+ a_Size = 0;
+ std::map< std::string, std::shared_ptr >::iterator itr = m_LoadedFonts.find( aFilename );
+ if( itr != m_LoadedFonts.end() )
+ {
+ ++itr->second->mRefs;
+ // A possible overflow cannot happen here, as it is asserted that the size is less than std::numeric_limits::max() a few lines below.
+ a_Size = static_cast(itr->second->mSize);
+ return reinterpret_cast(itr->second->mAddress.c_str());
+ }
+
+ auto strContent = LLFile::getContents(aFilename);
+
+ if( strContent.empty() )
+ return nullptr;
+
+ // For fontconfig a type of long is required, std::string::size() returns size_t. I think it is safe to limit this to 2GiB and not support fonts that huge (can that even be a thing?)
+ llassert_always( strContent.size() < std::numeric_limits::max() );
+
+ a_Size = static_cast(strContent.size());
+
+ auto pCache = std::make_shared( aFilename, strContent, a_Size );
+ itr = m_LoadedFonts.insert( std::make_pair( aFilename, pCache ) ).first;
+
+ return reinterpret_cast(itr->second->mAddress.c_str());
+}
+
+void LLFontManager::unloadAllFonts()
+{
+ m_LoadedFonts.clear();
+}
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index 783bf4a4b30..a9b3a944ee2 100644
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
@@ -43,15 +43,28 @@ typedef struct FT_FaceRec_* LLFT_Face;
struct FT_StreamRec_;
typedef struct FT_StreamRec_ LLFT_Stream;
+namespace ll
+{
+ namespace fonts
+ {
+ class LoadedFont;
+ }
+}
+
class LLFontManager
{
public:
static void initClass();
static void cleanupClass();
+ U8 const *loadFont( std::string const &aFilename, long &a_Size );
+
private:
LLFontManager();
~LLFontManager();
+
+ void unloadAllFonts();
+ std::map< std::string, std::shared_ptr > m_LoadedFonts;
};
struct LLFontGlyphInfo
@@ -90,11 +103,6 @@ class LLFontFreetype : public LLRefCount
S32 getNumFaces(const std::string& filename);
-#ifdef LL_WINDOWS
- S32 ftOpenFace(const std::string& filename, S32 face_n);
- void clearFontStreams();
-#endif
-
typedef std::function char_functor_t;
void addFallbackFont(const LLPointer& fallback_font, const char_functor_t& functor = nullptr);
@@ -170,11 +178,6 @@ class LLFontFreetype : public LLRefCount
LLFT_Face mFTFace;
-#ifdef LL_WINDOWS
- llifstream *pFileStream;
- LLFT_Stream *pFtStream;
-#endif
-
bool mIsFallback;
typedef std::pair, char_functor_t> fallback_font_t;
typedef std::vector fallback_font_vector_t;
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 0be27b89757..d13b98e2747 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -1123,17 +1123,6 @@ bool LLGLManager::initGL()
if (mGLVersion >= 2.f)
{
parse_glsl_version(mGLSLVersionMajor, mGLSLVersionMinor);
-
-#if 0 && LL_DARWIN
- // TODO maybe switch to using a core profile for GL 3.2?
- // https://stackoverflow.com/a/19868861
- //never use GLSL greater than 1.20 on OSX
- if (mGLSLVersionMajor > 1 || mGLSLVersionMinor > 30)
- {
- mGLSLVersionMajor = 1;
- mGLSLVersionMinor = 30;
- }
-#endif
}
if (mGLVersion >= 2.1f && LLImageGL::sCompressTextures)
@@ -1247,7 +1236,7 @@ bool LLGLManager::initGL()
// there's some implementation that reports a crazy value
mMaxUniformBlockSize = llmin(mMaxUniformBlockSize, 65536);
- if (mGLVersion >= 4.59f)
+ if (mHasAnisotropic)
{
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &mMaxAnisotropy);
}
@@ -1411,6 +1400,11 @@ void LLGLManager::initExtensions()
mHasCubeMapArray = mGLVersion >= 3.99f;
mHasTransformFeedback = mGLVersion >= 3.99f;
mHasDebugOutput = mGLVersion >= 4.29f;
+ mHasAnisotropic = mGLVersion >= 4.59f;
+ if(!mHasAnisotropic && gGLHExts.mSysExts)
+ {
+ mHasAnisotropic = ExtensionExists("GL_EXT_texture_filter_anisotropic", gGLHExts.mSysExts);
+ }
// Misc
glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange);
@@ -2728,7 +2722,7 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
if(cplane[2] < 0)
cplane *= -1;
- glm::mat4 suffix;
+ glm::mat4 suffix = glm::identity();
suffix = glm::row(suffix, 2, cplane);
glm::mat4 newP = suffix * P;
gGL.matrixMode(LLRender::MM_PROJECTION);
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 3735a991090..9cd5dc8145b 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -421,8 +421,11 @@ bool LLGLSLShader::createShader()
llassert_always(!mShaderFiles.empty());
#if LL_DARWIN
- // work-around missing mix(vec3,vec3,bvec3)
- mDefines["OLD_SELECT"] = "1";
+ if(!gGLManager.mIsApple)
+ {
+ // work-around missing mix(vec3,vec3,bvec3)
+ mDefines["OLD_SELECT"] = "1";
+ }
#endif
mShaderHash = hash();
@@ -543,7 +546,7 @@ bool LLGLSLShader::createShader()
}
}
-#ifdef LL_PROFILER_ENABLE_RENDER_DOC
+#if LL_PROFILER_ENABLE_RENDER_DOC
setLabel(mName.c_str());
#endif
@@ -2078,7 +2081,7 @@ LLUUID LLGLSLShader::hash()
return hash_obj.digest();
}
-#ifdef LL_PROFILER_ENABLE_RENDER_DOC
+#if LL_PROFILER_ENABLE_RENDER_DOC
void LLGLSLShader::setLabel(const char* label) {
LL_LABEL_OBJECT_GL(GL_PROGRAM, mProgramObject, strlen(label), label);
}
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 873ab0cff59..4702a27cc54 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -361,7 +361,7 @@ class LLGLSLShader
// hacky flag used for optimization in LLDrawPoolAlpha
bool mCanBindFast = false;
-#ifdef LL_PROFILER_ENABLE_RENDER_DOC
+#if LL_PROFILER_ENABLE_RENDER_DOC
void setLabel(const char* label);
#endif
@@ -381,7 +381,7 @@ extern LLGLSLShader gSolidColorProgram;
//Alpha mask shader (declared here so llappearance can access properly)
extern LLGLSLShader gAlphaMaskProgram;
-#ifdef LL_PROFILER_ENABLE_RENDER_DOC
+#if LL_PROFILER_ENABLE_RENDER_DOC
#define LL_SET_SHADER_LABEL(shader) shader.setLabel(#shader)
#else
#define LL_SET_SHADER_LABEL(shader, label)
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 1db36d91f9e..97ea6f67bd8 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -338,6 +338,7 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)
case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac
case GL_DEPTH_COMPONENT: return 24;
case GL_DEPTH_COMPONENT24: return 24;
+ case GL_RGBA16: return 64;
case GL_R16F: return 16;
case GL_RG16F: return 32;
case GL_RGB16F: return 48;
@@ -1096,6 +1097,8 @@ void sub_image_lines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 w
// full width texture, do 32 lines at a time
for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += batch_size)
{
+ // If this keeps crashing, pass down data_size, looks like it is using
+ // imageraw->getData(); for data, but goes way over allocated size limit
glTexSubImage2D(target, miplevel, x_offset, y_pos, width, batch_size, pixformat, pixtype, src);
src += line_width * batch_size;
}
@@ -1105,6 +1108,8 @@ void sub_image_lines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 w
// partial width or strange height
for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += 1)
{
+ // If this keeps crashing, pass down data_size, looks like it is using
+ // imageraw->getData(); for data, but goes way over allocated size limit
glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src);
src += line_width;
}
@@ -1545,6 +1550,7 @@ bool LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
llassert(mCurrentDiscardLevel >= 0);
discard_level = mCurrentDiscardLevel;
}
+ discard_level = llmin(discard_level, MAX_DISCARD_LEVEL);
// Actual image width/height = raw image width/height * 2^discard_level
S32 raw_w = imageraw->getWidth() ;
@@ -1643,6 +1649,7 @@ bool LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, bool data_
discard_level = mCurrentDiscardLevel;
}
discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
+ discard_level = llmin(discard_level, MAX_DISCARD_LEVEL);
if (main_thread // <--- always force creation of new_texname when not on main thread ...
&& !defer_copy // <--- ... or defer copy is set
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 1dc87a66cea..57be8570afb 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -118,7 +118,7 @@ static const GLenum sGLBlendFactor[] =
LLTexUnit::LLTexUnit(S32 index)
: mCurrTexType(TT_NONE),
- mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0),
+ mCurrTexture(0),
mHasMipMaps(false),
mIndex(index)
{
@@ -207,6 +207,12 @@ void LLTexUnit::bindFast(LLTexture* texture)
}
glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture);
mHasMipMaps = gl_tex->mHasMipMaps;
+ if (gl_tex->mTexOptionsDirty)
+ {
+ gl_tex->mTexOptionsDirty = false;
+ setTextureAddressModeFast(gl_tex->mAddressMode, gl_tex->getTarget());
+ setTextureFilteringOptionFast(gl_tex->mFilterOption, gl_tex->getTarget());
+ }
}
bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
@@ -461,11 +467,16 @@ void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode)
activate();
- glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]);
- glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]);
- if (mCurrTexType == TT_CUBE_MAP)
+ setTextureAddressModeFast(mode, mCurrTexType);
+}
+
+void LLTexUnit::setTextureAddressModeFast(eTextureAddressMode mode, eTextureType tex_type)
+{
+ glTexParameteri(sGLTextureType[tex_type], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]);
+ glTexParameteri(sGLTextureType[tex_type], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]);
+ if (tex_type == TT_CUBE_MAP || tex_type == TT_CUBE_MAP_ARRAY || tex_type == TT_TEXTURE_3D)
{
- glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]);
+ glTexParameteri(sGLTextureType[tex_type], GL_TEXTURE_WRAP_R, sGLAddressMode[mode]);
}
}
@@ -475,51 +486,56 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
gGL.flush();
+ setTextureFilteringOptionFast(option, mCurrTexType);
+}
+
+void LLTexUnit::setTextureFilteringOptionFast(LLTexUnit::eTextureFilterOptions option, eTextureType tex_type)
+{
if (option == TFO_POINT)
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(sGLTextureType[tex_type], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
else
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(sGLTextureType[tex_type], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
if (option >= TFO_TRILINEAR && mHasMipMaps)
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(sGLTextureType[tex_type], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else if (option >= TFO_BILINEAR)
{
if (mHasMipMaps)
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameteri(sGLTextureType[tex_type], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
}
else
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(sGLTextureType[tex_type], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
}
else
{
if (mHasMipMaps)
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(sGLTextureType[tex_type], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
}
else
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(sGLTextureType[tex_type], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}
- if (gGLManager.mGLVersion >= 4.59f)
+ if (gGLManager.mHasAnisotropic)
{
if (LLImageGL::sGlobalUseAnisotropic && option == TFO_ANISOTROPIC)
{
- glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY, gGLManager.mMaxAnisotropy);
+ glTexParameterf(sGLTextureType[tex_type], GL_TEXTURE_MAX_ANISOTROPY, gGLManager.mMaxAnisotropy);
}
else
{
- glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY, 1.f);
+ glTexParameterf(sGLTextureType[tex_type], GL_TEXTURE_MAX_ANISOTROPY, 1.f);
}
}
}
@@ -600,26 +616,6 @@ GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha)
}
}
-void LLTexUnit::setColorScale(S32 scale)
-{
- if (mCurrColorScale != scale || gGL.mDirty)
- {
- mCurrColorScale = scale;
- gGL.flush();
- glTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE, scale );
- }
-}
-
-void LLTexUnit::setAlphaScale(S32 scale)
-{
- if (mCurrAlphaScale != scale || gGL.mDirty)
- {
- mCurrAlphaScale = scale;
- gGL.flush();
- glTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale );
- }
-}
-
// Useful for debugging that you've manually assigned a texture operation to the correct
// texture unit based on the currently set active texture in opengl.
void LLTexUnit::debugTextureUnit(void)
@@ -1283,9 +1279,7 @@ void LLRender::translateUI(F32 x, F32 y, F32 z)
LL_ERRS() << "Need to push a UI translation frame before offsetting" << LL_ENDL;
}
- mUIOffset.back().mV[0] += x;
- mUIOffset.back().mV[1] += y;
- mUIOffset.back().mV[2] += z;
+ mUIOffset.back().add(LLVector4a(x, y, z));
}
void LLRender::scaleUI(F32 x, F32 y, F32 z)
@@ -1295,14 +1289,14 @@ void LLRender::scaleUI(F32 x, F32 y, F32 z)
LL_ERRS() << "Need to push a UI transformation frame before scaling." << LL_ENDL;
}
- mUIScale.back().scaleVec(LLVector3(x,y,z));
+ mUIScale.back().mul(LLVector4a(x, y, z));
}
void LLRender::pushUIMatrix()
{
if (mUIOffset.empty())
{
- mUIOffset.emplace_back(0.f,0.f,0.f);
+ mUIOffset.emplace_back(0.f);
}
else
{
@@ -1311,7 +1305,7 @@ void LLRender::pushUIMatrix()
if (mUIScale.empty())
{
- mUIScale.emplace_back(1.f,1.f,1.f);
+ mUIScale.emplace_back(1.f);
}
else
{
@@ -1333,18 +1327,20 @@ LLVector3 LLRender::getUITranslation()
{
if (mUIOffset.empty())
{
- return LLVector3(0,0,0);
+ return LLVector3::zero;
}
- return mUIOffset.back();
+
+ return LLVector3(mUIOffset.back().getF32ptr());
}
LLVector3 LLRender::getUIScale()
{
if (mUIScale.empty())
{
- return LLVector3(1,1,1);
+ return LLVector3::all_one;
}
- return mUIScale.back();
+
+ return LLVector3(mUIScale.back().getF32ptr());
}
@@ -1354,8 +1350,9 @@ void LLRender::loadUIIdentity()
{
LL_ERRS() << "Need to push UI translation frame before clearing offset." << LL_ENDL;
}
- mUIOffset.back().setVec(0,0,0);
- mUIScale.back().setVec(1,1,1);
+
+ mUIOffset.back().clear();
+ mUIScale.back().splat(1);
}
void LLRender::setColorMask(bool writeColor, bool writeAlpha)
@@ -1783,8 +1780,10 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
}
else
{
- LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back());
- mVerticesp[mCount].set(vert.mV[VX], vert.mV[VY], vert.mV[VZ]);
+ LLVector4a vert(x, y, z);
+ vert.add(mUIOffset.back());
+ vert.mul(mUIScale.back());
+ mVerticesp[mCount] = vert;
}
mCount++;
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 7b6bd4198b7..0801c12fb4c 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -43,6 +43,7 @@
#include "llglheaders.h"
#include "llmatrix4a.h"
#include "glm/mat4x4.hpp"
+#include
#include
#include
@@ -207,11 +208,15 @@ class LLTexUnit
// Warning: this stays set for the bound texture forever,
// make sure you want to permanently change the address mode for the bound texture.
void setTextureAddressMode(eTextureAddressMode mode);
+ // MUST already be active and bound
+ void setTextureAddressModeFast(eTextureAddressMode mode, eTextureType tex_type);
// Sets the filtering options used to sample the texture
// Warning: this stays set for the bound texture forever,
// make sure you want to permanently change the filtering for the bound texture.
void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option);
+ // MUST already be active and bound
+ void setTextureFilteringOptionFast(LLTexUnit::eTextureFilterOptions option, eTextureType tex_type);
static U32 getInternalType(eTextureType type);
@@ -227,13 +232,9 @@ class LLTexUnit
S32 mIndex;
U32 mCurrTexture;
eTextureType mCurrTexType;
- S32 mCurrColorScale;
- S32 mCurrAlphaScale;
bool mHasMipMaps;
void debugTextureUnit(void);
- void setColorScale(S32 scale);
- void setAlphaScale(S32 scale);
GLint getTextureSource(eTextureBlendSrc src);
GLint getTextureSourceType(eTextureBlendSrc src, bool isAlpha = false);
};
@@ -526,8 +527,8 @@ class LLRender
eBlendFactor mCurrBlendAlphaSFactor;
eBlendFactor mCurrBlendAlphaDFactor;
- std::vector