Merge branch 'FirestormViewer:master' into Fire-30873-NewPoser

master
Angeldark Raymaker 2024-09-20 19:54:52 +01:00 committed by GitHub
commit 636eae0e59
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
815 changed files with 16900 additions and 15377 deletions

View File

@ -40,7 +40,7 @@ CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
Cpp11BracedListStyle: false
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
@ -87,7 +87,7 @@ PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Right
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
@ -95,7 +95,7 @@ SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements

View File

@ -1,5 +1,6 @@
# Replace tabs with spaces
1b68f71348ecf3983b76b40d7940da8377f049b7
33418a77b716e122da9778869cdbabe97c83ff37
# Trim trailing whitespace
a0b3021bdcf76859054fda8e30abb3ed47749e83
8444cd9562a6a7b755fcb075864e205122354192

View File

@ -7,14 +7,14 @@ on:
tags: ["Second_Life*"]
jobs:
# The whole point of the setvar job is that we want to set a variable once
# that will be consumed by multiple subsequent jobs. We tried setting it in
# the global env, but a job.env can't directly reference the global env
# context.
setvar:
# The whole point of the setup job is that we want to set variables once
# that will be consumed by multiple subsequent jobs.
setup:
runs-on: ubuntu-latest
outputs:
release_run: ${{ steps.setvar.outputs.release_run }}
configurations: ${{ steps.setvar.outputs.configurations }}
bugsplat_db: ${{ steps.setvar.outputs.bugsplat_db }}
env:
# Build with a tag like "Second_Life#abcdef0" to generate a release page
# (used for builds we are planning to deploy).
@ -22,33 +22,36 @@ jobs:
# important to ensure it's the empty string when false. If you omit || '',
# its value when false is "false", which is interpreted as true.
RELEASE_RUN: ${{ (github.event.inputs.release_run || github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life')) && 'Y' || '' }}
FROM_FORK: ${{ github.event.pull_request.head.repo.fork }}
steps:
- name: Set Variable
- name: Set Variables
id: setvar
shell: bash
run: |
echo "release_run=$RELEASE_RUN" >> "$GITHUB_OUTPUT"
if [[ "$FROM_FORK" == "true" ]]; then
# PR from fork; don't build with Bugsplat, proprietary libs
echo 'configurations=["ReleaseOS"]' >> $GITHUB_OUTPUT
echo "bugsplat_db=" >> $GITHUB_OUTPUT
else
echo 'configurations=["Release"]' >> $GITHUB_OUTPUT
echo "bugsplat_db=SecondLife_Viewer_2018" >> $GITHUB_OUTPUT
fi
build:
needs: setvar
needs: setup
strategy:
matrix:
runner: [windows-large, macos-12-xl]
configuration: [Release]
Linden: [true]
include:
- runner: macos-12-xl
developer_dir: "/Applications/Xcode_14.0.1.app/Contents/Developer"
- runner: windows-large
configuration: ReleaseOS
Linden: false
configuration: ${{ fromJSON(needs.setup.outputs.configurations) }}
runs-on: ${{ matrix.runner }}
outputs:
viewer_channel: ${{ steps.build.outputs.viewer_channel }}
viewer_version: ${{ steps.build.outputs.viewer_version }}
viewer_branch: ${{ steps.which-branch.outputs.branch }}
relnotes: ${{ steps.which-branch.outputs.relnotes }}
imagename: ${{ steps.build.outputs.imagename }}
imagename: ${{ steps.build.outputs.imagename }}
configuration: ${{ matrix.configuration }}
env:
AUTOBUILD_ADDRSIZE: 64
AUTOBUILD_BUILD_ID: ${{ github.run_id }}
@ -61,12 +64,9 @@ jobs:
# autobuild-package.xml.
AUTOBUILD_VCS_INFO: "true"
AUTOBUILD_VSVER: "170"
DEVELOPER_DIR: ${{ matrix.developer_dir }}
DEVELOPER_DIR: "/Applications/Xcode_14.0.1.app/Contents/Developer"
# Ensure that Linden viewer builds engage Bugsplat.
BUGSPLAT_DB: ${{ matrix.Linden && 'SecondLife_Viewer_2018' || '' }}
# Run BUILD steps for Release configuration.
# Run BUILD steps for ReleaseOS configuration only for release runs.
BUILD: ${{ (matrix.Linden || needs.setvar.outputs.release_run) && 'Y' || '' }}
BUGSPLAT_DB: ${{ needs.setup.outputs.bugsplat_db }}
build_coverity: false
build_log_dir: ${{ github.workspace }}/.logs
build_viewer: true
@ -85,19 +85,16 @@ jobs:
variants: ${{ matrix.configuration }}
steps:
- name: Checkout code
if: env.BUILD
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Setup python
if: env.BUILD
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Checkout build variables
if: env.BUILD
uses: actions/checkout@v4
with:
repository: secondlife/build-variables
@ -105,19 +102,16 @@ jobs:
path: .build-variables
- name: Checkout master-message-template
if: env.BUILD
uses: actions/checkout@v4
with:
repository: secondlife/master-message-template
path: .master-message-template
- name: Install autobuild and python dependencies
if: env.BUILD
run: pip3 install autobuild llsd
- name: Cache autobuild packages
id: cache-installables
if: env.BUILD
uses: actions/cache@v4
with:
path: .autobuild-installables
@ -126,20 +120,14 @@ jobs:
${{ runner.os }}-64-${{ matrix.configuration }}-
${{ runner.os }}-64-
- name: Install windows dependencies
if: env.BUILD && runner.os == 'Windows'
run: choco install nsis-unicode
- name: Determine source branch
id: which-branch
if: env.BUILD
uses: secondlife/viewer-build-util/which-branch@v2
with:
token: ${{ github.token }}
- name: Build
id: build
if: env.BUILD
shell: bash
env:
AUTOBUILD_VCS_BRANCH: ${{ steps.which-branch.outputs.branch }}
@ -214,23 +202,32 @@ jobs:
[[ "$arch" == "MINGW6" ]] && arch=CYGWIN
export AUTOBUILD="$(which autobuild)"
# determine the viewer channel from the branch name
# determine the viewer channel from the branch or tag name
# trigger an EDU build by including "edu" in the tag
edu=${{ github.ref_type == 'tag' && contains(github.ref_name, 'edu') }}
echo "ref_type=${{ github.ref_type }}, ref_name=${{ github.ref_name }}, edu='$edu'"
branch=$AUTOBUILD_VCS_BRANCH
IFS='/' read -ra ba <<< "$branch"
prefix=${ba[0]}
if [ "$prefix" == "project" ]; then
IFS='_' read -ra prj <<< "${ba[1]}"
# uppercase first letter of each word
export viewer_channel="Second Life Project ${prj[*]^}"
elif [[ "$prefix" == "release" || "$prefix" == "main" ]];
if [[ "$edu" == "true" ]]
then
export viewer_channel="Second Life Release"
export viewer_channel="Second Life Release edu"
elif [[ "$branch" == "develop" ]];
then
export viewer_channel="Second Life Develop"
else
export viewer_channel="Second Life Test"
IFS='/' read -ra ba <<< "$branch"
prefix=${ba[0]}
if [ "$prefix" == "project" ]; then
IFS='_' read -ra prj <<< "${ba[1]}"
# uppercase first letter of each word
export viewer_channel="Second Life Project ${prj[*]^}"
elif [[ "$prefix" == "release" || "$prefix" == "main" ]];
then
export viewer_channel="Second Life Release"
else
export viewer_channel="Second Life Test"
fi
fi
echo "viewer_channel=$viewer_channel"
echo "viewer_channel=$viewer_channel" >> "$GITHUB_OUTPUT"
# On windows we need to point the build to the correct python
# as neither CMake's FindPython nor our custom Python.cmake module
@ -265,7 +262,7 @@ jobs:
echo "artifact=$RUNNER_OS$cfg_suffix" >> $GITHUB_OUTPUT
- name: Upload executable
if: matrix.Linden && steps.build.outputs.viewer_app
if: steps.build.outputs.viewer_app
uses: actions/upload-artifact@v4
with:
name: "${{ steps.build.outputs.artifact }}-app"
@ -275,15 +272,13 @@ jobs:
# The other upload of nontrivial size is the symbol file. Use a distinct
# artifact for that too.
- name: Upload symbol file
if: matrix.Linden
if: steps.build.outputs.symbolfile
uses: actions/upload-artifact@v4
with:
name: "${{ steps.build.outputs.artifact }}-symbols"
path: |
${{ steps.build.outputs.symbolfile }}
path: ${{ steps.build.outputs.symbolfile }}
- name: Upload metadata
if: matrix.Linden
uses: actions/upload-artifact@v4
with:
name: "${{ steps.build.outputs.artifact }}-metadata"
@ -294,7 +289,7 @@ jobs:
- name: Upload physics package
uses: actions/upload-artifact@v4
# should only be set for viewer-private
if: matrix.Linden && steps.build.outputs.physicstpv
if: matrix.configuration == 'Release' && steps.build.outputs.physicstpv
with:
name: "${{ steps.build.outputs.artifact }}-physics"
# emitted by build.sh, zero or one lines
@ -368,6 +363,7 @@ jobs:
BUGSPLAT_USER: ${{ secrets.BUGSPLAT_USER }}
BUGSPLAT_PASS: ${{ secrets.BUGSPLAT_PASS }}
needs: build
if: needs.build.outputs.configuration == 'Release'
runs-on: ubuntu-latest
steps:
- name: Download viewer exe
@ -402,6 +398,7 @@ jobs:
BUGSPLAT_USER: ${{ secrets.BUGSPLAT_USER }}
BUGSPLAT_PASS: ${{ secrets.BUGSPLAT_PASS }}
needs: build
if: needs.build.outputs.configuration == 'Release'
runs-on: ubuntu-latest
steps:
- name: Download Mac Symbols
@ -422,9 +419,9 @@ jobs:
files: "**/*.xcarchive.zip"
release:
needs: [setvar, build, sign-and-package-windows, sign-and-package-mac]
needs: [setup, build, sign-and-package-windows, sign-and-package-mac]
runs-on: ubuntu-latest
if: needs.setvar.outputs.release_run
if: needs.setup.outputs.release_run
steps:
- uses: actions/download-artifact@v4
with:

View File

@ -323,7 +323,7 @@ jobs:
# npm install -g node-dump-syms
- name: Post Bugsplat Symbols
uses: beqjanus/symbol-upload@main
uses: BugSplat-Git/symbol-upload@main
with:
clientId: ${{
steps.version.outputs.viewer_release_type == 'Release' && secrets.BUGSPLAT_RELEASE_ID ||
@ -391,27 +391,30 @@ jobs:
with:
sparse-checkout: |
fsutils/download_list.py
fsutils/build_config.json
fsutils/build_config.py
sparse-checkout-cone-mode: false
ref: ${{ github.head_ref || github.ref_name || 'master' }}
fetch-depth: 1
- name: Install discord-webhook library
run: pip install discord-webhook
- name: find channel and webhook from Branch name
- name: find channel and webhook from build_matrix outputs
run: |
if [[ "${{ github.ref_name }}" == Firestorm* ]]; then
viewer_release_type=${{ needs.build_matrix.outputs.viewer_release_type }}
if [[ "$viewer_release_type" == "Release" ]]; then
FS_RELEASE_FOLDER=release
FS_BUILD_WEBHOOK_URL=${{ secrets.RELEASE_WEBHOOK_URL }}
elif [[ "${{ github.ref_name }}" == *review* ]]; then
elif [[ "$viewer_release_type" == "Beta" ]]; then
FS_RELEASE_FOLDER=preview
FS_BUILD_WEBHOOK_URL=${{ secrets.BETA_WEBHOOK_URL }}
elif [[ "${{ github.ref_name }}" == *alpha* ]]; then
elif [[ "$viewer_release_type" == "Alpha" ]]; then
FS_RELEASE_FOLDER=test
FS_BUILD_WEBHOOK_URL=${{ secrets.BETA_WEBHOOK_URL }}
elif [[ "${{ github.ref_name }}" == *nightly* ]] || [[ "${{ github.event_name }}" == 'schedule' ]]; then
elif [[ "$viewer_release_type" == "Nightly" ]] || [[ "${{ github.event_name }}" == 'schedule' ]]; then
FS_RELEASE_FOLDER=nightly
FS_BUILD_WEBHOOK_URL=${{ secrets.NIGHTLY_WEBHOOK_URL }}
elif [[ "${{github.event_name }}" == "workflow_dispatch" ]]; then
elif [[ "$viewer_release_type" == "Manual" ]]; then
FS_RELEASE_FOLDER=test
FS_BUILD_WEBHOOK_URL=${{ secrets.MANUAL_WEBHOOK_URL }}
else
@ -430,7 +433,13 @@ jobs:
working-directory: ${{steps.download.outputs.download-path}}
- name: Reorganise artifacts ready for server upload.
run: python ./fsutils/download_list.py -u ${{steps.download.outputs.download-path}} -w ${{ env.FS_BUILD_WEBHOOK_URL }}
env:
FS_VIEWER_CHANNEL: ${{ needs.build_matrix.outputs.viewer_channel }}
FS_VIEWER_VERSION: ${{ needs.build_matrix.outputs.viewer_version }}
FS_VIEWER_BUILD: ${{ needs.build_matrix.outputs.viewer_build }}
FS_VIEWER_RELEASE_TYPE: ${{ needs.build_matrix.outputs.viewer_release_type }}
FS_VERSION_MGR_KEY: ${{ secrets.FS_VERSION_MGR_KEY }}
run: python ./fsutils/download_list.py ${{steps.download.outputs.download-path}} -w ${{ env.FS_BUILD_WEBHOOK_URL }}
- name: Setup rclone and download the folder
uses: beqjanus/setup-rclone@main

102
.github/workflows/deploy_only.yml vendored Normal file
View File

@ -0,0 +1,102 @@
name: Deploy Viewer
on:
workflow_dispatch:
inputs:
build_run_id:
description: 'Workflow Run ID of the build to deploy'
required: true
default: ''
viewer_channel:
description: 'viewer_channel'
required: true
default: 'Releasex64'
viewer_version:
description: 'viewer version not including build'
required: true
default: '7.1.10'
viewer_build:
description: 'build id'
required: true
default: '799999'
viewer_release_type:
description: 'release type'
required: true
default: 'Release'
branch:
description: 'Branch to deploy from'
required: false
default: 'master'
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
sparse-checkout: |
fsutils/download_list.py
fsutils/build_config.json
fsutils/build_config.py
sparse-checkout-cone-mode: false
ref: ${{ github.head_ref || github.ref_name || 'master' }}
fetch-depth: 1
- name: Download Build Artifacts
uses: dawidd6/action-download-artifact@v6
id: download
with:
workflow: build_viewer.yml
run_number: ${{ github.event.inputs.build_run_id }}
path: to_deploy
- name: Install discord-webhook library
run: pip install discord-webhook
- name: find channel and webhook from build_matrix outputs
run: |
viewer_release_type=${{ github.event.inputs.viewer_release_type }}
if [[ "$viewer_release_type" == "Release" ]]; then
FS_RELEASE_FOLDER=release
FS_BUILD_WEBHOOK_URL=${{ secrets.RELEASE_WEBHOOK_URL }}
elif [[ "$viewer_release_type" == "Beta" ]]; then
FS_RELEASE_FOLDER=preview
FS_BUILD_WEBHOOK_URL=${{ secrets.BETA_WEBHOOK_URL }}
elif [[ "$viewer_release_type" == "Alpha" ]]; then
FS_RELEASE_FOLDER=test
FS_BUILD_WEBHOOK_URL=${{ secrets.BETA_WEBHOOK_URL }}
elif [[ "$viewer_release_type" == "Nightly" ]] || [[ "${{ github.event_name }}" == 'schedule' ]]; then
FS_RELEASE_FOLDER=nightly
FS_BUILD_WEBHOOK_URL=${{ secrets.NIGHTLY_WEBHOOK_URL }}
elif [[ "$viewer_release_type" == "Manual" ]]; then
FS_RELEASE_FOLDER=test
FS_BUILD_WEBHOOK_URL=${{ secrets.MANUAL_WEBHOOK_URL }}
else
FS_RELEASE_TYPE=Unknown
fi
echo "FS_RELEASE_FOLDER=${FS_RELEASE_FOLDER}" >> $GITHUB_ENV
echo "FS_BUILD_WEBHOOK_URL=${FS_BUILD_WEBHOOK_URL}" >> $GITHUB_ENV
- name: List artifacts download
run: ls -R
working-directory: ${{steps.download.outputs.download-path}}
- name: Reorganise artifacts ready for server upload.
env:
FS_VIEWER_CHANNEL: ${{ github.event.inputs.viewer_channel }}
FS_VIEWER_VERSION: ${{ github.event.inputs.viewer_version }}
FS_VIEWER_BUILD: ${{ github.event.inputs.viewer_build }}
FS_VIEWER_RELEASE_TYPE: ${{ github.event.inputs.viewer_release_type }}
FS_VERSION_MGR_KEY: ${{ secrets.FS_VERSION_MGR_KEY }}
run: python ./fsutils/download_list.py ./to_deploy -w ${{ env.FS_BUILD_WEBHOOK_URL }}
- name: Setup rclone and download the folder
uses: beqjanus/setup-rclone@main
with:
rclone_config: ${{ secrets.RCLONE_CONFIG }}
- name: Copy files to remote host
run: rclone copy ./to_deploy/${{ env.FS_RELEASE_FOLDER }} fs_r2_deploy:viewerdownloads/${{ env.FS_RELEASE_FOLDER }}

View File

@ -26,23 +26,22 @@ on:
jobs:
tag-release:
runs-on: ubuntu-latest
env:
GITHUB_TAG_TOKEN: ${{ secrets.GITHUB_TAG_TOKEN }}
steps:
- name: Setup Env Vars
run: |
CHANNEL="${{ inputs.channel }}"
echo VIEWER_CHANNEL="Second_Life_${CHANNEL:-Develop}" >> ${GITHUB_ENV}
echo NIGHTLY_DATE=$(date --rfc-3339=date) >> ${GITHUB_ENV}
NIGHTLY_DATE=$(date --rfc-3339=date)
echo NIGHTLY_DATE=${NIGHTLY_DATE} >> ${GITHUB_ENV}
echo TAG_ID="$(echo ${{ github.sha }} | cut -c1-8)-${{ inputs.project || '${NIGHTLY_DATE}' }}" >> ${GITHUB_ENV}
- name: Update Tag
uses: actions/github-script@v7.0.1
if: env.GITHUB_TAG_TOKEN
with:
github-token: ${{ env.GITHUB_TAG_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.git.createRef(
github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: "refs/tags/${{ env.VIEWER_CHANNEL }}#${{ env.NIGHTLY_DATE }}",
ref: "refs/tags/${{ env.VIEWER_CHANNEL }}#${{ env.TAG_ID }}",
sha: context.sha
)
})

File diff suppressed because it is too large Load Diff

View File

@ -146,12 +146,21 @@ pre_build()
&& [ -r "$master_message_template_checkout/message_template.msg" ] \
&& template_verifier_master_url="-DTEMPLATE_VERIFIER_MASTER_URL=file://$master_message_template_checkout/message_template.msg"
RELEASE_CRASH_REPORTING=ON
HAVOK=ON
RELEASE_CRASH_REPORTING=OFF
HAVOK=OFF
SIGNING=()
if [[ "$arch" == "Darwin" && "$variant" == "Release" ]]
then SIGNING=("-DENABLE_SIGNING:BOOL=YES" \
"-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.")
if [[ "$variant" != *OS ]]
then
# Proprietary builds
RELEASE_CRASH_REPORTING=ON
HAVOK=ON
if [[ "$arch" == "Darwin" ]]
then
SIGNING=("-DENABLE_SIGNING:BOOL=YES" \
"-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.")
fi
fi
if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ]

View File

@ -134,8 +134,6 @@ cd \firestorm
git clone https://github.com/FirestormViewer/phoenix-firestorm.git
```
This can take a bit, it's a rather large download.
## Prepare third party libraries
Most third party libraries needed to build the viewer will be automatically downloaded for you and installed into the build directory within your source tree during compilation. Some need to be manually prepared and are not normally required when using an open source configuration (ReleaseFS_open).

View File

@ -1442,6 +1442,30 @@ Sovereign Engineer
SL-18534
SL-19690
SL-19336
secondlife/viewer/pull/1283
secondlife/viewer/pull/1287
secondlife/viewer/pull/1906
secondlife/viewer/pull/1930
secondlife/viewer/pull/1941
secondlife/viewer/pull/1946
secondlife/viewer/pull/1948
secondlife/viewer/pull/1950
secondlife/viewer/pull/1951
secondlife/viewer/pull/2066
secondlife/viewer/pull/2077
secondlife/viewer/pull/2078
secondlife/viewer/pull/2080
secondlife/viewer/pull/2085
secondlife/viewer/pull/2098
secondlife/viewer/pull/2099
secondlife/viewer/pull/2105
secondlife/viewer/pull/2115
secondlife/viewer/pull/2116
secondlife/viewer/pull/2124
secondlife/viewer/pull/2125
secondlife/viewer/pull/2135
secondlife/viewer/pull/2136
secondlife/viewer/pull/2149
SpacedOut Frye
VWR-34
VWR-45

View File

@ -0,0 +1,12 @@
# PBR Materials
## KHR Texture Transforms
Texture repeats for PBR materials on prims are based on the [KHR\_texture\_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) spec, and thus should be expected to behave according to the spec. We currently suport offset, rotation, and scale from the spec. texCoord is not currently supported.
PBR materials should have approximately correct lighting based on the normal texture:
- With default texture transforms, assuming the prim or model has correct normals and tangents
- With a texture transform applied, especially rotation or negative scale
- With a texture animation applied via `llSetTextureAnim`, especially a rotation animation
- Note: Texture animations are not guaranteed to loop when a PBR texture transform is applied

View File

@ -39,7 +39,7 @@ PBR terrain does not support materials with alpha blend or double-sided. In addi
## PBR Terrain Texture Transforms
Like PBR materials on prims, PBR terrain repeats are based on the [KHR\_texture\_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) spec, and thus should be expected to behave the same way.
Like PBR materials on prims, PBR terrain repeats are based on the [KHR\_texture\_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) spec, and thus should be expected to behave the same way. We currently suport offset, rotation, and scale from the spec. texCoord is not currently supported.
The southwest corner of a region, at z=0, is the UV origin for all texture coordinates of the whole region. Unless an offset is also applied, scale and rotation of the terrain texture transforms are relative to that point.
@ -50,3 +50,14 @@ If triplanar mapping is enabled, and an avatar faces an axially-aligned wall, th
Textures of materials should not appear mirrored.
When triplanar mapping is enabled, rotations on the axially aligned walls should apply in the same direction as they would on flat ground.
## PBR Terrain Normal Textures
This section assumes terrain normal maps are enabled at the current graphics setting.
PBR terrain should have approximately correct lighting based on the normal texture:
- When on flat ground
- On cliffs, when triplanar mapping is enabled. Lighting will be somewhat less accurate when the cliff face is not axially aligned.
- If no Terrain Texture Transform is applied.
- If a Terrain Texture Transform is applied, especially for rotation or negative scale.

View File

@ -44,6 +44,8 @@ The PBR terrain texture transform flag should be set automatically when logging
When the PBR terrain texture transform feature is enabled, the UI of the Terrain tab should be overhauled. Availability of features depends on the type of terrain.
**Known issue:** The Region/Estate floater may have to be closed/reopened a second time in order for the UI overhaul to take effect, after teleporting between regions that do and do not have the feature flag set.
When "PBR Metallic Roughness" is checked:
- There should be a way for the user to change the texture transforms for the terrain in the current region
@ -87,6 +89,12 @@ If saving the terrain fails for any reason, the terrain should not be updated.
Unlike a viewer without PBR terrain support, the new viewer will no longer treat textures with alpha channels as invalid.
### Saving PBR Terrain Texture Transforms
If "PBR Metallic Roughness" checkbox is checked, a user with saving composition permissions should also be allowed to edit and save PBR texture transforms.
One texture transform may be set for each material swatch. Setting texture transforms for each individual texture on the material is not currently supported.
## Graphics Features
Texture terrain with transparency is not permitted to be applied in the viewer.

View File

@ -0,0 +1,48 @@
# PBR Terrain Paintmap
## Introduction/Disclaimer
As of 2024-08-06, PBR terrain painting is **WIP**. Currently, there is only a client-side terrain paintmap, with no way to directly edit it. This document will explain how to informally explore this feature and compare it to the existing heightmap with noise. In the future, a testing document will be added for PBR terrain painting.
## Background
Historically, PBR terrain in a region has several parameters for controlling its composition. These are:
- The four materials
- The elevation of the terrain, which roughly controls the material, with some noise added on top ("heightmap with noise")
- Material Elevation Ranges, which control where the materials start and end
This allows for some coarse control over terrain composition. For example, you can have one corner of the terrain be a sandy beach and the rest of the coastline be rocky. Or you can have the peaks of your mountains be covered with snow. However, artistic control is limited due to the gradient imposed by the material elevation ranges, and the unpredictability of the noise.
A terrain painting option would allow for more control over the terrain composition. The first step to getting that working is the paintmap.
## How to activate the local paintmap
The local paintmap is a good way to assess the quality of the PBR terrain paintmap. By default, the newly created local paintmap inherits its composition (i.e. where the grass and dirt goes) from the existing terrain. This allows for a direct comparison with the terrain heightmap-with-noise shader.
Activating the local paintmap is similar to [applying local PBR terrain via the debug settings](https://wiki.secondlife.com/wiki/PBR_Terrain#How_to_apply_PBR_Terrain), but with a couple extra steps.
You will need:
- Four fullperm PBR material items to copy UUIDs from
- A region with a good variation of elevations which showcase the four composition layers (no special permissions needed)
Open the Debug Settings menu (Advanced > Show Debug Settings) and search for "terrain". The following relevant options are available:
- LocalTerrainAsset1
- LocalTerrainAsset1
- LocalTerrainAsset3
- LocalTerrainAsset4
- LocalTerrainPaintEnabled
- TerrainPaintBitDepth
- TerrainPaintResolution
By setting LocalTerrainAsset1, etc to valid material IDs, you will override the terrain to use those materials.
The next step is to "bake" the terrain into a paintmap (Develop > Terrain > Create Local Paintmap). This will *automatically* set LocalTerrainPaintEnabled to true. **WARNING:** LocalTerrainPaintEnabled will *not* do anything until one of LocalTerrainAsset1, etc is set.
You are now looking at the same terrain, but rendered as a paintmap.
To compare the quality of the paintmap version and the heightmap-with-noise version, toggle LocalTerrainPaintEnabled in Debug Settings.
To change the bit depth and/or resolution of the paintmap, change TerrainPaintBitDepth and TerrainPaintResolution as desired, then "re-bake" the paintmap (Develop > Terrain > Create Local Paintmap).

44
fsutils/build_config.json Normal file
View File

@ -0,0 +1,44 @@
{
"os_download_dirs": [
"windows", "mac", "linux"
],
"fs_version_mgr_platform": {
"windows": "win",
"mac": "mac",
"linux": "lin"
},
"build_type_hosted_folder": {
"Release": "release",
"Beta": "preview",
"Alpha": "test",
"Nightly": "nightly",
"Unknown": "test"
},
"os_hosted_folder": {
"windows": "windows",
"macos": "mac",
"ubuntu": "linux"
},
"platforms_printable": {
"windows": "MS Windows",
"mac": "MacOS",
"linux": "Linux"
},
"grids_printable": {
"SL": "Second Life",
"OS": "OpenSim"
},
"download_root": "https://downloads.firestormviewer.org",
"viewer_channel_mapping": {
"Release": "release",
"Beta": "beta",
"Alpha": "alpha",
"Nightly": "nightly"
},
"build_type_mapping": {
"regular": "regular",
"avx": "avx",
"tracy": "tracy",
"arm": "arm"
}
}

19
fsutils/build_config.py Normal file
View File

@ -0,0 +1,19 @@
# build_config.py
import json
class BuildConfig:
def __init__(self, config_file='./fsutils/build_config.json'):
with open(config_file, 'r') as f:
config_data = json.load(f)
self.supported_os_dirs = config_data.get('os_download_dirs', [])
# channel_to_build_type is a map from Beta, Release and Nightly to folder names preview release and nightly
self.build_type_hosted_folder = config_data.get('build_type_hosted_folder', {})
self.fs_version_mgr_platform = config_data.get('fs_version_mgr_platform', {})
self.os_hosted_folder = config_data.get('os_hosted_folder', {})
self.platforms_printable = config_data.get('platforms_printable', {})
self.grids_printable = config_data.get('grids_printable', {})
self.download_root = config_data.get('download_root', '')
self.viewer_channel_mapping = config_data.get('viewer_channel_mapping', {})
self.build_type_mapping = config_data.get('build_type_mapping', {})

View File

@ -6,10 +6,26 @@ import time
import zipfile
import glob
import shutil
import hashlib
import pytz
from datetime import datetime
import requests
from discord_webhook import DiscordWebhook
from build_config import BuildConfig
def get_current_date_str():
now = datetime.now(pytz.timezone('UTC'))
day = now.day
month = now.month
year = now.year
return f"{day}{month}{year}"
def generate_secret(secret_key):
current_date = get_current_date_str()
data = secret_key + current_date
secret_for_api = hashlib.sha1(data.encode()).hexdigest()
return secret_for_api
# run a command line subshell and return the output
@ -103,171 +119,340 @@ def flatten_tree(tree_root):
# Delete the subdirectory and its contents
shutil.rmtree(subdir_path)
def get_build_variables():
"""
Extracts initial build variables from environment variables.
In practice these are set from the outputs of the earlier matrix commands.
Returns:
dict: A dictionary containing 'version' and 'build_number'.
"""
import os
# parse args first arg optional -r (release) second arg mandatory string path_to_directory
version = os.environ.get('FS_VIEWER_VERSION')
build_number = os.environ.get('FS_VIEWER_BUILD')
release_type = os.environ.get('FS_VIEWER_RELEASE_TYPE')
parser = argparse.ArgumentParser(
prog="print_download_list",
description="Prints the list of files for download and their md5 checksums"
)
parser.add_argument("-r", "--release", required=False, default=False, action="store_true", help="use the release folder in the target URL")
parser.add_argument("-u", "--unzip", required=False, default=False, action="store_true", help="unzip the github artifact first")
parser.add_argument("-w", "--webhook", help="post details to the webhook")
if not version or not build_number or not release_type:
raise ValueError("Environment variables 'FS_VIEWER_VERSION' and 'FS_VIEWER_BUILD' must be set.")
# add path_to_directory required parameter to parser
parser.add_argument("path_to_directory", help="path to the directory in which we'll look for the files")
return {
'version': version,
'build_number': build_number,
'version_full': f"{version}.{build_number}",
'release_type': release_type,
}
args = parser.parse_args()
path_to_directory = args.path_to_directory
release = args.release
def get_hosted_folder_for_build_type(build_type, config):
return config.build_type_hosted_folder.get(
build_type,
config.build_type_hosted_folder.get("Unknown")
)
# Create a webhook object with the webhook URL
if args.webhook:
webhook = DiscordWebhook(url=args.webhook)
def is_supported_build_type(build_type, config):
if build_type in config.build_type_hosted_folder:
return True
else:
return False
def get_hosted_folder_for_os_type(os_type, config):
return config.os_hosted_folder.get(
os_type
)
dirs = ["windows", "mac", "linux"]
def get_supported_os(os_name, config):
# throws for unexpected os_name
return config.os_hosted_folder.get(os_name)
# build_types is a map from Beta, Release and Nightly to folder names preview release and nightly
build_types = {
"Alpha": "test",
"Beta": "preview",
"Release": "release",
"Nightly": "nightly",
"Unknown": "test"
}
target_folder = {
"ubuntu":"linux",
"windows":"windows",
"macos":"mac"
}
# unzip the github artifact for this OS (`dir`) into the folder `dir`
# get the .zip files in args.path_to_directory using glob
print(f"Processing artifacts in {args.path_to_directory}")
build_types_created = set()
zips = glob.glob(f"{args.path_to_directory}/*.zip")
for file in zips:
def extract_vars_from_zipfile_name(file):
# File is an artifact file sometihng like Nightly-windows-2022-64-sl-artifacts.zip
# print(f"unzipping {file}")
#extract first word (delimited by '-' from the file name)
# build_type is a fullpath but we only want the last folder, remove the leading part of the path leaving just the foldername using basename
filename = os.path.basename(file)
build_type = filename.split("-")[0]
platform = filename.split("-")[1].lower()
return filename,build_type, platform
# print(f"build_type is {build_type}")
if build_type not in build_types:
print(f"Invalid build_type {build_type} from file {file} using 'Unknown'")
build_type = "Unknown"
build_folder = build_types[build_type]
build_types_created.add(build_type)
def unpack_artifacts(path_to_artifacts_directory, config):
build_types_found = {}
zips = glob.glob(f"{path_to_artifacts_directory}/*.zip")
for file in zips:
print(f"Processing zip file {file}")
filename, build_type, platform = extract_vars_from_zipfile_name(file)
print(f"Identified filename {filename}, build_type {build_type} and platform {platform} from file {file}")
if is_supported_build_type( build_type, config) == False:
print(f"Invalid build_type {build_type} from file {file} using 'Unknown' instead")
build_type = "Unknown"
else:
print(f"Using build_type {build_type} from file {file}")
build_type_dir = os.path.join(args.path_to_directory, build_folder)
build_folder = get_hosted_folder_for_build_type(build_type, config)
print(f"build_folder {build_folder}")
try:
build_type_dir = os.path.join(path_to_artifacts_directory, build_folder)
except Exception as e:
print(f"An error occurred while creating build_type_dir folder from {path_to_artifacts_directory} and {build_folder}: {e}")
continue
print(f"build_type_dir {build_type_dir}")
os_folder = get_hosted_folder_for_os_type(platform, config)
print(f"os_folder {os_folder}")
try:
unpack_folder = os.path.join(build_type_dir, os_folder)
except Exception as e:
print(f"An error occurred while creating unpack_folder folder from {build_type_dir} and {os_folder}: {e}")
continue
print(f"unpacking {filename} to {unpack_folder}")
if os.path.isfile(file):
# this is an actual zip file
try:
unzip_file(file, unpack_folder)
except zipfile.BadZipFile:
print(f"Skipping {file} as it is not a valid zip file")
continue
except Exception as e:
print(f"An error occurred while unpacking {file}: {e} , skipping file {filename}")
continue
else:
# Create the destination folder if it doesn't exist
# if not os.path.exists(unpack_folder):
# os.makedirs(unpack_folder)
# Copy the contents of the source folder to the destination folder recursively
shutil.copytree(file, unpack_folder, dirs_exist_ok=True)
print(f"Finished unpacking {filename} to {unpack_folder}")
if build_type not in build_types_found:
print(f"Creating build_type {build_type} entry in build_types_found")
build_types_found[build_type] = {
"build_type": build_type,
"build_type_folder": build_folder,
"build_type_fullpath": build_type_dir,
"os_folders": [],
}
if os_folder not in build_types_found[build_type]["os_folders"]:
build_types_found[build_type]["os_folders"].append(os_folder)
print(f"Appended {os_folder} to build_type {build_type}")
print(f"Finished processing artifacts for build_type {build_type}")
return build_types_found
if platform not in target_folder:
print(f"Invalid platform {platform} using file {file}")
continue
unpack_folder = os.path.join(build_type_dir, target_folder[platform])
print(f"unpacking {filename} to {unpack_folder}")
if os.path.isfile(file):
# this is an actual zip file
unzip_file(file, unpack_folder)
else:
# Create the destination folder if it doesn't exist
# if not os.path.exists(unpack_folder):
# os.makedirs(unpack_folder)
# Copy the contents of the source folder to the destination folder recursively
shutil.copytree(file, unpack_folder, dirs_exist_ok=True)
output = ""
for build_type in build_types_created:
build_type_dir = os.path.join(args.path_to_directory, build_types[build_type])
def restructure_folders(build_type, config):
print(f"Restructuring folders for build_type {build_type}")
build_type_dir = build_type["build_type_fullpath"]
if not os.path.exists(build_type_dir):
print(f"Unexpected error: {build_type_dir} does not exist, even though it was in the set.")
continue
print(f"Unexpected error: path {build_type_dir} does not exist, even though it was in the set.")
raise FileNotFoundError
# loop over the folder in the build_type_dir
for dir in dirs:
print(f"Cleaning up {dir}")
for platform_folder in build_type["os_folders"]:
print(f"Cleaning up {platform_folder}")
# Traverse the directory tree and move all of the files to the root directory
flatten_tree(os.path.join(build_type_dir, dir))
flatten_tree(os.path.join(build_type_dir, platform_folder))
# Now move the symbols files to the symbols folder
# prep the symbols folder
# Define the folder for symbols
symbols_folder = os.path.join(build_type_dir, "symbols")
os.mkdir(symbols_folder)
symbol_archives = glob.glob(f"{build_type_dir}/**/*_hvk*", recursive=True)
for sym_file in symbol_archives:
print(f"Moving {sym_file} to {symbols_folder}")
shutil.move(sym_file, symbols_folder)
symbol_archives = glob.glob(f"{build_type_dir}/**/*_oss*", recursive=True)
for sym_file in symbol_archives:
print(f"Moving {sym_file} to {symbols_folder}")
shutil.move(sym_file, symbols_folder)
# prep the symbols folder
symbol_patterns = ["*_hvk*", "*_oss*"]
# Loop through each pattern, find matching files, and move them
for pattern in symbol_patterns:
symbol_archives = glob.glob(f"{build_type_dir}/**/{pattern}", recursive=True)
for sym_file in symbol_archives:
print(f"Moving {sym_file} to {symbols_folder}")
shutil.move(sym_file, symbols_folder)
def gather_build_info(build_type, config):
print(f"Gathering build info for build_type {build_type}")
# While we're at it, let's print the md5 listing
file_dict = {}
md5_dict = {}
platforms_printable = {"windows":"MS Windows", "mac":"MacOS", "linux":"Linux"}
grids_printable = {"SL":"Second Life", "OS":"OpenSim"}
download_root = f"https://downloads.firestormviewer.org/{build_types[build_type]}"
output += f'''
DOWNLOADS - {build_type}
-------------------------------------------------------------------------------------------------------
'''
for dir in dirs:
print(f"Getting files for {dir} in {build_type_dir}")
files = get_files(os.path.join(build_type_dir, dir))
download_root = f"{config.download_root}/{build_type['build_type_folder']}"
# for each os that we have built for
build_type_dir = build_type["build_type_fullpath"]
for platform_folder in build_type["os_folders"]:
print(f"Getting files for {platform_folder} in {build_type_dir}")
build_type_platform_folder = os.path.join(build_type_dir, platform_folder)
files = get_files(build_type_platform_folder)
try:
for file in files:
full_file = os.path.join(build_type_dir, dir, file)
md5 = get_md5(full_file)
full_file = os.path.join(build_type_platform_folder, file)
base_name = os.path.basename(file)
wordsize = "64"
file_URI = f"{download_root}/{platform_folder}/{base_name}"
md5 = get_md5(full_file)
if "FirestormOS-" in base_name:
grid = "OS"
else:
grid = "SL"
if dir in dirs:
file_dict[f"{grid}{dir}{wordsize}"] = full_file
md5_dict[f"{grid}{dir}{wordsize}"] = md5
file_key = f"{grid}-{platform_folder}"
# if platform_folder in config.os_download_dirs:
if "downloadable_artifacts" not in build_type:
build_type["downloadable_artifacts"] = {}
build_type["downloadable_artifacts"][f"{file_key}"] = {
"file_path": full_file,
"file_download_URI": file_URI,
"grid": grid,
"fs_ver_mgr_platform": config.fs_version_mgr_platform.get(platform_folder),
"md5": md5,
}
except TypeError:
print(f"No files found for {dir} in {build_type_dir}")
print(f"Error processing files for {platform_folder} in {build_type_dir}")
continue
except Exception as e:
print(f"An error occurred while processing files for {platform_folder} in {build_type_dir}: {e}")
continue
print(f"Created build info: {build_type}")
return build_type
output += f'''
{platforms_printable[dir]}
def create_discord_message(build_info, config):
# Start with a header line
text_summary = f'''
DOWNLOADS - {build_info["build_type"]}
-------------------------------------------------------------------------------------------------------
'''
dir = dir.lower()
wordsize = "64"
platform = f"{platforms_printable[dir]}"
# for each platform we potentailly build for
# Append platform label in printable form
for platform_folder in config.supported_os_dirs:
platform_printable = config.platforms_printable[platform_folder]
text_summary += f'''
{platform_printable}
'''
platform_folder = platform_folder.lower()
for grid in ["SL", "OS"]:
grid_printable = f"{grids_printable[grid]}"
grid_printable = f"{config.grids_printable[grid]}"
try:
output += f"{platform} for {grid_printable} ({wordsize}-bit)\n"
output += f"{download_root}/{dir}/{os.path.basename(file_dict[f'{grid}{dir}{wordsize}'])}\n"
output += "\n"
output += f"MD5: {md5_dict[f'{grid}{dir}{wordsize}']}\n"
output += "\n"
file_key = f"{grid}-{platform_folder}"
text_summary += f"{platform_printable} for {grid_printable}\n"
text_summary += f"{build_info['downloadable_artifacts'][file_key]['file_download_URI']}\n"
text_summary += "\n"
text_summary += f"MD5: {build_info['downloadable_artifacts'][file_key]['md5']}\n"
text_summary += "\n"
except KeyError:
output += f"{platform} for {grid_printable} ({wordsize}-bit) - NOT AVAILABLE\n"
output += "\n"
output += '''-------------------------------------------------------------------------------------------------------
text_summary += f"{platform_printable} for {grid_printable} - NOT AVAILABLE\n"
text_summary += "\n"
text_summary += '''
-------------------------------------------------------------------------------------------------------
'''
return text_summary
if args.webhook:
# Add the message to the webhook
webhook.set_content(content=output)
# Send the webhook
response = webhook.execute()
# Print the response
if not response.ok:
print(f"Webhook Error {response.status_code}: {response.text}")
print(output)
def update_fs_version_mgr(build_info, config):
print(f"Updating Firestorm Version Manager for build_type {build_info['build_type']}")
# Read the secret key from environment variables
secret_key = os.environ.get('FS_VERSION_MGR_KEY')
if not secret_key:
print("Error: FS_VERSION_MGR_KEY not set")
sys.exit(1)
secret_for_api = generate_secret(secret_key)
build_type = build_info["build_type"]
version = os.environ.get('FS_VIEWER_VERSION')
channel = os.environ.get('FS_VIEWER_CHANNEL')
build_number = os.environ.get('FS_VIEWER_BUILD')
build_variant = "regular"
for file_key in build_info["downloadable_artifacts"]:
try:
download_link = build_info["downloadable_artifacts"][file_key]["file_download_URI"]
md5_checksum = build_info["downloadable_artifacts"][file_key]["md5"]
grid = build_info["downloadable_artifacts"][file_key]["grid"].lower()
os_name = build_info["downloadable_artifacts"][file_key]["fs_ver_mgr_platform"]
except KeyError:
print(f"Error: Could not find downloadable artifacts for {file_key}")
continue
payload = {
"viewer_channel": build_type,
"grid_type": grid,
"operating_system": os_name,
"build_type": build_variant,
"viewer_version": version,
"build_number": int(build_number),
"download_link": download_link,
"md5_checksum": md5_checksum
}
print(f"Payload (without secret): {payload}")
payload["secret"] = secret_for_api
# Make the API call
url = "https://www.firestormviewer.org/set-fs-vrsns-jsn/"
headers = {"Content-Type": "application/json"}
response = None # Initialize response to None
try:
response = requests.post(url, json=payload, headers=headers)
# Manually check for status code instead of raising an exception
if response.status_code == 200:
response_data = response.json()
result = response_data.get('result')
message = response_data.get('message')
if result == 'success':
print(f"Version manager updated successfully for {os_name} {build_variant}")
else:
print(f"Error updating version manager: {message}")
else:
print(f"Unexpected status code received: {response.status_code}")
print(f"Response body: {response.text}")
except requests.exceptions.RequestException as e:
print(f"API request failed: {e}")
# Additional error handling
if response and response.status_code == 403:
print("Status Code:", response.status_code)
print("Response Headers:", response.headers)
print("Response Body:", response.text)
except ValueError:
print("API response is not valid JSON")
# parse args first arg optional -r (release) second arg mandatory string path_to_directory
def main():
try:
# Initialise the build configuration
config = BuildConfig()
parser = argparse.ArgumentParser(
prog="print_download_list",
description="Prints the list of files for download and their md5 checksums"
)
parser.add_argument("-w", "--webhook", help="post details to the webhook")
# add path_to_directory required parameter to parser
parser.add_argument("path_to_directory", help="path to the directory in which we'll look for the files")
args = parser.parse_args()
# Create a webhook object with the webhook URL
if args.webhook:
webhook = DiscordWebhook(url=args.webhook)
# unzip the github artifact for this OS (`dir`) into the folder `dir`
# get the .zip files in args.path_to_directory using glob
print(f"Processing artifacts in {args.path_to_directory}")
build_types_created = unpack_artifacts(args.path_to_directory, config)
print(f"buuild types created: {build_types_created}")
for build_type_key, build_type in build_types_created.items():
print(f"Processing {build_type_key}")
restructure_folders(build_type, config)
build_info = gather_build_info(build_type, config)
update_fs_version_mgr(build_info, config)
discord_text = create_discord_message(build_info, config)
if args.webhook:
# Add the message to the webhook
webhook.set_content(content=discord_text)
# Send the webhook
response = webhook.execute()
# Print the response
if not response.ok:
print(f"Webhook Error {response.status_code}: {response.text}")
print(discord_text)
except Exception as e:
print(f"An error occurred: {e}")
sys.exit(1)
if __name__ == '__main__':
import sys
main()

View File

@ -89,7 +89,6 @@ endif (USE_AVX_OPTIMIZATION)
add_subdirectory(cmake)
# <FS:Beq> Tracy Profiler support
option(USE_TRACY "Tracy Profiler support" OFF)
if (USE_TRACY)
message(STATUS "Compiling with Tracy profiler")
else (USE_TRACY)

View File

@ -39,6 +39,10 @@ add_compile_definitions( ADDRESS_SIZE=${ADDRESS_SIZE})
# -- which we do. Without one or the other, we get a ton of Boost warnings.
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)
# Configure crash reporting
set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds")
set(NON_RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in developer builds")
@ -76,9 +80,7 @@ if (WINDOWS)
# http://www.cmake.org/pipermail/cmake/2009-September/032143.html
string(REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
# zlib has assembly-language object files incompatible with SAFESEH
add_link_options(/LARGEADDRESSAWARE
/SAFESEH:NO
/NODEFAULTLIB:LIBCMT
/IGNORE:4099)
@ -99,6 +101,7 @@ if (WINDOWS)
/Ot
/fp:fast
/MP
/permissive-
)
# <FS:Ansariel> AVX/AVX2 support
@ -130,11 +133,6 @@ if (WINDOWS)
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
endif()
# workaround for github runner image breakage:
# https://github.com/actions/runner-images/issues/10004#issuecomment-2153445161
# can be removed after the above issue is resolved and deployed across GHA
add_compile_definitions(_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
# Allow use of sprintf etc
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif (WINDOWS)

View File

@ -18,6 +18,7 @@ if (WINDOWS)
${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")
@ -28,17 +29,16 @@ elseif (DARWIN)
endif (LLCOMMON_LINK_SHARED)
target_link_libraries( ll::apr INTERFACE
libapr-1.${APR_selector}
libaprutil-1.${APRUTIL_selector}
${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.${APR_selector}
${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.${APR_selector}
iconv
)
else (WINDOWS)
else()
# linux
target_link_libraries( ll::apr INTERFACE
apr-1
aprutil-1
uuid
${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.a
${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.a
rt
)
endif (WINDOWS)
endif ()
target_include_directories( ll::apr SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/apr-1 )

View File

@ -1,4 +1,5 @@
# -*- cmake -*-
include(Linking)
include(Prebuilt)
include_guard()
@ -9,9 +10,23 @@ use_prebuilt_binary(ogg_vorbis)
target_include_directories( ll::vorbis SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include )
if (WINDOWS)
target_link_libraries(ll::vorbis INTERFACE ogg_static vorbis_static vorbisenc_static vorbisfile_static )
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)
# <FS:Zi> These must be in this order, or it won't link: vorbisenc vorbisfile vorbis ogg
target_link_libraries(ll::vorbis INTERFACE vorbisenc vorbisfile vorbis ogg)
target_link_libraries(ll::vorbis INTERFACE
# <FS:Zi> These must be in this order, or it won't link: vorbisenc vorbisfile vorbis ogg
${ARCH_PREBUILT_DIRS_RELEASE}/libvorbisenc.a
${ARCH_PREBUILT_DIRS_RELEASE}/libvorbisfile.a
${ARCH_PREBUILT_DIRS_RELEASE}/libvorbis.a
${ARCH_PREBUILT_DIRS_RELEASE}/libogg.a
)
endif (WINDOWS)

View File

@ -25,6 +25,7 @@ if (WINDOWS)
libboost_regex-mt${addrsfx}
libboost_system-mt${addrsfx}
libboost_thread-mt${addrsfx}
libboost_url-mt${addrsfx}
libboost_wave-mt${addrsfx})
elseif (LINUX)
target_link_libraries( ll::boost INTERFACE
@ -36,6 +37,7 @@ elseif (LINUX)
boost_regex-mt${addrsfx}
boost_system-mt${addrsfx}
boost_thread-mt${addrsfx}
boost_url-mt${addrsfx}
boost_wave-mt${addrsfx})
elseif (DARWIN)
target_link_libraries( ll::boost INTERFACE
@ -46,6 +48,7 @@ elseif (DARWIN)
boost_regex-mt${addrsfx}
boost_system-mt${addrsfx}
boost_thread-mt${addrsfx}
boost_url-mt${addrsfx}
boost_wave-mt${addrsfx})
endif (WINDOWS)

View File

@ -60,13 +60,11 @@ set(cmake_SOURCE_FILES
Tut.cmake
UI.cmake
UnixInstall.cmake
URIPARSER.cmake
Variables.cmake
ViewerMiscLibs.cmake
VisualLeakDetector.cmake
LibVLCPlugin.cmake
WebRTC.cmake
XmlRpcEpi.cmake
xxHash.cmake
ZLIBNG.cmake
)

View File

@ -1,6 +1,6 @@
# -*- cmake -*-
include(Prebuilt)
include(NGHTTP2)
include(Linking)
include_guard()
add_library( ll::libcurl INTERFACE IMPORTED )
@ -8,8 +8,18 @@ add_library( ll::libcurl INTERFACE IMPORTED )
use_system_binary(libcurl)
use_prebuilt_binary(curl)
if (WINDOWS)
target_link_libraries(ll::libcurl INTERFACE libcurl.lib)
else (WINDOWS)
target_link_libraries(ll::libcurl INTERFACE libcurl.a)
endif (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 ()
target_include_directories( ll::libcurl SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)

View File

@ -55,29 +55,20 @@ if(WINDOWS)
set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(release_files
#openjp2.dll # <FS:Ansariel> Only copy OpenJPEG dll if needed
libapr-1.dll
libaprutil-1.dll
nghttp2.dll
glod.dll # <FS:Beq> restore GLOD
libhunspell.dll
uriparser.dll
)
if(LLCOMMON_LINK_SHARED)
set(release_files ${release_files} libapr-1.dll)
set(release_files ${release_files} libaprutil-1.dll)
endif()
# <FS:Ansariel> Only copy OpenJPEG dll if needed
if (NOT USE_KDU)
set(release_files ${release_files} openjp2.dll)
endif (NOT USE_KDU)
# </FS:Ansariel>
# OpenSSL
if(ADDRESS_SIZE EQUAL 64)
set(release_files ${release_files} libcrypto-1_1-x64.dll)
set(release_files ${release_files} libssl-1_1-x64.dll)
else(ADDRESS_SIZE EQUAL 64)
set(release_files ${release_files} libcrypto-1_1.dll)
set(release_files ${release_files} libssl-1_1.dll)
endif(ADDRESS_SIZE EQUAL 64)
# 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)
@ -152,9 +143,14 @@ if(WINDOWS)
# Check each of them.
foreach(release_msvc_file
msvcp${MSVC_VER}.dll
msvcp${MSVC_VER}_1.dll
msvcp${MSVC_VER}_2.dll
msvcp${MSVC_VER}_atomic_wait.dll
msvcp${MSVC_VER}_codecvt_ids.dll
#msvcr${MSVC_VER}.dll # <FS:Ansariel> Can't build with older VS versions anyway - no need trying to copy this file
vcruntime${MSVC_VER}.dll
vcruntime${MSVC_VER}_1.dll
vcruntime${MSVC_VER}_threads.dll
)
if(redist_path AND EXISTS "${redist_path}/${release_msvc_file}")
MESSAGE(STATUS "Copying redist file from ${redist_path}/${release_msvc_file}")
@ -174,10 +170,6 @@ if(WINDOWS)
MESSAGE(STATUS "Redist lib ${release_msvc_file} not found")
endif()
endforeach()
MESSAGE(STATUS "Will copy redist files for MSVC ${MSVC_VER}:")
foreach(target ${third_party_targets})
MESSAGE(STATUS "${target}")
endforeach()
elseif(DARWIN)
set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
@ -191,23 +183,21 @@ elseif(DARWIN)
)
set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")
set(release_files
libapr-1.0.dylib
libapr-1.dylib
libaprutil-1.0.dylib
libaprutil-1.dylib
${EXPAT_COPY}
libGLOD.dylib # <FS:Beq> restore GLOD
libhunspell-1.3.0.dylib
libndofdev.dylib
libnghttp2.dylib
libnghttp2.14.dylib
liburiparser.dylib
liburiparser.1.dylib
liburiparser.1.0.27.dylib
libgrowl.dylib
libgrowl++.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::fmodstudio)
set(debug_files ${debug_files} libfmodL.dylib)
set(release_files ${release_files} libfmod.dylib)
@ -247,8 +237,6 @@ elseif(LINUX)
if (NOT USESYSTEMLIBS)
set(release_files
#libdb-5.1.so
${EXPAT_COPY}
libhunspell-1.3.so.0.0.0
libopenal.so
#libopenjp2.so
libuuid.so.16
@ -266,11 +254,8 @@ elseif(LINUX)
if( USE_AUTOBUILD_3P )
list( APPEND release_files
libapr-1.so.0
libaprutil-1.so.0
libhunspell-1.3.so.0.0.0
#libopenjp2.so
libuuid.so.16
libuuid.so.16.0.22
@ -279,6 +264,13 @@ elseif(LINUX)
libgmodule-2.0.a
libgobject-2.0.a
)
if(LLCOMMON_LINK_SHARED)
set(release_files ${release_files}
libapr-1.so.0
libaprutil-1.so.0
)
endif()
endif()
if (TARGET ll::fmodstudio)

View File

@ -7,14 +7,13 @@ add_library( ll::expat INTERFACE IMPORTED )
use_system_binary(expat)
use_prebuilt_binary(expat)
if (WINDOWS)
target_link_libraries( ll::expat INTERFACE libexpatMT )
set(EXPAT_COPY libexpatMT.dll)
else (WINDOWS)
target_link_libraries( ll::expat INTERFACE expat )
if (DARWIN)
set(EXPAT_COPY libexpat.1.dylib libexpat.dylib)
else ()
set(EXPAT_COPY libexpat.so.1 libexpat.so)
endif ()
endif (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)
endif ()
target_include_directories( ll::expat SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include )

View File

@ -1,5 +1,6 @@
# -*- cmake -*-
include(Prebuilt)
include(Linking)
include_guard()
add_library( ll::freetype INTERFACE IMPORTED )
@ -7,4 +8,10 @@ add_library( ll::freetype INTERFACE IMPORTED )
use_system_binary(freetype)
use_prebuilt_binary(freetype)
target_include_directories( ll::freetype SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/freetype2/)
target_link_libraries( ll::freetype INTERFACE freetype )
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()

View File

@ -1,4 +1,5 @@
# -*- cmake -*-
include(Linking)
include(Prebuilt)
include_guard()
@ -8,10 +9,16 @@ add_library( ll::hunspell INTERFACE IMPORTED )
use_system_binary(hunspell)
use_prebuilt_binary(libhunspell)
if (WINDOWS)
target_link_libraries( ll::hunspell INTERFACE libhunspell)
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 hunspell-1.3)
target_link_libraries( ll::hunspell INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libhunspell-1.7.a
)
elseif(LINUX)
target_link_libraries( ll::hunspell INTERFACE hunspell-1.3)
target_link_libraries( ll::hunspell INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libhunspell-1.7.a
)
endif()
target_include_directories( ll::hunspell SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/hunspell)

View File

@ -7,12 +7,14 @@ include_guard()
add_library( ll::libjpeg INTERFACE IMPORTED )
use_system_binary(libjpeg)
use_prebuilt_binary(jpeglib)
use_prebuilt_binary(libjpeg-turbo)
if (LINUX)
target_link_libraries( ll::libjpeg INTERFACE jpeg)
target_link_libraries( ll::libjpeg INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libjpeg.a)
elseif (DARWIN)
target_link_libraries( ll::libjpeg INTERFACE jpeg)
target_link_libraries( ll::libjpeg INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libjpeg.a)
elseif (WINDOWS)
target_link_libraries( ll::libjpeg INTERFACE jpeglib)
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)

View File

@ -6,5 +6,3 @@ include(EXPAT)
include(Tracy)
include(xxHash)
include(ZLIBNG)
include(XmlRpcEpi)

View File

@ -2,11 +2,11 @@
# these should be moved to their own cmake file
include(Prebuilt)
include(Linking)
include(Boost)
include_guard()
add_library( ll::pcre INTERFACE IMPORTED )
add_library( ll::minizip-ng INTERFACE IMPORTED )
add_library( ll::libxml INTERFACE IMPORTED )
add_library( ll::colladadom INTERFACE IMPORTED )
@ -22,21 +22,18 @@ use_system_binary( colladadom )
use_prebuilt_binary(colladadom)
use_prebuilt_binary(minizip-ng) # needed for colladadom
use_prebuilt_binary(pcre)
use_prebuilt_binary(libxml2)
target_link_libraries( ll::pcre INTERFACE pcrecpp pcre )
if (WINDOWS)
target_link_libraries( ll::minizip-ng INTERFACE libminizip )
target_link_libraries( ll::minizip-ng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/minizip.lib )
else()
target_link_libraries( ll::minizip-ng INTERFACE minizip )
target_link_libraries( ll::minizip-ng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libminizip.a )
endif()
if (WINDOWS)
target_link_libraries( ll::libxml INTERFACE libxml2_a)
target_link_libraries( ll::libxml INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libxml2.lib Bcrypt.lib)
else()
target_link_libraries( ll::libxml INTERFACE xml2)
target_link_libraries( ll::libxml INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libxml2.a)
endif()
target_include_directories( ll::colladadom SYSTEM INTERFACE
@ -44,9 +41,14 @@ target_include_directories( ll::colladadom SYSTEM INTERFACE
${LIBS_PREBUILT_DIR}/include/collada/1.4
)
if (WINDOWS)
target_link_libraries(ll::colladadom INTERFACE libcollada14dom23-s ll::libxml ll::minizip-ng )
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::libxml ll::minizip-ng)
target_link_libraries(ll::colladadom INTERFACE collada14dom ll::boost ll::libxml ll::minizip-ng)
elseif (LINUX)
target_link_libraries(ll::colladadom INTERFACE collada14dom ll::libxml ll::minizip-ng)
# GLIB uses pcre, so we need to keep it for Linux
add_library( ll::pcre INTERFACE IMPORTED )
use_prebuilt_binary(pcre)
target_link_libraries( ll::pcre INTERFACE pcrecpp pcre )
target_link_libraries(ll::colladadom INTERFACE collada14dom ll::boost ll::libxml ll::minizip-ng)
endif()

View File

@ -10,9 +10,7 @@ if (WINDOWS)
# <FS:Ansariel> ARCH_PREBUILT_DIRS_RELEASE is "." and would cause searching for the lib in the wrong place when not using VS
##target_link_libraries( ll::nghttp2 INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/nghttp2.lib)
target_link_libraries( ll::nghttp2 INTERFACE nghttp2.lib)
elseif (DARWIN)
target_link_libraries( ll::nghttp2 INTERFACE libnghttp2.dylib)
else (WINDOWS)
target_link_libraries( ll::nghttp2 INTERFACE libnghttp2.a )
endif (WINDOWS)
else ()
target_link_libraries( ll::nghttp2 INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libnghttp2.a)
endif ()
target_include_directories( ll::nghttp2 SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/nghttp2)

View File

@ -1,5 +1,6 @@
# -*- cmake -*-
include(Prebuilt)
include(Linking)
include_guard()
add_library( ll::openssl INTERFACE IMPORTED )
@ -7,9 +8,9 @@ add_library( ll::openssl INTERFACE IMPORTED )
use_system_binary(openssl)
use_prebuilt_binary(openssl)
if (WINDOWS)
target_link_libraries(ll::openssl INTERFACE libssl libcrypto)
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 ssl crypto dl)
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)
endif (WINDOWS)

View File

@ -15,8 +15,8 @@ add_library( ll::libpng INTERFACE IMPORTED )
use_system_binary(libpng)
use_prebuilt_binary(libpng)
if (WINDOWS)
target_link_libraries(ll::libpng INTERFACE libpng16)
target_link_libraries(ll::libpng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libpng16.lib)
else()
target_link_libraries(ll::libpng INTERFACE png16 )
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)

View File

@ -4,13 +4,31 @@ include(Prebuilt)
include_guard()
add_library( ll::tracy INTERFACE IMPORTED )
set(USE_TRACY OFF CACHE BOOL "Use Tracy profiler.")
# default Tracy profiling on for test builds, but off for all others
string(TOLOWER ${VIEWER_CHANNEL} channel_lower)
if(WINDOWS AND channel_lower MATCHES "^second life test")
option(USE_TRACY "Use Tracy profiler." ON)
else()
option(USE_TRACY "Use Tracy profiler." OFF)
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)
use_prebuilt_binary(tracy)
target_include_directories( ll::tracy SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/tracy)
# target_link_libraries( ll::tracy INTERFACE TracyClient )
target_compile_definitions(ll::tracy INTERFACE -DTRACY_ENABLE=1 -DTRACY_ONLY_IPV4=1)
if (USE_TRACY_ON_DEMAND)
target_compile_definitions(ll::tracy INTERFACE -DTRACY_ON_DEMAND=1)
endif ()
if (USE_TRACY_LOCAL_ONLY)
target_compile_definitions(ll::tracy INTERFACE -DTRACY_NO_BROADCAST=1 -DTRACY_ONLY_LOCALHOST=1)
endif ()
# See: indra/llcommon/llprofiler.h
add_compile_definitions(LL_PROFILER_CONFIGURATION=3)

View File

@ -1,19 +0,0 @@
# -*- cmake -*-
include_guard()
include(Prebuilt)
add_library( ll::uriparser INTERFACE IMPORTED )
use_system_binary( uriparser )
use_prebuilt_binary(uriparser)
if (WINDOWS)
target_link_libraries( ll::uriparser INTERFACE uriparser)
elseif (LINUX)
target_link_libraries( ll::uriparser INTERFACE uriparser)
elseif (DARWIN)
target_link_libraries( ll::uriparser INTERFACE liburiparser.dylib)
endif (WINDOWS)
target_include_directories( ll::uriparser SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/uriparser)

View File

@ -1,11 +0,0 @@
# -*- cmake -*-
include(Prebuilt)
include_guard()
add_library( ll::xmlrpc-epi INTERFACE IMPORTED )
use_system_binary( xmlrpc-epi )
use_prebuilt_binary(xmlrpc-epi)
target_link_libraries(ll::xmlrpc-epi INTERFACE xmlrpc-epi )
target_include_directories( ll::xmlrpc-epi SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)

View File

@ -12,9 +12,9 @@ endif()
use_prebuilt_binary(zlib-ng)
if (WINDOWS)
target_link_libraries( ll::zlib-ng INTERFACE zlib )
target_link_libraries( ll::zlib-ng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/zlib.lib )
else()
target_link_libraries( ll::zlib-ng INTERFACE z )
target_link_libraries( ll::zlib-ng INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libz.a )
endif (WINDOWS)
if( NOT LINUX )

View File

@ -252,8 +252,7 @@ LLAvatarAppearanceDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index,
LLWearableType::EType t = (LLWearableType::EType)va_arg(argp,int);
mWearables.push_back(t);
}
va_end( argp ); // <FS:ND/> Needs to be freed when done.
va_end(argp);
}
ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index) const

View File

@ -27,8 +27,6 @@
#ifndef LL_LOCALTEXTUREOBJECT_H
#define LL_LOCALTEXTUREOBJECT_H
#include <boost/shared_ptr.hpp>
#include "llpointer.h"
#include "llgltexture.h"

View File

@ -559,7 +559,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
}
if (mLastWeight != mLastWeight)
{
mLastWeight = mCurWeight+.001;
mLastWeight = mCurWeight+.001f;
}
// perform differential update of morph

View File

@ -34,7 +34,6 @@
#include "llpolymorph.h"
#include "llwearable.h"
#include "llfasttimer.h"
#include "llcallstack.h"
#include "llpolyskeletaldistortion.h"
@ -206,11 +205,6 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )
// needed?
// joint->storeScaleForReset( newScale );
// BENTO for detailed stack tracing of params.
std::stringstream ostr;
ostr << "LLPolySkeletalDistortion::apply, id " << getID() << " " << getName() << " effective wt " << effective_weight << " last wt " << mLastWeight << " scaleDelta " << scaleDelta << " offset " << offset;
LLScopedContextString str(ostr.str());
joint->setScale(newScale, true);
}

View File

@ -106,7 +106,7 @@ void LLTexLayerSetBuffer::pushProjection() const
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
gGL.loadIdentity();
gGL.ortho(0.0f, getCompositeWidth(), 0.0f, getCompositeHeight(), -1.0f, 1.0f);
gGL.ortho(0.0f, (F32)getCompositeWidth(), 0.0f, (F32)getCompositeHeight(), -1.0f, 1.0f);
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.pushMatrix();

View File

@ -806,16 +806,12 @@ bool LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid)
if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND))
{
// Just put it on the decode queue.
// Just put it on the decode queue it if it's not already in the queue
LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has local asset file already" << LL_ENDL;
// <FS:Ansariel> FIRE-480: Opening multiple instances causes sound failures
//mImpl->mDecodeQueue.push_back(uuid);
// ...only add it if it's note already in the queue
if (std::find(mImpl->mDecodeQueue.begin(), mImpl->mDecodeQueue.end(), uuid) == mImpl->mDecodeQueue.end())
{
mImpl->mDecodeQueue.push_back(uuid);
mImpl->mDecodeQueue.emplace_back(uuid);
}
// </FS:Ansariel>
return true;
}

View File

@ -1367,13 +1367,13 @@ void LLAudioSource::pruneSoundLog()
{
std::map<LLUUID, LLSoundHistoryItem>::iterator iter = gSoundHistory.begin();
std::map<LLUUID, LLSoundHistoryItem>::iterator end = gSoundHistory.end();
U64 lowest_time = (*iter).second.mTimeStopped;
U64 lowest_time = (U64)(*iter).second.mTimeStopped;
LLUUID lowest_id = (*iter).first;
for ( ; iter != end; ++iter)
{
if ((*iter).second.mTimeStopped < lowest_time)
{
lowest_time = (*iter).second.mTimeStopped;
lowest_time = (U64)(*iter).second.mTimeStopped;
lowest_id = (*iter).first;
}
}
@ -1972,7 +1972,17 @@ bool LLAudioData::load()
{
// Hrm. Right now, let's unset the buffer, since it's empty.
gAudiop->cleanupBuffer(mBufferp);
mBufferp = NULL;
mBufferp = nullptr;
if (!gDirUtilp->fileExists(wav_path))
{
mHasLocalData = false;
mHasDecodedData = false;
mHasCompletedDecode = false;
mHasDecodeFailed = false;
mHasWAVLoadFailed = false;
gAudiop->preloadSound(mID);
}
// <FS:Ansariel> FIRE-480: Opening multiple instances causes sound failures
if (!gDirUtilp->fileExists(wav_path))

View File

@ -38,7 +38,7 @@
LLStringTable LLCharacter::sVisualParamNames(1024);
std::vector< LLCharacter* > LLCharacter::sInstances;
std::list< LLCharacter* > LLCharacter::sInstances;
bool LLCharacter::sAllowInstancesChange = true ;
//-----------------------------------------------------------------------------
@ -53,7 +53,6 @@ LLCharacter::LLCharacter()
mSkeletonSerialNum( 0 )
{
llassert_always(sAllowInstancesChange) ;
sInstances.push_back(this);
mMotionController.setCharacter( this );
mPauseRequest = new LLPauseRequestHandle();
@ -66,28 +65,12 @@ LLCharacter::LLCharacter()
//-----------------------------------------------------------------------------
LLCharacter::~LLCharacter()
{
for (LLVisualParam *param = getFirstVisualParam();
param;
param = getNextVisualParam())
for (const auto& it : mVisualParamIndexMap)
{
delete param;
delete it.second;
}
size_t i ;
size_t size = sInstances.size() ;
for(i = 0 ; i < size ; i++)
{
if(sInstances[i] == this)
{
break ;
}
}
llassert_always(i < size) ;
llassert_always(sAllowInstancesChange) ;
sInstances[i] = sInstances[size - 1] ;
sInstances.pop_back() ;
}

View File

@ -256,6 +256,28 @@ public:
S32 getVisualParamCount() const { return (S32)mVisualParamIndexMap.size(); }
LLVisualParam* getVisualParam(const char *name);
// <FS:Ansariel> [Legacy Bake]
//void animateTweakableVisualParams(F32 delta)
void animateTweakableVisualParams(F32 delta, bool upload_bake)
{
for (auto& it : mVisualParamIndexMap)
{
if (it.second->isTweakable())
{
// <FS:Ansariel> [Legacy Bake]
//it.second->animate(delta);
it.second->animate(delta, upload_bake);
}
}
}
void applyAllVisualParams(ESex avatar_sex)
{
for (auto& it : mVisualParamIndexMap)
{
it.second->apply(avatar_sex);
}
}
ESex getSex() const { return mSex; }
void setSex( ESex sex ) { mSex = sex; }
@ -266,7 +288,7 @@ public:
U32 getSkeletonSerialNum() const { return mSkeletonSerialNum; }
void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; }
static std::vector< LLCharacter* > sInstances;
static std::list< LLCharacter* > sInstances;
static bool sAllowInstancesChange ; //debug use
virtual void setHoverOffset(const LLVector3& hover_offset, bool send_update=true) { mHoverOffset = hover_offset; }

View File

@ -32,7 +32,6 @@
#include "lljoint.h"
#include "llmath.h"
#include "llcallstack.h"
#include <boost/algorithm/string.hpp>
//<FS:ND> Query by JointKey rather than just a string, the key can be a U32 index for faster lookup
@ -363,7 +362,6 @@ void LLJoint::setPosition( const LLVector3& requested_pos, bool apply_attachment
{
if (pos != active_override && do_debug_joint(getName()))
{
LLScopedContextString str("setPosition");
LL_DEBUGS("Avatar") << " joint " << getName() << " requested_pos " << requested_pos
<< " overriden by attachment " << active_override << LL_ENDL;
}
@ -371,12 +369,7 @@ void LLJoint::setPosition( const LLVector3& requested_pos, bool apply_attachment
}
if ((pos != getPosition()) && do_debug_joint(getName()))
{
LLScopedContextString str("setPosition");
LLCallStack cs;
LLContextStatus con_status;
LL_DEBUGS("Avatar") << " joint " << getName() << " set pos " << pos << LL_ENDL;
LL_DEBUGS("Avatar") << "CONTEXT:\n" << "====================\n" << con_status << "====================" << LL_ENDL;
LL_DEBUGS("Avatar") << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL;
}
if (pos != getPosition())
{
@ -900,7 +893,6 @@ void LLJoint::setScale( const LLVector3& requested_scale, bool apply_attachment_
{
if (scale != active_override && do_debug_joint(getName()))
{
LLScopedContextString str("setScale");
LL_DEBUGS("Avatar") << " joint " << getName() << " requested_scale " << requested_scale
<< " overriden by attachment " << active_override << LL_ENDL;
}
@ -908,12 +900,7 @@ void LLJoint::setScale( const LLVector3& requested_scale, bool apply_attachment_
}
if ((mXform.getScale() != scale) && do_debug_joint(getName()))
{
LLScopedContextString str("setScale");
LLCallStack cs;
LLContextStatus con_status;
LL_DEBUGS("Avatar") << " joint " << getName() << " set scale " << scale << LL_ENDL;
LL_DEBUGS("Avatar") << "CONTEXT:\n" << "====================\n" << con_status << LL_ENDL;
LL_DEBUGS("Avatar") << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL;
}
mXform.setScale(scale);
touch();

View File

@ -2229,7 +2229,12 @@ bool LLKeyframeMotion::dumpToFile(const std::string& name)
}
S32 file_size = getFileSize();
U8* buffer = new U8[file_size];
U8* buffer = new(std::nothrow) U8[file_size];
if (!buffer)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Bad memory allocation for buffer, file: " << name << " " << file_size << LL_ENDL;
}
LL_DEBUGS("BVH") << "Dumping " << outfilename << LL_ENDL;
LLDataPackerBinaryBuffer dp(buffer, file_size);
@ -2409,13 +2414,10 @@ void LLKeyframeMotion::onLoadComplete(const LLUUID& asset_uuid,
{
LLUUID* id = (LLUUID*)user_data;
std::vector<LLCharacter* >::iterator char_iter = LLCharacter::sInstances.begin();
while(char_iter != LLCharacter::sInstances.end() &&
(*char_iter)->getID() != *id)
{
++char_iter;
}
auto char_iter = std::find_if(LLCharacter::sInstances.begin(), LLCharacter::sInstances.end(), [&](LLCharacter* c)
{
return c->getID() == *id;
});
delete id;
@ -2440,7 +2442,12 @@ void LLKeyframeMotion::onLoadComplete(const LLUUID& asset_uuid,
LLFileSystem file(asset_uuid, type, LLFileSystem::READ);
S32 size = file.getSize();
U8* buffer = new U8[size];
U8* buffer = new(std::nothrow) U8[size];
if (!buffer)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Bad memory allocation for buffer of size: " << size << LL_ENDL;
}
file.read((U8*)buffer, size); /*Flawfinder: ignore*/
LL_DEBUGS("Animation") << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL;

View File

@ -386,7 +386,7 @@ bool LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor;
// roll is critically damped interpolation between current roll and angular velocity-derived target roll
mRoll = LLSmoothInterpolation::lerp(mRoll, target_roll, U32Milliseconds(100));
mRoll = LLSmoothInterpolation::lerp(mRoll, target_roll, F32Milliseconds(100.f));
LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
mPelvisState->setRotation(roll);

View File

@ -10,7 +10,6 @@ include(Boost)
include(LLSharedLibs)
include(Copy3rdPartyLibs)
include(ZLIBNG)
include(URIPARSER)
include(Tracy)
@ -19,8 +18,6 @@ set(llcommon_SOURCE_FILES
commoncontrol.cpp
indra_constants.cpp
lazyeventapi.cpp
llallocator.cpp
llallocator_heap_profile.cpp
llapp.cpp
llapr.cpp
llassettype.cpp
@ -29,7 +26,6 @@ set(llcommon_SOURCE_FILES
llbase64.cpp
llbitpack.cpp
llcallbacklist.cpp
llcallstack.cpp
llcleanup.cpp
llcommon.cpp
llcommonutils.cpp
@ -128,8 +124,6 @@ set(llcommon_HEADER_FILES
lazyeventapi.h
linden_common.h
llalignedarray.h
llallocator.h
llallocator_heap_profile.h
llapp.h
llapr.h
llassettype.h
@ -139,7 +133,6 @@ set(llcommon_HEADER_FILES
llbitpack.h
llboost.h
llcallbacklist.h
llcallstack.h
llcleanup.h
llcommon.h
llcommonutils.h
@ -267,16 +260,8 @@ if (DARWIN)
list(APPEND llcommon_HEADER_FILES llsys_objc.h)
list(APPEND llcommon_SOURCE_FILES llsys_objc.mm)
endif (DARWIN)
# <FS:Beq> Tracy Profiler support
list(APPEND llcommon_SOURCE_FILES llprofiler.cpp)
if (USE_TRACY)
list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp)
endif()
# </FS:Beq>
# <FS:ND> Add all nd* files. memory pool, intrinsics, ...
SET( llcommon_ND_SOURCE_FILES
nd/ndexceptions.cpp
nd/ndlogthrottle.cpp
@ -300,6 +285,10 @@ list(APPEND llcommon_SOURCE_FILES "tea.cpp" )
list(APPEND llcommon_HEADER_FILES "tea.h" )
# </FS:ND>
if (USE_TRACY)
list(APPEND llcommon_SOURCE_FILES llprofiler.cpp)
endif ()
list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
add_library (llcommon ${llcommon_SOURCE_FILES})
@ -320,7 +309,6 @@ target_link_libraries(
ll::expat
ll::zlib-ng
ll::boost
ll::uriparser
ll::oslibraries
ll::tracy
)

View File

@ -1,8 +0,0 @@
// Just a simple wrapper to easily import the single tracy source file and save
// all the pain of cross platform libraries in the Tracy 3p build.
#include "linden_common.h"
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
#include "TracyClient.cpp"
#endif // LL_PROFILER_CONFIGURATION

View File

@ -1,156 +0,0 @@
/**
* @file llallocator_heap_profile.cpp
* @brief Implementation of the parser for tcmalloc heap profile data.
* @author Brad Kittenbrink
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
// <FS:ND> Disable some warnings on newer GCC versions.
// This might also trigger on something like 4.8, but I did not such a GCC to test anything lower than 4.9 and higher than 4.6
//<FS:TS> It does trigger on 4.8. Not sure about 4.7.
#if LL_LINUX
#pragma GCC diagnostic ignored "-Wuninitialized"
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) >= 40800
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
#endif
// </FS:ND>
#include "linden_common.h"
#include "llallocator_heap_profile.h"
#if LL_MSVC
// disable warning about boost::lexical_cast returning uninitialized data
// when it fails to parse the string
#pragma warning (disable:4701)
#pragma warning (disable:4702)
#endif
#include <boost/algorithm/string/split.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/range/iterator_range.hpp>
static const std::string HEAP_PROFILE_MAGIC_STR = "heap profile:";
static bool is_separator(char c)
{
return isspace(c) || c == '[' || c == ']' || c == ':';
}
void LLAllocatorHeapProfile::parse(std::string const & prof_text)
{
// a typedef for handling a token in the string buffer
// it's a begin/end pair of string::const_iterators
typedef boost::iterator_range<std::string::const_iterator> range_t;
mLines.clear();
if(prof_text.compare(0, HEAP_PROFILE_MAGIC_STR.length(), HEAP_PROFILE_MAGIC_STR) != 0)
{
// *TODO - determine if there should be some better error state than
// mLines being empty. -brad
LL_WARNS() << "invalid heap profile data passed into parser." << LL_ENDL;
return;
}
std::vector< range_t > prof_lines;
std::string::const_iterator prof_begin = prof_text.begin() + HEAP_PROFILE_MAGIC_STR.length();
range_t prof_range(prof_begin, prof_text.end());
boost::algorithm::split(prof_lines,
prof_range,
boost::bind(std::equal_to<llwchar>(), '\n', _1));
std::vector< range_t >::const_iterator i;
for(i = prof_lines.begin(); i != prof_lines.end() && !i->empty(); ++i)
{
range_t const & line_text = *i;
std::vector<range_t> line_elems;
boost::algorithm::split(line_elems,
line_text,
is_separator);
std::vector< range_t >::iterator j;
j = line_elems.begin();
while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
llassert_always(j != line_elems.end());
U32 live_count = boost::lexical_cast<U32>(*j);
++j;
while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
llassert_always(j != line_elems.end());
U64 live_size = boost::lexical_cast<U64>(*j);
++j;
while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
llassert_always(j != line_elems.end());
U32 tot_count = boost::lexical_cast<U32>(*j);
++j;
while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
llassert_always(j != line_elems.end());
U64 tot_size = boost::lexical_cast<U64>(*j);
++j;
while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
llassert(j != line_elems.end());
if (j != line_elems.end())
{
++j; // skip the '@'
mLines.push_back(line(live_count, live_size, tot_count, tot_size));
line & current_line = mLines.back();
for(; j != line_elems.end(); ++j)
{
if(!j->empty())
{
U32 marker = boost::lexical_cast<U32>(*j);
current_line.mTrace.push_back(marker);
}
}
}
}
// *TODO - parse MAPPED_LIBRARIES section here if we're ever interested in it
}
void LLAllocatorHeapProfile::dump(std::ostream & out) const
{
for (const LLAllocatorHeapProfile::line& line : mLines)
{
out << line.mLiveCount << ": " << line.mLiveSize << '[' << line.mTotalCount << ": " << line.mTotalSize << "] @";
for (const stack_marker marker : line.mTrace)
{
out << ' ' << marker;
}
out << '\n';
}
out.flush();
}

View File

@ -1,71 +0,0 @@
/**
* @file llallocator_heap_profile.h
* @brief Declaration of the parser for tcmalloc heap profile data.
* @author Brad Kittenbrink
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLALLOCATOR_HEAP_PROFILE_H
#define LL_LLALLOCATOR_HEAP_PROFILE_H
#include "stdtypes.h"
#include <map>
#include <vector>
class LLAllocatorHeapProfile
{
public:
typedef int stack_marker;
typedef std::vector<stack_marker> stack_trace;
struct line {
line(U32 live_count, U64 live_size, U32 tot_count, U64 tot_size) :
mLiveSize(live_size),
mTotalSize(tot_size),
mLiveCount(live_count),
mTotalCount(tot_count)
{
}
U64 mLiveSize, mTotalSize;
U32 mLiveCount, mTotalCount;
stack_trace mTrace;
};
typedef std::vector<line> lines_t;
LLAllocatorHeapProfile()
{
}
void parse(std::string const & prof_text);
void dump(std::ostream & out) const;
public:
lines_t mLines;
};
#endif // LL_LLALLOCATOR_HEAP_PROFILE_H

View File

@ -90,7 +90,7 @@ bool LLApp::sDisableCrashlogger = false;
// Local flag for whether or not to do logging in signal handlers.
//static
bool LLApp::sLogInSignal = false;
bool LLApp::sLogInSignal = true;
// static
// Keeps track of application status
@ -373,6 +373,9 @@ static std::map<LLApp::EAppStatus, const char*> statusDesc
// static
void LLApp::setStatus(EAppStatus status)
{
auto status_it = statusDesc.find(status);
std::string status_text = status_it != statusDesc.end() ? std::string(status_it->second) : std::to_string(status);
LL_INFOS() << "status: " << status_text << LL_ENDL;
// notify everyone waiting on sStatus any time its value changes
sStatus.set_all(status);
@ -381,18 +384,7 @@ void LLApp::setStatus(EAppStatus status)
if (! LLEventPumps::wasDeleted())
{
// notify interested parties of status change
LLSD statsd;
auto found = statusDesc.find(status);
if (found != statusDesc.end())
{
statsd = found->second;
}
else
{
// unknown status? at least report value
statsd = LLSD::Integer(status);
}
LLEventPumps::instance().obtain("LLApp").post(llsd::map("status", statsd));
LLEventPumps::instance().obtain("LLApp").post(llsd::map("status", status_text));
}
}
@ -493,6 +485,33 @@ int LLApp::getPid()
#endif
}
// static
void LLApp::notifyOutOfDiskSpace()
{
static const U32Seconds min_interval = U32Seconds(60);
static U32Seconds min_time_to_send = U32Seconds(0);
U32Seconds now = LLTimer::getTotalTime();
if (now < min_time_to_send)
return;
min_time_to_send = now + min_interval;
if (LLApp* app = instance())
{
app->sendOutOfDiskSpaceNotification();
}
else
{
LL_WARNS() << "No app instance" << LL_ENDL;
}
}
// virtual
void LLApp::sendOutOfDiskSpaceNotification()
{
LL_WARNS() << "Should never be called" << LL_ENDL; // Should be overridden
}
#ifndef LL_WINDOWS
void setup_signals()
{
@ -660,6 +679,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
{
LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL;
}
if (LLApp::isError())
{
// Received second fatal signal while handling first, just die right now
@ -697,11 +717,11 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
clear_signals();
raise(signum);
return;
} else {
if (LLApp::sLogInSignal)
{
LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL;
}
}
if (LLApp::sLogInSignal)
{
LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL;
}
}
}

View File

@ -202,6 +202,8 @@ public:
static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not)
static int getPid();
static void notifyOutOfDiskSpace();
//
// Sleep for specified time while still running
//
@ -301,6 +303,8 @@ protected:
*/
void stepFrame();
virtual void sendOutOfDiskSpaceNotification();
private:
// Contains the filename of the minidump file after a crash.
char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH];

View File

@ -28,6 +28,7 @@
#include "linden_common.h"
#include "llapr.h"
#include "llapp.h"
#include "llmutex.h"
#include "apr_dso.h"
@ -616,7 +617,11 @@ S32 LLAPRFile::writeEx(const std::string& filename, const void *buf, S32 offset,
apr_status_t s = apr_file_write(file_handle, buf, &bytes_written);
if (s != APR_SUCCESS)
{
LL_WARNS("APR") << " Attempting to write filename: " << filename << LL_ENDL;
LL_WARNS("APR") << "Attempting to write filename: " << filename << LL_ENDL;
if (APR_STATUS_IS_ENOSPC(s))
{
LLApp::notifyOutOfDiskSpace();
}
ll_apr_warn_status(s);
bytes_written = 0;
}

View File

@ -1,188 +0,0 @@
/**
* @file llcallstack.cpp
* @brief run-time extraction of the current callstack
*
* $LicenseInfo:firstyear=2016&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2016, 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 "llcommon.h"
#include "llcallstack.h"
#include "StackWalker.h"
#include "llthreadlocalstorage.h"
#if LL_WINDOWS
class LLCallStackImpl: public StackWalker
{
public:
LLCallStackImpl():
StackWalker(false,0) // non-verbose, options = 0
{
}
~LLCallStackImpl()
{
}
void getStack(std::vector<std::string>& stack, S32 skip_count=0, bool verbose=false)
{
m_stack.clear();
ShowCallstack(verbose);
// Skip the first few lines because they're just bookkeeping for LLCallStack,
// plus any additional lines requested to skip.
S32 first_line = skip_count + 3;
for (S32 i=first_line; i<m_stack.size(); ++i)
{
stack.push_back(m_stack[i]);
}
}
protected:
virtual void OnOutput(LPCSTR szText)
{
m_stack.push_back(szText);
}
std::vector<std::string> m_stack;
};
#else
// Stub - not implemented currently on other platforms.
class LLCallStackImpl
{
public:
LLCallStackImpl() {}
~LLCallStackImpl() {}
void getStack(std::vector<std::string>& stack, S32 skip_count=0, bool verbose=false)
{
stack.clear();
}
};
#endif
LLCallStackImpl *LLCallStack::s_impl = NULL;
LLCallStack::LLCallStack(S32 skip_count, bool verbose):
m_skipCount(skip_count),
m_verbose(verbose)
{
if (!s_impl)
{
s_impl = new LLCallStackImpl;
}
LLTimer t;
s_impl->getStack(m_strings, m_skipCount, m_verbose);
}
bool LLCallStack::contains(const std::string& str)
{
for (const std::string& src_str : m_strings)
{
if (src_str.find(str) != std::string::npos)
{
return true;
}
}
return false;
}
std::ostream& operator<<(std::ostream& s, const LLCallStack& call_stack)
{
#ifndef LL_RELEASE_FOR_DOWNLOAD
for (const std::string& str : call_stack.m_strings)
{
s << str;
}
#else
s << "UNAVAILABLE IN RELEASE";
#endif
return s;
}
LLContextStrings::LLContextStrings()
{
}
// static
LLContextStrings* LLContextStrings::getThreadLocalInstance()
{
LLContextStrings *cons = LLThreadLocalSingletonPointer<LLContextStrings>::getInstance();
if (!cons)
{
LLThreadLocalSingletonPointer<LLContextStrings>::setInstance(new LLContextStrings);
}
return LLThreadLocalSingletonPointer<LLContextStrings>::getInstance();
}
// static
void LLContextStrings::addContextString(const std::string& str)
{
LLContextStrings *cons = getThreadLocalInstance();
//LL_INFOS() << "CTX " << (S32)cons << " ADD " << str << " CNT " << cons->m_contextStrings[str] << LL_ENDL;
cons->m_contextStrings[str]++;
}
// static
void LLContextStrings::removeContextString(const std::string& str)
{
LLContextStrings *cons = getThreadLocalInstance();
cons->m_contextStrings[str]--;
//LL_INFOS() << "CTX " << (S32)cons << " REMOVE " << str << " CNT " << cons->m_contextStrings[str] << LL_ENDL;
if (cons->m_contextStrings[str] == 0)
{
cons->m_contextStrings.erase(str);
}
}
// static
bool LLContextStrings::contains(const std::string& str)
{
const std::map<std::string,S32>& strings =
LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->m_contextStrings;
for (const std::map<std::string,S32>::value_type& str_pair : strings)
{
if (str_pair.first.find(str) != std::string::npos)
{
return true;
}
}
return false;
}
// static
void LLContextStrings::output(std::ostream& os)
{
const std::map<std::string,S32>& strings =
LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->m_contextStrings;
for (const std::map<std::string,S32>::value_type& str_pair : strings)
{
os << str_pair.first << "[" << str_pair.second << "]" << "\n";
}
}
// static
std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status)
{
LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->output(s);
return s;
}
bool LLContextStatus::contains(const std::string& str)
{
return LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->contains(str);
}

View File

@ -1,93 +0,0 @@
/**
* @file llcallstack.h
* @brief run-time extraction of the current callstack
*
* $LicenseInfo:firstyear=2016&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2016, 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 <map>
class LLCallStackImpl;
class LLCallStack
{
public:
LLCallStack(S32 skip_count=0, bool verbose=false);
std::vector<std::string> m_strings;
bool m_verbose;
bool contains(const std::string& str);
private:
static LLCallStackImpl *s_impl;
S32 m_skipCount;
};
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLCallStack& call_stack);
class LLContextStrings
{
public:
LLContextStrings();
static void addContextString(const std::string& str);
static void removeContextString(const std::string& str);
static void output(std::ostream& os);
static LLContextStrings* getThreadLocalInstance();
static bool contains(const std::string& str);
private:
std::map<std::string,S32> m_contextStrings;
};
class LLScopedContextString
{
public:
LLScopedContextString(const std::string& str):
m_str(str)
{
LLContextStrings::addContextString(m_str);
}
~LLScopedContextString()
{
LLContextStrings::removeContextString(m_str);
}
private:
std::string m_str;
};
// Mostly exists as a class to hook an ostream override to.
struct LLContextStatus
{
bool contains(const std::string& str);
};
LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status);
// <FS:Ansariel> Restore this: Don't need this in actual relase builds
#ifdef LL_RELEASE_FOR_DOWNLOAD
#define dumpStack(tag)
#else
#define dumpStack(tag) \
LL_DEBUGS(tag) << "STACK:\n" \
<< "====================\n" \
<< LLCallStack() \
<< "====================" \
<< LL_ENDL;
#endif
// </FS:Ansariel>

View File

@ -31,8 +31,9 @@
#include "llexception.h"
#include <boost/fiber/fss.hpp>
#include <boost/fiber/future/promise.hpp>
#include <boost/fiber/future/future.hpp>
#include <boost/fiber/future/promise.hpp>
#include <boost/fiber/recursive_mutex.hpp>
#include "mutex.h"
#include "llsingleton.h"
#include "llinstancetracker.h"
@ -307,6 +308,12 @@ public:
// use mutex, lock, condition_variable suitable for coroutines
using Mutex = boost::fibers::mutex;
using RMutex = boost::fibers::recursive_mutex;
// With C++17, LockType is deprecated: at this point we can directly
// declare 'std::unique_lock lk(some_mutex)' without explicitly stating
// the mutex type. Sadly, making LockType an alias template for
// std::unique_lock doesn't work the same way: Class Template Argument
// Deduction only works for class templates, not alias templates.
using LockType = std::unique_lock<Mutex>;
using cv_status = boost::fibers::cv_status;
using ConditionVariable = boost::fibers::condition_variable;

View File

@ -41,20 +41,11 @@
#include "llstring.h"
#include "llfasttimer.h"
static const F64 DATE_EPOCH = 0.0;
static const F64 LL_APR_USEC_PER_SEC = 1000000.0;
// should be APR_USEC_PER_SEC, but that relies on INT64_C which
// isn't defined in glib under our build set up for some reason
LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH)
{}
LLDate::LLDate(const LLDate& date) :
mSecondsSinceEpoch(date.mSecondsSinceEpoch)
{}
LLDate::LLDate(F64SecondsImplicit seconds_since_epoch) :
mSecondsSinceEpoch(seconds_since_epoch.value())
{}

View File

@ -45,16 +45,13 @@
*/
class LL_COMMON_API LLDate
{
static constexpr F64 DATE_EPOCH = 0.0;
public:
/**
* @brief Construct a date equal to epoch.
*/
LLDate();
/**
* @brief Construct a date equal to the source date.
*/
LLDate(const LLDate& date);
constexpr LLDate() : mSecondsSinceEpoch(DATE_EPOCH)
{}
/**
* @brief Construct a date from a seconds since epoch value.

View File

@ -30,7 +30,6 @@
#define LL_LLDOUBLEDISPATCH_H
#include <list>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>

View File

@ -55,7 +55,7 @@
#include "llsingleton.h"
#include "llstl.h"
#include "lltimer.h"
#include <boost/fiber/recursive_mutex.hpp>
#include "llprofiler.h"
// On Mac, got:
// #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define
@ -170,7 +170,7 @@ namespace {
virtual void recordMessage(LLError::ELevel level,
const std::string& message) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING;
if (LLError::getAlwaysFlush())
{
mFile << message << std::endl;
@ -237,7 +237,7 @@ namespace {
virtual void recordMessage(LLError::ELevel level,
const std::string& message) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING;
// The default colors for error, warn and debug are now a bit more pastel
// and easier to read on the default (black) terminal background but you
// now have the option to set the color of each via an environment variables:
@ -280,7 +280,7 @@ namespace {
LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING;
static std::string s_ansi_bold = createBoldANSI(); // bold text
static std::string s_ansi_reset = createResetANSI(); // reset
// ANSI color code escape sequence, message, and reset in one fprintf call
@ -317,7 +317,7 @@ namespace {
virtual void recordMessage(LLError::ELevel level,
const std::string& message) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING;
mBuffer->addLine(message);
}
@ -344,7 +344,7 @@ namespace {
virtual void recordMessage(LLError::ELevel level,
const std::string& message) override
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING;
debugger_print(message);
}
};
@ -512,7 +512,7 @@ namespace
LLError::TimeFunction mTimeFunction;
Recorders mRecorders;
boost::fibers::recursive_mutex mRecorderMutex;
LL_PROFILE_MUTEX_NAMED(LLCoros::RMutex, mRecorderMutex, "Log Recorders");
int mShouldLogCallCounter;
@ -535,7 +535,6 @@ namespace
mCrashFunction(NULL),
mTimeFunction(NULL),
mRecorders(),
mRecorderMutex(),
mShouldLogCallCounter(0)
{
}
@ -1056,7 +1055,7 @@ namespace LLError
return;
}
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
std::unique_lock lock(s->mRecorderMutex);
std::unique_lock lock(s->mRecorderMutex); LL_PROFILE_MUTEX_LOCK(s->mRecorderMutex);
s->mRecorders.push_back(recorder);
}
@ -1067,7 +1066,7 @@ namespace LLError
return;
}
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
std::unique_lock lock(s->mRecorderMutex);
std::unique_lock lock(s->mRecorderMutex); LL_PROFILE_MUTEX_LOCK(s->mRecorderMutex);
s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder),
s->mRecorders.end());
}
@ -1116,7 +1115,7 @@ namespace LLError
std::shared_ptr<RECORDER> findRecorder()
{
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
std::unique_lock lock(s->mRecorderMutex);
std::unique_lock lock(s->mRecorderMutex); LL_PROFILE_MUTEX_LOCK(s->mRecorderMutex);
return findRecorderPos<RECORDER>(s).first;
}
@ -1127,7 +1126,7 @@ namespace LLError
bool removeRecorder()
{
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
std::unique_lock lock(s->mRecorderMutex);
std::unique_lock lock(s->mRecorderMutex); LL_PROFILE_MUTEX_LOCK(s->mRecorderMutex);
auto found = findRecorderPos<RECORDER>(s);
if (found.first)
{
@ -1227,13 +1226,13 @@ namespace
void writeToRecorders(const LLError::CallSite& site, const std::string& message)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING;
LLError::ELevel level = site.mLevel;
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
std::string escaped_message;
std::unique_lock lock(s->mRecorderMutex);
std::unique_lock lock(s->mRecorderMutex); LL_PROFILE_MUTEX_LOCK(s->mRecorderMutex);
for (LLError::RecorderPtr& r : s->mRecorders)
{
// <FS:Ansariel> Crash fix
@ -1294,24 +1293,21 @@ namespace
}
namespace {
// We need a couple different mutexes, but we want to use the same mechanism
// for both. Make getMutex() a template function with different instances
// for different MutexDiscriminator values.
enum MutexDiscriminator
{
LOG_MUTEX,
STACKS_MUTEX
};
// Some logging calls happen very early in processing -- so early that our
// module-static variables aren't yet initialized. getMutex() wraps a
// function-static LLMutex so that early calls can still have a valid
// LLMutex instance.
template <MutexDiscriminator MTX>
LLMutex* getMutex()
auto getLogMutex()
{
// guaranteed to be initialized the first time control reaches here
static LLMutex sMutex;
return &sMutex;
static LL_PROFILE_MUTEX_NAMED(std::recursive_mutex, sLogMutex, "Log Mutex");
return &sLogMutex;
}
auto getStacksMutex()
{
// guaranteed to be initialized the first time control reaches here
static LL_PROFILE_MUTEX_NAMED(std::recursive_mutex, sStacksMutex, "Stacks Mutex");
return &sStacksMutex;
}
bool checkLevelMap(const LevelMap& map, const std::string& key,
@ -1365,9 +1361,9 @@ namespace LLError
bool Log::shouldLog(CallSite& site)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5);
if (!lock.isLocked())
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING;
std::unique_lock lock(*getLogMutex(), std::try_to_lock); LL_PROFILE_MUTEX_LOCK(*getLogMutex());
if (!lock)
{
return false;
}
@ -1410,9 +1406,9 @@ namespace LLError
void Log::flush(const std::ostringstream& out, const CallSite& site)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
if (!lock.isLocked())
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING;
std::unique_lock lock(*getLogMutex(), std::try_to_lock); LL_PROFILE_MUTEX_LOCK(*getLogMutex());
if (!lock)
{
return;
}
@ -1542,8 +1538,8 @@ namespace LLError
//static
void LLCallStacks::push(const char* function, const int line)
{
LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
if (!lock.isLocked())
std::unique_lock lock(*getStacksMutex(), std::try_to_lock); LL_PROFILE_MUTEX_LOCK(*getStacksMutex());
if (!lock)
{
return;
}
@ -1567,8 +1563,8 @@ namespace LLError
//static
void LLCallStacks::end(const std::ostringstream& out)
{
LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
if (!lock.isLocked())
std::unique_lock lock(*getStacksMutex(), std::try_to_lock); LL_PROFILE_MUTEX_LOCK(*getStacksMutex());
if (!lock)
{
return;
}
@ -1584,8 +1580,8 @@ namespace LLError
//static
void LLCallStacks::print()
{
LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
if (!lock.isLocked())
std::unique_lock lock(*getStacksMutex(), std::try_to_lock); LL_PROFILE_MUTEX_LOCK(*getStacksMutex());
if (!lock)
{
return;
}

View File

@ -32,7 +32,6 @@
#include "llpointer.h"
#include "llrefcount.h"
#include "boost/function.hpp"
#include "boost/shared_ptr.hpp"
#include <string>
class LLSD;
@ -190,7 +189,7 @@ namespace LLError
{}
void recordMessage(LLError::ELevel level, const std::string& message) override
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
mCallable(level, message);
}
private:

View File

@ -429,7 +429,7 @@ public:
// path, then stores it to mTarget.
virtual bool post(const LLSD& event)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
// Extract the element specified by 'mPath' from 'event'. To perform a
// generic type-appropriate store through mTarget, construct an

View File

@ -38,16 +38,8 @@
#include <vector>
#include <deque>
#include <functional>
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
#pragma warning (disable : 4264)
#endif
#include <boost/signals2.hpp>
#if LL_WINDOWS
#pragma warning (pop)
#endif
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include <boost/utility.hpp> // noncopyable
#include <boost/optional/optional.hpp>

View File

@ -248,6 +248,24 @@ int LLFile::close(LLFILE * file)
return ret_value;
}
std::string LLFile::getContents(const std::string& filename)
{
LLFILE* fp = fopen(filename, "rb"); /* Flawfinder: ignore */
if (fp)
{
fseek(fp, 0, SEEK_END);
U32 length = ftell(fp);
fseek(fp, 0, SEEK_SET);
std::vector<char> buffer(length);
size_t nread = fread(buffer.data(), 1, length, fp);
fclose(fp);
return std::string(buffer.data(), nread);
}
return LLStringUtil::null;
}
int LLFile::remove(const std::string& filename, int supress_error)
{
@ -308,7 +326,7 @@ int LLFile::rename(const std::string& filename, const std::string& newname, int
return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, supress_error);
}
bool LLFile::copy(const std::string from, const std::string to)
bool LLFile::copy(const std::string& from, const std::string& to)
{
bool copied = false;
LLFILE* in = LLFile::fopen(from, "rb"); /* Flawfinder: ignore */
@ -450,7 +468,7 @@ LLFILE * LLFile::_Fiopen(const std::string& filename,
if (valid[n] == 0)
return (0); // no valid mode
else if (norepflag && mode & (ios_base::out || ios_base::app)
else if (norepflag && mode & (ios_base::out | ios_base::app)
&& (fp = LLFile::fopen(filename, "r")) != 0) /* Flawfinder: ignore */
{ // file must not exist, close and fail
fclose(fp);

View File

@ -67,6 +67,8 @@ public:
static int close(LLFILE * file);
static std::string getContents(const std::string& filename);
// perms is a permissions mask like 0777 or 0700. In most cases it will
// be overridden by the user's umask. It is ignored on Windows.
// mkdir() considers "directory already exists" to be SUCCESS.
@ -75,7 +77,7 @@ public:
static int rmdir(const std::string& filename);
static int remove(const std::string& filename, int supress_error = 0);
static int rename(const std::string& filename,const std::string& newname, int supress_error = 0);
static bool copy(const std::string from, const std::string to);
static bool copy(const std::string& from, const std::string& to);
static int stat(const std::string& filename,llstat* file_status);
static bool isdir(const std::string& filename);
@ -158,7 +160,7 @@ private:
* Does The Right Thing when passed a non-ASCII pathname. Sadly, that isn't
* true of Microsoft's std::ifstream.
*/
class LL_COMMON_API llifstream : public std::ifstream
class LL_COMMON_API llifstream : public std::ifstream
{
// input stream associated with a C stream
public:
@ -203,7 +205,7 @@ class LL_COMMON_API llifstream : public std::ifstream
* Right Thing when passed a non-ASCII pathname. Sadly, that isn't true of
* Microsoft's std::ofstream.
*/
class LL_COMMON_API llofstream : public std::ofstream
class LL_COMMON_API llofstream : public std::ofstream
{
public:
// Constructors:
@ -239,7 +241,7 @@ class LL_COMMON_API llofstream : public std::ofstream
/**
* @breif filesize helpers.
* @brief filesize helpers.
*
* The file size helpers are not considered particularly efficient,
* and should only be used for config files and the like -- not in a

View File

@ -185,7 +185,7 @@ canonise_fl(FL_Locale *l) {
#define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn)
struct IDToCode {
LANGID id;
char* code;
const char* code;
};
static const IDToCode both_to_code[] = {
{ML(ENGLISH,US), "en_US.ISO_8859-1"},

View File

@ -31,7 +31,6 @@
#include <vector>
#include <list>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_enum.hpp>
#include <boost/unordered_map.hpp>

View File

@ -52,7 +52,7 @@ namespace LLInstanceTrackerPrivate
struct StaticBase
{
// We need to be able to lock static data while manipulating it.
std::mutex mMutex;
LL_PROFILE_MUTEX_NAMED(std::mutex, mMutex, "InstanceTracker Data");
};
void logerrs(const char* cls, const std::string&, const std::string&, const std::string&);
@ -101,7 +101,8 @@ public:
static size_t instanceCount()
{
return LockStatic()->mMap.size();
LockStatic lock; LL_PROFILE_MUTEX_LOCK(lock->mMutex);
return lock->mMap.size();
}
// snapshot of std::pair<const KEY, std::shared_ptr<SUBCLASS>> pairs, for
@ -236,7 +237,7 @@ public:
static ptr_t getInstance(const KEY& k)
{
LockStatic lock;
LockStatic lock; LL_PROFILE_MUTEX_LOCK(lock->mMutex);
const InstanceMap& map(lock->mMap);
typename InstanceMap::const_iterator found = map.find(k);
return (found == map.end()) ? NULL : found->second;
@ -252,19 +253,19 @@ protected:
ptr_t ptr(static_cast<T*>(this), [](T*){});
// save corresponding weak_ptr for future reference
mSelf = ptr;
LockStatic lock;
LockStatic lock; LL_PROFILE_MUTEX_LOCK(lock->mMutex);
add_(lock, key, ptr);
}
public:
virtual ~LLInstanceTracker()
{
LockStatic lock;
LockStatic lock; LL_PROFILE_MUTEX_LOCK(lock->mMutex);
remove_(lock);
}
protected:
virtual void setKey(KEY key)
{
LockStatic lock;
LockStatic lock; LL_PROFILE_MUTEX_LOCK(lock->mMutex);
// Even though the shared_ptr we store in our map has a no-op deleter
// for T itself, letting the use count decrement to 0 will still
// delete the use-count object. Capture the shared_ptr we just removed
@ -376,7 +377,8 @@ public:
static size_t instanceCount()
{
return LockStatic()->mSet.size();
LockStatic lock; LL_PROFILE_MUTEX_LOCK(lock->mMutex);
return lock->mSet.size();
}
// snapshot of std::shared_ptr<SUBCLASS> pointers
@ -488,14 +490,16 @@ protected:
// save corresponding weak_ptr for future reference
mSelf = ptr;
// Also store it in our class-static set to track this instance.
LockStatic()->mSet.emplace(ptr);
LockStatic lock; LL_PROFILE_MUTEX_LOCK(lock->mMutex);
lock->mSet.emplace(ptr);
}
public:
virtual ~LLInstanceTracker()
{
// convert weak_ptr to shared_ptr because that's what we store in our
// InstanceSet
LockStatic()->mSet.erase(mSelf.lock());
LockStatic lock; LL_PROFILE_MUTEX_LOCK(lock->mMutex);
lock->mSet.erase(mSelf.lock());
}
protected:
LLInstanceTracker(const LLInstanceTracker& other):

View File

@ -51,13 +51,28 @@
//----------------------------------------------------------------------------
//static
// most important memory metric for texture streaming
// On Windows, this should agree with resource monitor -> performance -> memory -> available
// On OS X, this should be activity monitor -> memory -> (physical memory - memory used)
// NOTE: this number MAY be less than the actual available memory on systems with more than MaxHeapSize64 GB of physical memory (default 16GB)
// In that case, should report min(available, sMaxHeapSizeInKB-sAllocateMemInKB)
U32Kilobytes LLMemory::sAvailPhysicalMemInKB(U32_MAX);
// Installed physical memory
U32Kilobytes LLMemory::sMaxPhysicalMemInKB(0);
// Maximimum heap size according to the user's settings (default 16GB)
U32Kilobytes LLMemory::sMaxHeapSizeInKB(U32_MAX);
// Current memory usage
U32Kilobytes LLMemory::sAllocatedMemInKB(0);
U32Kilobytes LLMemory::sAllocatedPageSizeInKB(0);
static LLTrace::SampleStatHandle<F64Megabytes> sAllocatedMem("allocated_mem", "active memory in use by application");
static LLTrace::SampleStatHandle<F64Megabytes> sVirtualMem("virtual_mem", "virtual memory assigned to application");
U32Kilobytes LLMemory::sAllocatedMemInKB(0);
U32Kilobytes LLMemory::sAllocatedPageSizeInKB(0);
U32Kilobytes LLMemory::sMaxHeapSizeInKB(U32_MAX);
void ll_assert_aligned_func(uintptr_t ptr,U32 alignment)
{
@ -85,8 +100,14 @@ void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size)
//static
void LLMemory::updateMemoryInfo()
{
LL_PROFILE_ZONE_SCOPED
U32Kilobytes avail_phys; // <FS:Beq/> align MemInfo across platforms
LL_PROFILE_ZONE_SCOPED;
sMaxPhysicalMemInKB = gSysMemory.getPhysicalMemoryKB();
U32Kilobytes avail_mem;
LLMemoryInfo::getAvailableMemoryKB(avail_mem);
sAvailPhysicalMemInKB = avail_mem;
#if LL_WINDOWS
PROCESS_MEMORY_COUNTERS counters;
@ -97,25 +118,9 @@ void LLMemory::updateMemoryInfo()
}
sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(counters.WorkingSetSize));
// sample(sAllocatedMem, sAllocatedMemInKB); // <FS:Beq/> align MemInfo across platforms
sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage));
sample(sVirtualMem, sAllocatedPageSizeInKB);
// <FS:Beq> align MemInfo across platforms
// U32Kilobytes avail_phys, avail_virtual;
// LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ;
// sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB);
// if(sMaxPhysicalMemInKB > sAllocatedMemInKB)
// {
// sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ;
// }
// else
// {
// sAvailPhysicalMemInKB = U32Kilobytes(0);
// }
U32Kilobytes avail_virtual;
LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ;
// </FS:Beq>
#elif defined(LL_DARWIN)
task_vm_info info;
mach_msg_type_number_t infoCount = TASK_VM_INFO_COUNT;
@ -124,7 +129,7 @@ void LLMemory::updateMemoryInfo()
{
// Our Windows definition of PagefileUsage is documented by Microsoft as "the total amount of
// memory that the memory manager has committed for a running process", which is rss.
sAllocatedPageSizeInKB = U64Bytes(info.resident_size);
sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(info.resident_size));
// Activity Monitor => Inspect Process => Real Memory Size appears to report resident_size
// Activity monitor => main window memory column appears to report phys_footprint, which spot checks as at least 30% less.
@ -134,71 +139,26 @@ void LLMemory::updateMemoryInfo()
// reported for the app by the Memory Monitor in Instruments.' It is still about 8% bigger than phys_footprint.
//
// (On Windows, we use WorkingSetSize.)
sAllocatedMemInKB = U64Bytes(info.resident_size - info.reusable);
sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(info.resident_size - info.reusable));
}
else
{
LL_WARNS() << "task_info failed" << LL_ENDL;
}
// Total installed and available physical memory are properties of the host, not just our process.
vm_statistics64_data_t vmstat;
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
mach_port_t host = mach_host_self();
vm_size_t page_size;
host_page_size(host, &page_size);
kern_return_t result = host_statistics64(host, HOST_VM_INFO64, reinterpret_cast<host_info_t>(&vmstat), &count);
if (result == KERN_SUCCESS) {
// This is what Chrome reports as 'the "Physical Memory Free" value reported by the Memory Monitor in Instruments.'
// Note though that inactive pages are not included here and not yet free, but could become so under memory pressure.
// <FS:Beq> align MemInfo across platforms
// sAvailPhysicalMemInKB = U32Bytes(vmstat.free_count * page_size);
// sMaxPhysicalMemInKB = LLMemoryInfo::getHardwareMemSize();
avail_phys = U64Bytes( (vmstat.free_count + vmstat.inactive_count) * page_size);
sMaxHeapSizeInKB = LLMemoryInfo::getHardwareMemSize();
// </FS:Beq>
}
else
{
LL_WARNS() << "task_info failed" << LL_ENDL;
}
// <FS:Beq> align MemInfo across platforms
#elif defined(LL_LINUX)
// Use sysinfo() to get the total physical memory.
struct sysinfo info;
sysinfo(&info);
sMaxHeapSizeInKB = U32Kilobytes::convert((U64Bytes)info.totalram); // Total RAM in system
avail_phys = U32Kilobytes::convert((U64Bytes)info.freeram); // Total Free RAM in system
sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(LLMemory::getCurrentRSS())); // represents the RAM allocated by this process only (inline with the windows implementation)
// </FS:Beq>
sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(LLMemory::getCurrentRSS())); // represents the RAM allocated by this process only (in line with the windows implementation)
#else
//not valid for other systems for now.
LL_WARNS() << "LLMemory::updateMemoryInfo() not implemented for this platform." << LL_ENDL;
sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS());
sMaxPhysicalMemInKB = U64Bytes(U32_MAX);
sAvailPhysicalMemInKB = U64Bytes(U32_MAX);
#endif
// <FS:Beq> align MemInfo across platforms
sample(sAllocatedMem, sAllocatedMemInKB);
// sMaxPhysicalMem - max this process can use = the lesser of (what we already have + what's available) or MaxHeap
sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB);
if(sMaxPhysicalMemInKB > sAllocatedMemInKB)
{
sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ;
}
else
{
sAvailPhysicalMemInKB = U32Kilobytes(0);
}
// debug log the memory info
LL_DEBUGS("MemoryInfo") << "Memory Info:"
<< "Heap: " << sMaxHeapSizeInKB << "; " // Heap
<< "Free: " << sAvailPhysicalMemInKB << "; " // Free
<< "FS Use: " << sAllocatedMemInKB << "; " // In use by this instance right now
<< "FS Max poss: " << sMaxPhysicalMemInKB << "; " // How much we could have (In use now + free)
<< LL_ENDL;
// </FS:Beq>
sAvailPhysicalMemInKB = llmin(sAvailPhysicalMemInKB, sMaxHeapSizeInKB - sAllocatedMemInKB);
return ;
}
@ -229,16 +189,16 @@ void* LLMemory::tryToAlloc(void* address, U32 size)
//static
void LLMemory::logMemoryInfo(bool update)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
if(update)
{
updateMemoryInfo() ;
}
LL_INFOS() << "Current allocated physical memory(KB): " << sAllocatedMemInKB << LL_ENDL ;
LL_INFOS() << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << LL_ENDL ;
LL_INFOS() << "Current available physical memory(KB): " << sAvailPhysicalMemInKB << LL_ENDL ;
LL_INFOS() << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << LL_ENDL ;
LL_INFOS() << llformat("Current allocated physical memory: %.2f MB", sAllocatedMemInKB / 1024.0) << LL_ENDL;
LL_INFOS() << llformat("Current allocated page size: %.2f MB", sAllocatedPageSizeInKB / 1024.0) << LL_ENDL;
LL_INFOS() << llformat("Current available physical memory: %.2f MB", sAvailPhysicalMemInKB / 1024.0) << LL_ENDL;
LL_INFOS() << llformat("Current max usable memory: %.2f MB", sMaxPhysicalMemInKB / 1024.0) << LL_ENDL;
}
//static

View File

@ -100,7 +100,7 @@ void LLMutex::unlock()
bool LLMutex::isLocked()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
if (!mMutex.try_lock())
{
return true;
@ -124,7 +124,7 @@ LLThread::id_t LLMutex::lockingThread() const
bool LLMutex::trylock()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
if (isSelfLocked())
{ //redundant lock
mCount++;
@ -161,7 +161,7 @@ LLSharedMutex::LLSharedMutex()
bool LLSharedMutex::isLocked() const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
std::lock_guard<std::mutex> lock(mLockMutex);
return !mLockingThreads.empty();
@ -169,7 +169,7 @@ bool LLSharedMutex::isLocked() const
bool LLSharedMutex::isThreadLocked() const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
LLThread::id_t current_thread = LLThread::currentID();
std::lock_guard<std::mutex> lock(mLockMutex);
@ -179,7 +179,7 @@ bool LLSharedMutex::isThreadLocked() const
void LLSharedMutex::lockShared()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
LLThread::id_t current_thread = LLThread::currentID();
mLockMutex.lock();
@ -204,7 +204,7 @@ void LLSharedMutex::lockShared()
void LLSharedMutex::lockExclusive()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
LLThread::id_t current_thread = LLThread::currentID();
mLockMutex.lock();
@ -237,7 +237,7 @@ void LLSharedMutex::lockExclusive()
bool LLSharedMutex::trylockShared()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
LLThread::id_t current_thread = LLThread::currentID();
std::lock_guard<std::mutex> lock(mLockMutex);
@ -260,7 +260,7 @@ bool LLSharedMutex::trylockShared()
bool LLSharedMutex::trylockExclusive()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
LLThread::id_t current_thread = LLThread::currentID();
std::lock_guard<std::mutex> lock(mLockMutex);
@ -282,7 +282,7 @@ bool LLSharedMutex::trylockExclusive()
void LLSharedMutex::unlockShared()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
LLThread::id_t current_thread = LLThread::currentID();
std::lock_guard<std::mutex> lock(mLockMutex);
@ -303,7 +303,7 @@ void LLSharedMutex::unlockShared()
void LLSharedMutex::unlockExclusive()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
LLThread::id_t current_thread = LLThread::currentID();
std::lock_guard<std::mutex> lock(mLockMutex);
@ -338,20 +338,20 @@ LLCondition::~LLCondition()
void LLCondition::wait()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
std::unique_lock< std::mutex > lock(mMutex);
mCond.wait(lock);
}
void LLCondition::signal()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
mCond.notify_one();
}
void LLCondition::broadcast()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
mCond.notify_all();
}
@ -364,7 +364,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex)
: mMutex(mutex),
mLocked(false)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
if (mMutex)
mLocked = mMutex->trylock();
}
@ -373,7 +373,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
: mMutex(mutex),
mLocked(false)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
if (!mMutex)
return;
@ -388,7 +388,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
LLMutexTrylock::~LLMutexTrylock()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
if (mMutex && mLocked)
mMutex->unlock();
}
@ -400,7 +400,7 @@ LLMutexTrylock::~LLMutexTrylock()
//
LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
if(mutex)
{
mutex->lock();
@ -419,7 +419,7 @@ LLScopedLock::~LLScopedLock()
void LLScopedLock::unlock()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
if(mLocked)
{
mMutex->unlock();

View File

@ -46,8 +46,11 @@
template <class Type> class LLPointer
{
public:
template<typename Subclass>
friend class LLPointer;
LLPointer() :
mPointer(NULL)
mPointer(nullptr)
{
}
@ -63,6 +66,12 @@ public:
ref();
}
LLPointer(LLPointer<Type>&& ptr) noexcept
{
mPointer = ptr.mPointer;
ptr.mPointer = nullptr;
}
// Support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLPointer(const LLPointer<Subclass>& ptr) :
@ -71,6 +80,13 @@ public:
ref();
}
template<typename Subclass>
LLPointer(LLPointer<Subclass>&& ptr) noexcept :
mPointer(ptr.get())
{
ptr.mPointer = nullptr;
}
~LLPointer()
{
unref();
@ -82,11 +98,11 @@ public:
const Type& operator*() const { return *mPointer; }
Type& operator*() { return *mPointer; }
//operator BOOL() const { return (mPointer != NULL); } // <FS:Ansariel> We should not need this anymore
operator bool() const { return (mPointer != NULL); }
bool operator!() const { return (mPointer == NULL); }
bool isNull() const { return (mPointer == NULL); }
bool notNull() const { return (mPointer != NULL); }
//operator BOOL() const { return (mPointer != nullptr); } // <FS:Ansariel> We should not need this anymore
operator bool() const { return (mPointer != nullptr); }
bool operator!() const { return (mPointer == nullptr); }
bool isNull() const { return (mPointer == nullptr); }
bool notNull() const { return (mPointer != nullptr); }
operator Type*() const { return mPointer; }
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
@ -107,6 +123,17 @@ public:
return *this;
}
LLPointer<Type>& operator =(LLPointer<Type>&& ptr)
{
if (mPointer != ptr.mPointer)
{
unref();
mPointer = ptr.mPointer;
ptr.mPointer = nullptr;
}
return *this;
}
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
@ -115,6 +142,18 @@ public:
return *this;
}
template<typename Subclass>
LLPointer<Type>& operator =(LLPointer<Subclass>&& ptr)
{
if (mPointer != ptr.mPointer)
{
unref();
mPointer = ptr.mPointer;
ptr.mPointer = nullptr;
}
return *this;
}
// Just exchange the pointers, which will not change the reference counts.
static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
{
@ -141,9 +180,9 @@ protected:
if (mPointer)
{
Type *temp = mPointer;
mPointer = NULL;
mPointer = nullptr;
temp->unref();
if (mPointer != NULL)
if (mPointer != nullptr)
{
LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL;
unref();
@ -168,9 +207,11 @@ protected:
template <class Type> class LLConstPointer
{
template<typename Subclass>
friend class LLConstPointer;
public:
LLConstPointer() :
mPointer(NULL)
mPointer(nullptr)
{
}
@ -186,6 +227,12 @@ public:
ref();
}
LLConstPointer(LLConstPointer<Type>&& ptr) noexcept
{
mPointer = ptr.mPointer;
ptr.mPointer = nullptr;
}
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLConstPointer(const LLConstPointer<Subclass>& ptr) :
@ -194,6 +241,13 @@ public:
ref();
}
template<typename Subclass>
LLConstPointer(LLConstPointer<Subclass>&& ptr) noexcept :
mPointer(ptr.get())
{
ptr.mPointer = nullptr;
}
~LLConstPointer()
{
unref();
@ -203,11 +257,11 @@ public:
const Type* operator->() const { return mPointer; }
const Type& operator*() const { return *mPointer; }
//operator BOOL() const { return (mPointer != NULL); } // <FS:Ansariel> We should not need this anymore
operator bool() const { return (mPointer != NULL); }
bool operator!() const { return (mPointer == NULL); }
bool isNull() const { return (mPointer == NULL); }
bool notNull() const { return (mPointer != NULL); }
//operator BOOL() const { return (mPointer != nullptr); } // <FS:Ansariel> We should not need this anymore
operator bool() const { return (mPointer != nullptr); }
bool operator!() const { return (mPointer == nullptr); }
bool isNull() const { return (mPointer == nullptr); }
bool notNull() const { return (mPointer != nullptr); }
operator const Type*() const { return mPointer; }
bool operator !=(const Type* ptr) const { return (mPointer != ptr); }
@ -239,6 +293,17 @@ public:
return *this;
}
LLConstPointer<Type>& operator =(LLConstPointer<Type>&& ptr)
{
if (mPointer != ptr.mPointer)
{
unref();
mPointer = ptr.mPointer;
ptr.mPointer = nullptr;
}
return *this;
}
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLConstPointer<Type>& operator =(const LLConstPointer<Subclass>& ptr)
@ -252,6 +317,18 @@ public:
return *this;
}
template<typename Subclass>
LLConstPointer<Type>& operator =(LLConstPointer<Subclass>&& ptr)
{
if (mPointer != ptr.mPointer)
{
unref();
mPointer = ptr.mPointer;
ptr.mPointer = nullptr;
}
return *this;
}
// Just exchange the pointers, which will not change the reference counts.
static void swap(LLConstPointer<Type>& a, LLConstPointer<Type>& b)
{
@ -278,9 +355,9 @@ protected:
if (mPointer)
{
const Type *temp = mPointer;
mPointer = NULL;
mPointer = nullptr;
temp->unref();
if (mPointer != NULL)
if (mPointer != nullptr)
{
LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL;
unref();
@ -313,7 +390,7 @@ public:
: LLPointer<Type>(ptr),
mStayUnique(false)
{
if (ptr.mForceUnique)
if (ptr.mStayUnique)
{
makeUnique();
}

View File

@ -90,9 +90,6 @@
#ifndef LL_MSVC
#define LL_MSVC 1
#endif
#if _MSC_VER < 1400
#define LL_MSVC7 //Visual C++ 2003 or earlier
#endif
#endif
// Deal with minor differences on Unixy OSes.
@ -146,8 +143,6 @@
#endif
// level 4 warnings that we need to disable:
#pragma warning (disable : 4244) // possible loss of data on conversions
#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template
#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class
#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class
#endif // LL_MSVC

View File

@ -32,7 +32,6 @@
#include "llwin32headerslean.h"
#include "llexception.h"
#include "apr_thread_proc.h"
#include <boost/shared_ptr.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/optional.hpp>
#include <boost/noncopyable.hpp>

View File

@ -1,32 +1,36 @@
/**
* @file llprofiler.cpp
* @brief llprofiler Telemetry abstraction
*
* $LicenseInfo:firstyear=2021&license=fsviewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2021, The Phoenix Firestorm Project, 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
*
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
* $/LicenseInfo$
*/
* @file llprofiler.cpp
* @brief Implementation of llprofiler
* @author Rye Cogtail
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, 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 "TracyClient.cpp"
#include "llprofiler.h"
namespace LLProfiler
{
bool active{false};
}

View File

@ -85,12 +85,6 @@ namespace LLProfiler
#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
#define TRACY_ENABLE 1
// Normally these would be enabled but we want to be able to build any viewer with Tracy enabled and run the Tracy server on another machine
// They must be undefined in order to work across multiple machines
// #define TRACY_NO_BROADCAST 1
// #define TRACY_ONLY_LOCALHOST 1
#define TRACY_ONLY_IPV4 1
#include "tracy/Tracy.hpp"
// <FS:Beq> Fixed mutual exclusion issues with RAM and GPU. NOTE: This might still break on Apple in which case we'll need to restrict that platform
//// GPU Mutually exclusive with detailed memory tracing
@ -131,6 +125,12 @@ namespace LLProfiler
#define LL_PROFILE_ZONE_INFO(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF ) // RGB cyan
#define LL_PROFILE_ZONE_WARN(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 ) // RGB red
#define LL_PROFILE_MUTEX(type, varname) TracyLockable(type, varname)
#define LL_PROFILE_MUTEX_NAMED(type, varname, desc) TracyLockableN(type, varname, desc)
#define LL_PROFILE_MUTEX_SHARED(type, varname) TracySharedLockable(type, varname)
#define LL_PROFILE_MUTEX_SHARED_NAMED(type, varname, desc) TracySharedLockableN(type, varname, desc)
#define LL_PROFILE_MUTEX_LOCK(varname) { auto& mutex = varname; LockMark(mutex); }
// <FS:Beq> Additional FS Tracy macros
#define LL_PROFILE_ZONE_COLOR(color) ZoneNamedC( ___tracy_scoped_zone, color, LLProfiler::active );
#define LL_PROFILE_PLOT( name, value ) TracyPlot( name, value);
@ -155,6 +155,13 @@ namespace LLProfiler
#define LL_PROFILE_ZONE_ERR(name) (void)(name); // Not supported
#define LL_PROFILE_ZONE_INFO(name) (void)(name); // Not supported
#define LL_PROFILE_ZONE_WARN(name) (void)(name); // Not supported
#define LL_PROFILE_MUTEX(type, varname) type varname
#define LL_PROFILE_MUTEX_NAMED(type, varname, desc) type varname
#define LL_PROFILE_MUTEX_SHARED(type, varname) type varname
#define LL_PROFILE_MUTEX_SHARED_NAMED(type, varname, desc) type varname
#define LL_PROFILE_MUTEX_LOCK(varname) // LL_PROFILE_MUTEX_LOCK is a no-op when Tracy is disabled
// <FS:Beq> Additional FS Tracy macros
#define LL_PROFILE_ZONE_COLOR(color)
#define LL_PROFILE_PLOT( name, value )
@ -187,6 +194,13 @@ namespace LLProfiler
#define LL_PROFILE_ZONE_ERR(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000 ) // RGB yellow
#define LL_PROFILE_ZONE_INFO(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF ) // RGB cyan
#define LL_PROFILE_ZONE_WARN(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 ) // RGB red
#define LL_PROFILE_MUTEX(type, varname) TracyLockable(type, varname)
#define LL_PROFILE_MUTEX_NAMED(type, varname, desc) TracyLockableN(type, varname, desc)
#define LL_PROFILE_MUTEX_SHARED(type, varname) TracySharedLockable(type, varname)
#define LL_PROFILE_MUTEX_SHARED_NAMED(type, varname, desc) TracySharedLockableN(type, varname, desc)
#define LL_PROFILE_MUTEX_LOCK(varname) { auto& mutex = varname; LockMark(mutex); } // see https://github.com/wolfpld/tracy/issues/575
// <FS:Beq> Additional FS Tracy macros
#define LL_PROFILE_ZONE_COLOR(color) ZoneNamedC( ___tracy_scoped_zone, color, LLProfiler::active );
#define LL_PROFILE_PLOT( name, value ) TracyPlot( name, value);

View File

@ -432,12 +432,12 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req)
using namespace std::chrono_literals;
const auto throttle_time = 2ms;
if( req->mDeferUntil > LL::WorkQueue::TimePoint::clock::now())
if (req->mDeferUntil > LL::WorkQueue::TimePoint::clock::now())
{
ms_sleep(throttle_time.count());
ms_sleep((U32)throttle_time.count());
}
// if we're still not ready to retry then requeue
if( req->mDeferUntil > LL::WorkQueue::TimePoint::clock::now())
if (req->mDeferUntil > LL::WorkQueue::TimePoint::clock::now())
{
LL_PROFILE_ZONE_NAMED("qtpr - defer requeue");
@ -506,7 +506,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req)
// if (sleep_time.count() > 0)
// {
// ms_sleep(sleep_time.count());
// ms_sleep((U32)sleep_time.count());
// }
// }
// processRequest(req);

View File

@ -85,7 +85,7 @@ inline F32 ll_internal_random<F32>()
// Per Monty, it's important to clamp using the correct fmodf() rather
// than expanding to F64 for fmod() and then truncating back to F32. Prior
// to this change, we were getting sporadic ll_frand() == 1.0 results.
F32 rv{ narrow<F32>(gRandomGenerator()) };
F32 rv{ narrow<F64>(gRandomGenerator()) };
if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f);
return rv;
}

View File

@ -30,7 +30,6 @@
#define LL_LLRUN_H
#include <vector>
#include <boost/shared_ptr.hpp>
class LLRunnable;

View File

@ -30,6 +30,7 @@
#include "linden_common.h"
#include "llsd.h"
#include "llbase64.h"
#include "llerror.h"
#include "../llmath/llmath.h"
#include "llformat.h"
@ -105,6 +106,9 @@ public:
static void reset(Impl*& var, Impl* impl);
///< safely set var to refer to the new impl (possibly shared)
static void move(Impl*& var, Impl*& impl);
///< safely move impl from one object to another
static Impl& safe( Impl*);
static const Impl& safe(const Impl*);
///< since a NULL Impl* is used for undefined, this ensures there is
@ -122,11 +126,17 @@ public:
virtual void assign(Impl*& var, LLSD::Boolean);
virtual void assign(Impl*& var, LLSD::Integer);
virtual void assign(Impl*& var, LLSD::Real);
virtual void assign(Impl*& var, const char*);
virtual void assign(Impl*& var, const LLSD::String&);
virtual void assign(Impl*& var, const LLSD::UUID&);
virtual void assign(Impl*& var, const LLSD::Date&);
virtual void assign(Impl*& var, const LLSD::URI&);
virtual void assign(Impl*& var, const LLSD::Binary&);
virtual void assign(Impl*& var, LLSD::String&&);
virtual void assign(Impl*& var, LLSD::UUID&&);
virtual void assign(Impl*& var, LLSD::Date&&);
virtual void assign(Impl*& var, LLSD::URI&&);
virtual void assign(Impl*& var, LLSD::Binary&&);
///< If the receiver is the right type and unshared, these are simple
// data assignments, othewise the default implementation handless
// constructing the proper Impl subclass
@ -142,11 +152,13 @@ public:
virtual const String& asStringRef() const { static const std::string empty; return empty; }
virtual bool has(const String&) const { return false; }
virtual LLSD get(const String&) const { return LLSD(); }
virtual String asXMLRPCValue() const { return "<nil/>"; }
virtual bool has(std::string_view) const { return false; }
virtual LLSD get(std::string_view) const { return LLSD(); }
virtual LLSD getKeys() const { return LLSD::emptyArray(); }
virtual void erase(const String&) { }
virtual const LLSD& ref(const String&) const{ return undef(); }
virtual const LLSD& ref(std::string_view) const{ return undef(); }
virtual size_t size() const { return 0; }
virtual LLSD get(size_t) const { return LLSD(); }
@ -182,7 +194,7 @@ namespace LLSDUnnamedNamespace
namespace
#endif
{
template<LLSD::Type T, class Data, class DataRef = Data>
template<LLSD::Type T, class Data, class DataRef = Data, class DataMove = Data>
class ImplBase : public LLSD::Impl
///< This class handles most of the work for a subclass of Impl
// for a given simple data type. Subclasses of this provide the
@ -195,6 +207,7 @@ namespace
public:
ImplBase(DataRef value) : mValue(value) { }
ImplBase(DataMove value) : mValue(std::move(value)) { }
virtual LLSD::Type type() const { return T; }
@ -209,11 +222,21 @@ namespace
mValue = value;
}
}
virtual void assign(LLSD::Impl*& var, DataMove value) {
if (shared())
{
Impl::assign(var, std::move(value));
}
else
{
mValue = std::move(value);
}
}
};
class ImplBoolean
: public ImplBase<LLSD::TypeBoolean, LLSD::Boolean>
class ImplBoolean final
: public ImplBase<LLSD::TypeBoolean, LLSD::Boolean, LLSD::Boolean, LLSD::Boolean&&>
{
public:
ImplBoolean(LLSD::Boolean v) : Base(v) { }
@ -222,6 +245,8 @@ namespace
virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; }
virtual LLSD::Real asReal() const { return mValue ? 1 : 0; }
virtual LLSD::String asString() const;
virtual LLSD::String asXMLRPCValue() const { return mValue ? "<boolean>1</boolean>" : "<boolean>0</boolean>"; }
};
LLSD::String ImplBoolean::asString() const
@ -233,8 +258,8 @@ namespace
{ return mValue ? "true" : ""; }
class ImplInteger
: public ImplBase<LLSD::TypeInteger, LLSD::Integer>
class ImplInteger final
: public ImplBase<LLSD::TypeInteger, LLSD::Integer, LLSD::Integer, LLSD::Integer&&>
{
public:
ImplInteger(LLSD::Integer v) : Base(v) { }
@ -243,14 +268,16 @@ namespace
virtual LLSD::Integer asInteger() const { return mValue; }
virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const;
virtual LLSD::String asXMLRPCValue() const { return "<int>" + std::to_string(mValue) + "</int>"; }
};
LLSD::String ImplInteger::asString() const
{ return llformat("%d", mValue); }
class ImplReal
: public ImplBase<LLSD::TypeReal, LLSD::Real>
class ImplReal final
: public ImplBase<LLSD::TypeReal, LLSD::Real, LLSD::Real, LLSD::Real&&>
{
public:
ImplReal(LLSD::Real v) : Base(v) { }
@ -259,6 +286,8 @@ namespace
virtual LLSD::Integer asInteger() const;
virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const;
virtual LLSD::String asXMLRPCValue() const { return "<double>" + std::to_string(mValue) + "</double>"; }
};
LLSD::Boolean ImplReal::asBoolean() const
@ -271,11 +300,12 @@ namespace
{ return llformat("%lg", mValue); }
class ImplString
: public ImplBase<LLSD::TypeString, LLSD::String, const LLSD::String&>
class ImplString final
: public ImplBase<LLSD::TypeString, LLSD::String, const LLSD::String&, LLSD::String&&>
{
public:
ImplString(const LLSD::String& v) : Base(v) { }
ImplString(LLSD::String&& v) : Base(std::move(v)) {}
virtual LLSD::Boolean asBoolean() const { return !mValue.empty(); }
virtual LLSD::Integer asInteger() const;
@ -286,9 +316,24 @@ namespace
virtual LLSD::URI asURI() const { return LLURI(mValue); }
virtual size_t size() const { return mValue.size(); }
virtual const LLSD::String& asStringRef() const { return mValue; }
virtual LLSD::String asXMLRPCValue() const { return "<string>" + LLStringFn::xml_encode(mValue) + "</string>"; }
using LLSD::Impl::assign; // Unhiding base class virtuals...
virtual void assign(LLSD::Impl*& var, const char* value)
{
if (shared())
{
Impl::assign(var, value);
}
else
{
mValue = value;
}
}
};
LLSD::Integer ImplString::asInteger() const
LLSD::Integer ImplString::asInteger() const
{
// This must treat "1.23" not as an error, but as a number, which is
// then truncated down to an integer. Hence, this code doesn't call
@ -298,7 +343,7 @@ namespace
return (int)asReal();
}
LLSD::Real ImplString::asReal() const
LLSD::Real ImplString::asReal() const
{
F64 v = 0.0;
std::istringstream i_stream(mValue);
@ -315,25 +360,32 @@ namespace
}
class ImplUUID
: public ImplBase<LLSD::TypeUUID, LLSD::UUID, const LLSD::UUID&>
class ImplUUID final
: public ImplBase<LLSD::TypeUUID, LLSD::UUID, const LLSD::UUID&, LLSD::UUID&&>
{
public:
ImplUUID(const LLSD::UUID& v) : Base(v) { }
ImplUUID(LLSD::UUID&& v) : Base(std::move(v)) { }
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::UUID asUUID() const { return mValue; }
virtual LLSD::String asXMLRPCValue() const { return "<string>" + mValue.asString() + "</string>"; }
};
class ImplDate
: public ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&>
class ImplDate final
: public ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&, LLSD::Date&&>
{
public:
ImplDate(const LLSD::Date& v)
: ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&>(v)
: ImplBase(v)
{ }
ImplDate(LLSD::Date&& v)
: ImplBase(std::move(v))
{ }
virtual LLSD::Integer asInteger() const
{
return (LLSD::Integer)(mValue.secondsSinceEpoch());
@ -344,34 +396,42 @@ namespace
}
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::Date asDate() const { return mValue; }
virtual LLSD::String asXMLRPCValue() const { return "<dateTime.iso8601>" + mValue.toHTTPDateString("%FT%T") + "</dateTime.iso8601>"; }
};
class ImplURI
: public ImplBase<LLSD::TypeURI, LLSD::URI, const LLSD::URI&>
class ImplURI final
: public ImplBase<LLSD::TypeURI, LLSD::URI, const LLSD::URI&, LLSD::URI&&>
{
public:
ImplURI(const LLSD::URI& v) : Base(v) { }
ImplURI(LLSD::URI&& v) : Base(std::move(v)) { }
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::URI asURI() const { return mValue; }
virtual LLSD::String asXMLRPCValue() const { return "<string>" + LLStringFn::xml_encode(mValue.asString()) + "</string>"; }
};
class ImplBinary
: public ImplBase<LLSD::TypeBinary, LLSD::Binary, const LLSD::Binary&>
class ImplBinary final
: public ImplBase<LLSD::TypeBinary, LLSD::Binary, const LLSD::Binary&, LLSD::Binary&&>
{
public:
ImplBinary(const LLSD::Binary& v) : Base(v) { }
ImplBinary(LLSD::Binary&& v) : Base(std::move(v)) { }
virtual const LLSD::Binary& asBinary() const{ return mValue; }
virtual LLSD::String asXMLRPCValue() const { return "<base64>" + LLBase64::encode(mValue.data(), mValue.size()) + "</base64>"; }
};
class ImplMap : public LLSD::Impl
class ImplMap final : public LLSD::Impl
{
private:
typedef std::map<LLSD::String, LLSD> DataMap;
typedef std::map<LLSD::String, LLSD, std::less<>> DataMap;
DataMap mData;
@ -387,17 +447,30 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
virtual bool has(const LLSD::String&) const;
virtual LLSD::String asXMLRPCValue() const
{
std::ostringstream os;
os << "<struct>";
for (const auto& it : mData)
{
os << "<member><name>" << LLStringFn::xml_encode(it.first) << "</name>"
<< it.second.asXMLRPCValue() << "</member>";
}
os << "</struct>";
return os.str();
}
virtual bool has(std::string_view) const;
using LLSD::Impl::get; // Unhiding get(size_t)
using LLSD::Impl::erase; // Unhiding erase(size_t)
using LLSD::Impl::ref; // Unhiding ref(size_t)
virtual LLSD get(const LLSD::String&) const;
virtual LLSD get(std::string_view) const;
virtual LLSD getKeys() const;
void insert(const LLSD::String& k, const LLSD& v);
void insert(std::string_view k, const LLSD& v);
virtual void erase(const LLSD::String&);
LLSD& ref(const LLSD::String&);
virtual const LLSD& ref(const LLSD::String&) const;
LLSD& ref(std::string_view);
virtual const LLSD& ref(std::string_view) const;
virtual size_t size() const { return mData.size(); }
@ -425,14 +498,14 @@ namespace
}
}
bool ImplMap::has(const LLSD::String& k) const
bool ImplMap::has(const std::string_view k) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
DataMap::const_iterator i = mData.find(k);
return i != mData.end();
}
LLSD ImplMap::get(const LLSD::String& k) const
LLSD ImplMap::get(const std::string_view k) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
DataMap::const_iterator i = mData.find(k);
@ -452,10 +525,10 @@ namespace
return keys;
}
void ImplMap::insert(const LLSD::String& k, const LLSD& v)
void ImplMap::insert(std::string_view k, const LLSD& v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
mData.insert(DataMap::value_type(k, v));
mData.emplace(k, v);
}
void ImplMap::erase(const LLSD::String& k)
@ -464,15 +537,21 @@ namespace
mData.erase(k);
}
LLSD& ImplMap::ref(const LLSD::String& k)
LLSD& ImplMap::ref(std::string_view k)
{
return mData[k];
DataMap::iterator i = mData.lower_bound(k);
if (i == mData.end() || mData.key_comp()(k, i->first))
{
return mData.emplace_hint(i, std::make_pair(k, LLSD()))->second;
}
return i->second;
}
const LLSD& ImplMap::ref(const LLSD::String& k) const
const LLSD& ImplMap::ref(std::string_view k) const
{
DataMap::const_iterator i = mData.lower_bound(k);
if (i == mData.end() || mData.key_comp()(k, i->first))
if (i == mData.end() || mData.key_comp()(k, i->first))
{
return undef();
}
@ -500,7 +579,7 @@ namespace
{
//std::cout << " " << (*iter).first << ": " << (*iter).second << std::endl;
Impl::calcStats((*iter).second, type_counts, share_counts);
iter++;
++iter;
}
// Add in the values for this map
@ -511,7 +590,7 @@ namespace
class ImplArray : public LLSD::Impl
{
private:
typedef std::vector<LLSD> DataVector;
typedef std::vector<LLSD> DataVector;
DataVector mData;
@ -527,6 +606,18 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
virtual LLSD::String asXMLRPCValue() const
{
std::ostringstream os;
os << "<array><data>";
for (const auto& it : mData)
{
os << it.asXMLRPCValue();
}
os << "</data></array>";
return os.str();
}
using LLSD::Impl::get; // Unhiding get(LLSD::String)
using LLSD::Impl::erase; // Unhiding erase(LLSD::String)
using LLSD::Impl::ref; // Unhiding ref(LLSD::String)
@ -647,7 +738,7 @@ namespace
while (iter != endArray())
{ // Add values for all items held in the array
Impl::calcStats((*iter), type_counts, share_counts);
iter++;
++iter;
}
// Add in the values for this array
@ -685,6 +776,16 @@ void LLSD::Impl::reset(Impl*& var, Impl* impl)
var = impl;
}
void LLSD::Impl::move(Impl*& var, Impl*& impl)
{
if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0)
{
delete var; // destroy var if usage falls to 0 and not static
}
var = impl; // Steal impl to var without incrementing use since this is a move
impl = nullptr; // null out old-impl pointer
}
LLSD::Impl& LLSD::Impl::safe(Impl* impl)
{
static Impl theUndefined(STATIC_USAGE_COUNT);
@ -738,6 +839,11 @@ void LLSD::Impl::assign(Impl*& var, LLSD::Real v)
reset(var, new ImplReal(v));
}
void LLSD::Impl::assign(Impl*& var, const char* v)
{
reset(var, new ImplString(v));
}
void LLSD::Impl::assign(Impl*& var, const LLSD::String& v)
{
reset(var, new ImplString(v));
@ -763,6 +869,31 @@ void LLSD::Impl::assign(Impl*& var, const LLSD::Binary& v)
reset(var, new ImplBinary(v));
}
void LLSD::Impl::assign(Impl*& var, LLSD::String&& v)
{
reset(var, new ImplString(std::move(v)));
}
void LLSD::Impl::assign(Impl*& var, LLSD::UUID&& v)
{
reset(var, new ImplUUID(std::move(v)));
}
void LLSD::Impl::assign(Impl*& var, LLSD::Date&& v)
{
reset(var, new ImplDate(std::move(v)));
}
void LLSD::Impl::assign(Impl*& var, LLSD::URI&& v)
{
reset(var, new ImplURI(std::move(v)));
}
void LLSD::Impl::assign(Impl*& var, LLSD::Binary&& v)
{
reset(var, new ImplBinary(std::move(v)));
}
const LLSD& LLSD::Impl::undef()
{
@ -835,6 +966,9 @@ LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0)
LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT; assign(other); }
void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); }
LLSD::LLSD(LLSD&& other) noexcept : impl(nullptr) { ALLOC_LLSD_OBJECT; Impl::move(impl, other.impl); }
void LLSD::assign(LLSD&& other) { Impl::move(impl, other.impl); }
LLSD& LLSD::operator=(LLSD&& other) noexcept { Impl::move(impl, other.impl); return *this; }
void LLSD::clear() { Impl::assignUndefined(impl); }
@ -849,6 +983,11 @@ LLSD::LLSD(const String& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const Date& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const URI& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const Binary& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(UUID&& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(std::move(v)); }
LLSD::LLSD(String&& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(std::move(v)); }
LLSD::LLSD(Date&& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(std::move(v)); }
LLSD::LLSD(URI&& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(std::move(v)); }
LLSD::LLSD(Binary&& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(std::move(v)); }
// Scalar Assignment
void LLSD::assign(Boolean v) { safe(impl).assign(impl, v); }
@ -859,6 +998,11 @@ void LLSD::assign(const UUID& v) { safe(impl).assign(impl, v); }
void LLSD::assign(const Date& v) { safe(impl).assign(impl, v); }
void LLSD::assign(const URI& v) { safe(impl).assign(impl, v); }
void LLSD::assign(const Binary& v) { safe(impl).assign(impl, v); }
void LLSD::assign(String&& v) { safe(impl).assign(impl, std::move(v)); }
void LLSD::assign(UUID&& v) { safe(impl).assign(impl, std::move(v)); }
void LLSD::assign(Date&& v) { safe(impl).assign(impl, std::move(v)); }
void LLSD::assign(URI&& v) { safe(impl).assign(impl, std::move(v)); }
void LLSD::assign(Binary&& v) { safe(impl).assign(impl, std::move(v)); }
// Scalar Accessors
LLSD::Boolean LLSD::asBoolean() const { return safe(impl).asBoolean(); }
@ -872,11 +1016,13 @@ const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); }
const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); }
LLSD::String LLSD::asXMLRPCValue() const { return "<value>" + safe(impl).asXMLRPCValue() + "</value>"; }
// const char * helpers
LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
void LLSD::assign(const char* v)
{
if(v) assign(std::string(v));
if(v) safe(impl).assign(impl, v);
else assign(std::string());
}
@ -888,24 +1034,24 @@ LLSD LLSD::emptyMap()
return v;
}
bool LLSD::has(const String& k) const { return safe(impl).has(k); }
LLSD LLSD::get(const String& k) const { return safe(impl).get(k); }
bool LLSD::has(const std::string_view k) const { return safe(impl).has(k); }
LLSD LLSD::get(const std::string_view k) const { return safe(impl).get(k); }
LLSD LLSD::getKeys() const { return safe(impl).getKeys(); }
void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v); }
void LLSD::insert(std::string_view k, const LLSD& v) { makeMap(impl).insert(k, v); }
LLSD& LLSD::with(const String& k, const LLSD& v)
LLSD& LLSD::with(std::string_view k, const LLSD& v)
{
makeMap(impl).insert(k, v);
return *this;
}
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
LLSD& LLSD::operator[](const String& k)
LLSD& LLSD::operator[](const std::string_view k)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
return makeMap(impl).ref(k);
}
const LLSD& LLSD::operator[](const String& k) const
const LLSD& LLSD::operator[](const std::string_view k) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
return safe(impl).ref(k);

View File

@ -161,6 +161,13 @@ public:
//@}
/** @name Movable */
//@{
LLSD(LLSD&& other) noexcept;
void assign(LLSD&& other);
LLSD& operator=(LLSD&& other) noexcept;
//@}
void clear(); ///< resets to Undefined
@ -188,6 +195,11 @@ public:
LLSD(const Date&);
LLSD(const URI&);
LLSD(const Binary&);
LLSD(String&&);
LLSD(UUID&&);
LLSD(Date&&);
LLSD(URI&&);
LLSD(Binary&&);
//@}
/** @name Convenience Constructors */
@ -215,6 +227,11 @@ public:
void assign(const Date&);
void assign(const URI&);
void assign(const Binary&);
void assign(String&&);
void assign(UUID&&);
void assign(Date&&);
void assign(URI&&);
void assign(Binary&&);
LLSD& operator=(Boolean v) { assign(v); return *this; }
LLSD& operator=(Integer v) { assign(v); return *this; }
@ -224,6 +241,11 @@ public:
LLSD& operator=(const Date& v) { assign(v); return *this; }
LLSD& operator=(const URI& v) { assign(v); return *this; }
LLSD& operator=(const Binary& v) { assign(v); return *this; }
LLSD& operator=(String&& v) { assign(std::move(v)); return *this; }
LLSD& operator=(UUID&& v) { assign(std::move(v)); return *this; }
LLSD& operator=(Date&& v) { assign(std::move(v)); return *this; }
LLSD& operator=(URI&& v) { assign(std::move(v)); return *this; }
LLSD& operator=(Binary&& v) { assign(std::move(v)); return *this; }
//@}
/**
@ -259,10 +281,14 @@ public:
UUID asUUID() const;
Date asDate() const;
URI asURI() const;
const Binary& asBinary() const;
const Binary& asBinary() const;
// asStringRef on any non-string type will return a ref to an empty string.
const String& asStringRef() const;
const String& asStringRef() const;
// Return "<value><((type))>((scalar value or recursive calls))</((type))></value>"
// See http://xmlrpc.com/spec.md
String asXMLRPCValue() const;
operator Boolean() const { return asBoolean(); }
operator Integer() const { return asInteger(); }
@ -275,7 +301,7 @@ public:
// This is needed because most platforms do not automatically
// convert the boolean negation as a bool in an if statement.
bool operator!() const {return !asBoolean();}
bool operator!() const { return !asBoolean(); }
//@}
/** @name Character Pointer Helpers
@ -292,24 +318,22 @@ public:
//@{
static LLSD emptyMap();
bool has(const String&) const;
LLSD get(const String&) const;
bool has(const std::string_view) const;
LLSD get(const std::string_view) const;
LLSD getKeys() const; // Return an LLSD array with keys as strings
void insert(const String&, const LLSD&);
void insert(std::string_view, const LLSD&);
void erase(const String&);
LLSD& with(const String&, const LLSD&);
LLSD& with(std::string_view, const LLSD&);
LLSD& operator[](const String&);
LLSD& operator[](const std::string_view);
LLSD& operator[](const char* c)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
return (*this)[String(c)];
return c ? (*this)[std::string_view(c)] : *this;
}
const LLSD& operator[](const String&) const;
const LLSD& operator[](const std::string_view) const;
const LLSD& operator[](const char* c) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
return (*this)[String(c)];
return c ? (*this)[std::string_view(c)] : *this;
}
//@}

View File

@ -35,16 +35,7 @@
#include "llerror.h"
#include "../llmath/llmath.h"
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable : 4702) // compiler thinks unreachable code
#endif
#include <boost/json/src.hpp>
#if LL_WINDOWS
#pragma warning (pop)
#endif
//=========================================================================
LLSD LlsdFromJson(const boost::json::value& val)

View File

@ -149,7 +149,7 @@ bool LLParamSDParser::readF32(Parser& parser, void* val_ptr)
{
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
*((F32*)val_ptr) = self.mCurReadSD->asReal();
*((F32*)val_ptr) = (F32)self.mCurReadSD->asReal();
return true;
}

View File

@ -232,7 +232,7 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes)
}
// Since we've already read 'inbuf' bytes into 'hdr_buf', prepend that
// data to whatever remains in 'str'.
LLMemoryStreamBuf already(reinterpret_cast<const U8*>(hdr_buf), inbuf);
LLMemoryStreamBuf already(reinterpret_cast<const U8*>(hdr_buf), (S32)inbuf);
cat_streambuf prebuff(&already, str.rdbuf());
std::istream prepend(&prebuff);
#if 1
@ -476,7 +476,7 @@ LLSDNotationParser::~LLSDNotationParser()
// virtual
S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
// map: { string:object, string:object }
// array: [ object, object, object ]
// undef: !
@ -567,7 +567,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) c
data,
NOTATION_FALSE_SERIAL,
false);
if(PARSE_FAILURE == cnt) parse_count = cnt;
if(PARSE_FAILURE == cnt) parse_count = (S32)cnt;
else account(cnt);
}
else
@ -593,7 +593,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) c
if(isalpha(c))
{
auto cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true);
if(PARSE_FAILURE == cnt) parse_count = cnt;
if(PARSE_FAILURE == cnt) parse_count = (S32)cnt;
else account(cnt);
}
else
@ -736,7 +736,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) c
S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
// map: { string:object, string:object }
map = LLSD::emptyMap();
S32 parse_count = 0;
@ -797,7 +797,7 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) c
S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
// array: [ object, object, object ]
array = LLSD::emptyArray();
S32 parse_count = 0;
@ -837,7 +837,7 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_dept
bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
std::string value;
auto count = deserialize_string(istr, value, mMaxBytesLeft);
if(PARSE_FAILURE == count) return false;
@ -848,7 +848,7 @@ bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
// binary: b##"ff3120ab1"
// or: b(len)"..."
@ -951,7 +951,7 @@ LLSDBinaryParser::~LLSDBinaryParser()
// virtual
S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
/**
* Undefined: '!'<br>
* Boolean: '1' for true '0' for false<br>

View File

@ -567,7 +567,7 @@ void LLSDXMLParser::Impl::parsePart(const char* buf, llssize len)
if ( buf != NULL
&& len > 0 )
{
XML_Status status = XML_Parse(mParser, buf, len, false);
XML_Status status = XML_Parse(mParser, buf, (int)len, 0);
if (status == XML_STATUS_ERROR)
{
LL_INFOS() << "Unexpected XML parsing error at start" << LL_ENDL;
@ -965,7 +965,7 @@ void LLSDXMLParser::parsePart(const char *buf, llssize len)
// virtual
S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data, S32 max_depth) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
#ifdef XML_PARSER_PERFORMANCE_TESTS
XML_Timer timer( &parseTime );

View File

@ -57,7 +57,7 @@
// U32
LLSD ll_sd_from_U32(const U32 val)
{
std::vector<U8> v;
LLSD::Binary v;
U32 net_order = htonl(val);
v.resize(4);
@ -69,7 +69,7 @@ LLSD ll_sd_from_U32(const U32 val)
U32 ll_U32_from_sd(const LLSD& sd)
{
U32 ret;
std::vector<U8> v = sd.asBinary();
const LLSD::Binary& v = sd.asBinary();
if (v.size() < 4)
{
return 0;
@ -82,7 +82,7 @@ U32 ll_U32_from_sd(const LLSD& sd)
//U64
LLSD ll_sd_from_U64(const U64 val)
{
std::vector<U8> v;
LLSD::Binary v;
U32 high, low;
high = (U32)(val >> 32);
@ -100,7 +100,7 @@ LLSD ll_sd_from_U64(const U64 val)
U64 ll_U64_from_sd(const LLSD& sd)
{
U32 high, low;
std::vector<U8> v = sd.asBinary();
const LLSD::Binary& v = sd.asBinary();
if (v.size() < 8)
{
@ -118,7 +118,7 @@ U64 ll_U64_from_sd(const LLSD& sd)
// IP Address (stored in net order in a U32, so don't need swizzling)
LLSD ll_sd_from_ipaddr(const U32 val)
{
std::vector<U8> v;
LLSD::Binary v;
v.resize(4);
memcpy(&(v[0]), &val, 4); /* Flawfinder: ignore */
@ -129,7 +129,7 @@ LLSD ll_sd_from_ipaddr(const U32 val)
U32 ll_ipaddr_from_sd(const LLSD& sd)
{
U32 ret;
std::vector<U8> v = sd.asBinary();
const LLSD::Binary& v = sd.asBinary();
if (v.size() < 4)
{
return 0;
@ -141,17 +141,17 @@ U32 ll_ipaddr_from_sd(const LLSD& sd)
// Converts an LLSD binary to an LLSD string
LLSD ll_string_from_binary(const LLSD& sd)
{
std::vector<U8> value = sd.asBinary();
const LLSD::Binary& value = sd.asBinary();
std::string str;
str.resize(value.size());
memcpy(&str[0], &value[0], value.size());
memcpy(&str[0], value.data(), value.size());
return str;
}
// Converts an LLSD string to an LLSD binary
LLSD ll_binary_from_string(const LLSD& sd)
{
std::vector<U8> binary_value;
LLSD::Binary binary_value;
std::string string_value = sd.asString();
for (const U8 c : string_value)
@ -220,7 +220,7 @@ bool compare_llsd_with_template(
const LLSD& template_llsd,
LLSD& resultant_llsd)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
if (
llsd_to_test.isUndefined() &&
@ -343,7 +343,7 @@ bool filter_llsd_with_template(
const LLSD & template_llsd,
LLSD & resultant_llsd)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
if (llsd_to_test.isUndefined() && template_llsd.isDefined())
{
@ -539,7 +539,7 @@ class TypeLookup
public:
TypeLookup()
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
{
@ -549,7 +549,7 @@ public:
std::string lookup(LLSD::Type type) const
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
MapType::const_iterator found = mMap.find(type);
if (found != mMap.end())
@ -601,7 +601,7 @@ static std::string match_types(LLSD::Type expect, // prototype.type()
LLSD::Type actual, // type we're checking
const std::string& pfx) // as for llsd_matches
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
// Trivial case: if the actual type is exactly what we expect, we're good.
if (actual == expect)
@ -640,7 +640,7 @@ static std::string match_types(LLSD::Type expect, // prototype.type()
// see docstring in .h file
std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
// An undefined prototype means that any data is valid.
// An undefined slot in an array or map prototype means that any data
@ -774,7 +774,7 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
// We're comparing strict equality of LLSD representation rather than
// performing any conversions. So if the types aren't equal, the LLSD
@ -884,7 +884,7 @@ namespace llsd
LLSD& drill_ref(LLSD& blob, const LLSD& rawPath)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
// Treat rawPath uniformly as an array. If it's not already an array,
// store it as the only entry in one. (But let's say Undefined means an
@ -911,7 +911,7 @@ LLSD& drill_ref(LLSD& blob, const LLSD& rawPath)
// path entry that's bad.
for (LLSD::Integer i = 0; i < path.size(); ++i)
{
LL_PROFILE_ZONE_NUM( i )
LL_PROFILE_ZONE_NUM(i);
const LLSD& key{path[i]};
if (key.isString())
@ -941,7 +941,7 @@ LLSD& drill_ref(LLSD& blob, const LLSD& rawPath)
LLSD drill(const LLSD& blob, const LLSD& path)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
// drill_ref() does exactly what we want. Temporarily cast away
// const-ness and use that.
@ -955,7 +955,7 @@ LLSD drill(const LLSD& blob, const LLSD& path)
// filter may be include to exclude/include keys in a map.
LLSD llsd_clone(LLSD value, LLSD filter)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
LLSD clone;
bool has_filter(filter.isMap());
@ -996,8 +996,7 @@ LLSD llsd_clone(LLSD value, LLSD filter)
case LLSD::TypeBinary:
{
LLSD::Binary bin(value.asBinary().begin(), value.asBinary().end());
clone = LLSD::Binary(bin);
clone = LLSD::Binary(value.asBinary().begin(), value.asBinary().end());
break;
}
default:

View File

@ -59,9 +59,8 @@ private:
// it's safe to log -- which involves querying a different LLSingleton --
// which requires accessing the master list.
typedef std::recursive_mutex mutex_t;
typedef std::unique_lock<mutex_t> lock_t;
mutex_t mMutex;
LL_PROFILE_MUTEX_NAMED(mutex_t, mMutex, "Singleton MasterList");
typedef std::unique_lock<decltype(mMutex)> lock_t;
public:
// Instantiate this to both obtain a reference to MasterList::instance()

View File

@ -35,9 +35,12 @@
#include "lockstatic.h"
#include "llthread.h" // on_main_thread()
#include "llmainthreadtask.h"
#include "llprofiler.h"
#include "llerror.h"
#ifdef LL_WINDOWS
#pragma warning( disable : 4506 ) // no definition for inline function
#pragma warning(push)
#pragma warning(disable : 4506) // no definition for inline function
#endif
class LLSingletonBase: private boost::noncopyable
@ -297,7 +300,7 @@ private:
// Use a recursive_mutex in case of constructor circularity. With a
// non-recursive mutex, that would result in deadlock.
typedef std::recursive_mutex mutex_t;
mutex_t mMutex; // LockStatic looks for mMutex
LL_PROFILE_MUTEX_NAMED(mutex_t, mMutex, "Singleton Data"); // LockStatic looks for mMutex
EInitState mInitState{UNINITIALIZED};
DERIVED_TYPE* mInstance{nullptr};
@ -419,7 +422,7 @@ protected:
// deleteSingleton() to defend against manual deletion. When we moved
// cleanup to deleteSingleton(), we hit crashes due to dangling
// pointers in the MasterList.
LockStatic lk;
LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
lk->mInstance = nullptr;
lk->mInitState = DELETED;
@ -447,7 +450,7 @@ public:
// Hold the lock while we call cleanupSingleton() and the destructor.
// Our destructor also instantiates LockStatic, requiring a recursive
// mutex.
LockStatic lk;
LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
// of course, only cleanup and delete if there's something there
if (lk->mInstance)
{
@ -504,7 +507,7 @@ public:
{ // nested scope for 'lk'
// In case racing threads call getInstance() at the same moment,
// serialize the calls.
LockStatic lk;
LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
switch (lk->mInitState)
{
@ -594,7 +597,7 @@ public:
static bool instanceExists()
{
// defend any access to sData from racing threads
LockStatic lk;
LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
return lk->mInitState == INITIALIZED;
}
@ -604,7 +607,7 @@ public:
static bool wasDeleted()
{
// defend any access to sData from racing threads
LockStatic lk;
LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
return lk->mInitState == DELETED;
}
};
@ -643,7 +646,7 @@ private:
// In case racing threads both call initParamSingleton() at the same
// time, serialize them. One should initialize; the other should see
// mInitState already set.
LockStatic lk;
LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
// For organizational purposes this function shouldn't be called twice
if (lk->mInitState != super::UNINITIALIZED)
{
@ -707,7 +710,7 @@ public:
{
// In case racing threads call getInstance() at the same moment as
// initParamSingleton(), serialize the calls.
LockStatic lk;
LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
switch (lk->mInitState)
{
@ -861,4 +864,8 @@ private:
template <class T>
T* LLSimpleton<T>::sInstance{ nullptr };
#ifdef LL_WINDOWS
#pragma warning(pop)
#endif
#endif

View File

@ -33,10 +33,7 @@
#include <sstream>
#include "llwin32headerslean.h"
#pragma warning (push)
#pragma warning (disable:4091) // a microsoft header has warnings. Very nice.
#include <dbghelp.h>
#pragma warning (pop)
typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
IN ULONG frames_to_skip,

View File

@ -201,11 +201,11 @@ void delete_and_clear_array(T*& ptr)
// foo[2] = "hello";
// const char* bar = get_ptr_in_map(foo, 2); // bar -> "hello"
// const char* baz = get_ptr_in_map(foo, 3); // baz == NULL
template <typename K, typename T>
inline T* get_ptr_in_map(const std::map<K,T*>& inmap, const K& key)
template <typename T>
inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_type const& key)
{
// Typedef here avoids warnings because of new c++ naming rules.
typedef typename std::map<K,T*>::const_iterator map_iter;
typedef typename T::const_iterator map_iter;
map_iter iter = inmap.find(key);
if(iter == inmap.end())
{

View File

@ -250,7 +250,7 @@ LLWString utf16str_to_wstring(const U16* utf16str, size_t len)
while (i < len)
{
llwchar cur_char;
i += utf16chars_to_wchar(chars16+i, &cur_char);
i += (S32)utf16chars_to_wchar(chars16+i, &cur_char);
wout += cur_char;
}
return wout;
@ -972,6 +972,11 @@ void HeapFree_deleter(void* ptr)
} // anonymous namespace
unsigned long windows_get_last_error()
{
return GetLastError();
}
template<>
std::wstring windows_message<std::wstring>(DWORD error)
{
@ -1280,6 +1285,75 @@ namespace LLStringFn
return output;
}
using literals_t = std::map<char, std::string>;
static const literals_t xml_elem_literals =
{
{ '<', "&lt;" },
{ '>', "&gt;" },
{ '&', "&amp;" }
};
static const literals_t xml_attr_literals =
{
{ '"', "&quot;" },
{ '\'', "&apos;" }
};
static void literals_encode(std::string& text, const literals_t& literals)
{
for (const std::pair<char, std::string> it : literals)
{
std::string::size_type pos = 0;
while ((pos = text.find(it.first, pos)) != std::string::npos)
{
text.replace(pos, 1, it.second);
pos += it.second.size();
}
}
}
static void literals_decode(std::string& text, const literals_t& literals)
{
for (const std::pair<char, std::string> it : literals)
{
std::string::size_type pos = 0;
while ((pos = text.find(it.second, pos)) != std::string::npos)
{
text[pos++] = it.first;
text.erase(pos, it.second.size() - 1);
}
}
}
/**
* @brief Replace all characters that are not allowed in XML 1.0
* with corresponding literals: [ < > & ] => [ &lt; &gt; &amp; ]
*/
std::string xml_encode(const std::string& input, bool for_attribute)
{
std::string result(input);
literals_encode(result, xml_elem_literals);
if (for_attribute)
{
literals_encode(result, xml_attr_literals);
}
return result;
}
/**
* @brief Replace some of XML literals that are defined in XML 1.0
* with corresponding characters: [ &lt; &gt; &amp; ] => [ < > & ]
*/
std::string xml_decode(const std::string& input, bool for_attribute)
{
std::string result(input);
literals_decode(result, xml_elem_literals);
if (for_attribute)
{
literals_decode(result, xml_attr_literals);
}
return result;
}
/**
* @brief Replace all control characters (c < 0x20) with replacement in
* string.

View File

@ -50,7 +50,6 @@
#endif
#include <string.h>
#include <boost/scoped_ptr.hpp>
const char LL_UNKNOWN_CHAR = '?';
class LLSD;
@ -845,8 +844,10 @@ template<>
LL_COMMON_API std::wstring windows_message<std::wstring>(unsigned long error);
/// Get Windows message string, implicitly calling GetLastError()
LL_COMMON_API unsigned long windows_get_last_error();
template<typename STRING>
STRING windows_message() { return windows_message<STRING>(GetLastError()); }
STRING windows_message() { return windows_message<STRING>(windows_get_last_error()); }
//@}
@ -902,6 +903,20 @@ namespace LLStringFn
LL_COMMON_API std::string strip_invalid_xml(const std::string& input);
/**
* @brief Replace all characters that are not allowed in XML 1.0
* with corresponding literals: [ < > & ] => [ &lt; &gt; &amp; ]
*/
LL_COMMON_API std::string xml_encode(const std::string& input, bool for_attribute = false);
/**
* @brief Replace some of XML literals that are defined in XML 1.0
* with corresponding characters: [ &lt; &gt; &amp; ] => [ < > & ]
*/
LL_COMMON_API std::string xml_decode(const std::string& input, bool for_attribute = false);
/**
* @brief Replace all control characters (0 <= c < 0x20) with replacement in
* string. This is safe for utf-8

View File

@ -74,6 +74,8 @@ using namespace llsd;
# include <mach/mach_host.h>
# include <mach/task.h>
# include <mach/task_info.h>
# include <sys/types.h>
# include <mach/mach_init.h>
#elif LL_LINUX
# include <errno.h>
# include <sys/utsname.h>
@ -85,6 +87,7 @@ const char MEMINFO_FILE[] = "/proc/meminfo";
#endif
LLCPUInfo gSysCPU;
LLMemoryInfo gSysMemory;
// Don't log memory info any more often than this. It also serves as our
// framerate sample size.
@ -804,34 +807,33 @@ U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const
}
//static
void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb)
void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_mem_kb)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
#if LL_WINDOWS
// Sigh, this shouldn't be a static method, then we wouldn't have to
// reload this data separately from refresh()
LLSD statsMap(loadStatsMap());
avail_physical_mem_kb = (U32Kilobytes)statsMap["Avail Physical KB"].asInteger();
avail_virtual_mem_kb = (U32Kilobytes)statsMap["Avail Virtual KB"].asInteger();
avail_mem_kb = (U32Kilobytes)statsMap["Avail Physical KB"].asInteger();
#elif LL_DARWIN
// mStatsMap is derived from vm_stat, look for (e.g.) "kb free":
// $ vm_stat
// Mach Virtual Memory Statistics: (page size of 4096 bytes)
// Pages free: 462078.
// Pages active: 142010.
// Pages inactive: 220007.
// Pages wired down: 159552.
// "Translation faults": 220825184.
// Pages copy-on-write: 2104153.
// Pages zero filled: 167034876.
// Pages reactivated: 65153.
// Pageins: 2097212.
// Pageouts: 41759.
// Object cache: 841598 hits of 7629869 lookups (11% hit rate)
avail_physical_mem_kb = (U32Kilobytes)-1 ;
avail_virtual_mem_kb = (U32Kilobytes)-1 ;
// use host_statistics64 to get memory info
vm_statistics64_data_t vmstat;
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
mach_port_t host = mach_host_self();
vm_size_t page_size;
host_page_size(host, &page_size);
kern_return_t result = host_statistics64(host, HOST_VM_INFO64, reinterpret_cast<host_info_t>(&vmstat), &count);
if (result == KERN_SUCCESS)
{
avail_mem_kb = U64Bytes((vmstat.free_count + vmstat.inactive_count) * page_size);
}
else
{
avail_mem_kb = (U32Kilobytes)-1;
}
#elif LL_LINUX
// mStatsMap is derived from MEMINFO_FILE:
@ -882,15 +884,14 @@ void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32
// DirectMap4k: 434168 kB
// DirectMap2M: 477184 kB
// (could also run 'free', but easier to read a file than run a program)
avail_physical_mem_kb = (U32Kilobytes)-1 ;
avail_virtual_mem_kb = (U32Kilobytes)-1 ;
LLSD statsMap(loadStatsMap());
avail_mem_kb = (U32Kilobytes)statsMap["MemFree"].asInteger();
#else
//do not know how to collect available memory info for other systems.
//leave it blank here for now.
avail_physical_mem_kb = (U32Kilobytes)-1 ;
avail_virtual_mem_kb = (U32Kilobytes)-1 ;
avail_mem_kb = (U32Kilobytes)-1 ;
#endif
}
@ -936,7 +937,7 @@ LLSD LLMemoryInfo::getStatsMap() const
LLMemoryInfo& LLMemoryInfo::refresh()
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
mStatsMap = loadStatsMap();
LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n";
@ -993,7 +994,7 @@ LLSD LLMemoryInfo::loadStatsMap()
// specifically accepts PROCESS_MEMORY_COUNTERS*, and since this is a
// classic-C API, PROCESS_MEMORY_COUNTERS_EX isn't a subclass. Cast the
// pointer.
GetProcessMemoryInfo(GetCurrentProcess(), PPROCESS_MEMORY_COUNTERS(&pmem), sizeof(pmem));
GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*) &pmem, sizeof(pmem));
stats.add("Page Fault Count", pmem.PageFaultCount);
stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize/div);

View File

@ -134,8 +134,8 @@ public:
static U32Kilobytes getHardwareMemSize(); // Because some Mac linkers won't let us reference extern gSysMemory from a different lib.
#endif
//get the available memory infomation in KiloBytes.
static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb);
//get the available memory in KiloBytes.
static void getAvailableMemoryKB(U32Kilobytes& avail_mem_kb);
// Retrieve a map of memory statistics. The keys of the map are platform-
// dependent. The values are in kilobytes to try to avoid integer overflow.
@ -169,6 +169,7 @@ bool LL_COMMON_API gunzip_file(const std::string& srcfile, const std::string& ds
// gzip srcfile into dstfile. Returns false on error.
bool LL_COMMON_API gzip_file(const std::string& srcfile, const std::string& dstfile);
extern LL_COMMON_API LLMemoryInfo gSysMemory;
extern LL_COMMON_API LLCPUInfo gSysCPU;
#endif // LL_LLSYS_H

View File

@ -274,6 +274,7 @@ void LLThread::shutdown()
mStatus = STOPPED;
return;
}
delete mThreadp;
mThreadp = NULL;
}
@ -304,6 +305,7 @@ void LLThread::start()
{
mThreadp = new std::thread(std::bind(&LLThread::threadRun, this));
mNativeHandle = mThreadp->native_handle();
mThreadp->detach();
}
catch (std::system_error& ex)
{
@ -349,7 +351,7 @@ bool LLThread::runCondition(void)
// Stop thread execution if requested until unpaused.
void LLThread::checkPause()
{
LL_PROFILER_THREAD_BEGIN(mName.c_str())
LL_PROFILER_THREAD_BEGIN(mName.c_str());
mDataLock->lock();
@ -364,7 +366,7 @@ void LLThread::checkPause()
mDataLock->unlock();
LL_PROFILER_THREAD_END(mName.c_str())
LL_PROFILER_THREAD_END(mName.c_str());
}
//============================================================================
@ -385,20 +387,20 @@ void LLThread::setQuitting()
// <FS:Beq> give this a better chance to inline
// LLThread::id_t LLThread::currentID()
// {
// LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
// LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
// return std::this_thread::get_id();
// }
// static
void LLThread::yield()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
std::this_thread::yield();
}
void LLThread::wake()
{
LL_PROFILER_THREAD_BEGIN(mName.c_str())
LL_PROFILER_THREAD_BEGIN(mName.c_str());
mDataLock->lock();
if(!shouldSleep())
@ -407,12 +409,12 @@ void LLThread::wake()
}
mDataLock->unlock();
LL_PROFILER_THREAD_END(mName.c_str())
LL_PROFILER_THREAD_END(mName.c_str());
}
void LLThread::wakeLocked()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
if(!shouldSleep())
{
mRunCondition->signal();
@ -421,13 +423,13 @@ void LLThread::wakeLocked()
void LLThread::lockData()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
mDataLock->lock();
}
void LLThread::unlockData()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
mDataLock->unlock();
}

View File

@ -91,7 +91,7 @@ U32 micro_sleep(U64 us, U32 max_yields)
U32 micro_sleep(U64 us, U32 max_yields)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
#if 0
LARGE_INTEGER ft;
ft.QuadPart = -static_cast<S64>(us * 10); // '-' using relative time
@ -101,7 +101,7 @@ U32 micro_sleep(U64 us, U32 max_yields)
WaitForSingleObject(timer, INFINITE);
CloseHandle(timer);
#else
Sleep(us / 1000);
Sleep((DWORD)(us / 1000));
#endif
return 0;
@ -109,7 +109,7 @@ U32 micro_sleep(U64 us, U32 max_yields)
void ms_sleep(U32 ms)
{
LL_PROFILE_ZONE_SCOPED
LL_PROFILE_ZONE_SCOPED;
micro_sleep(ms * 1000, 0);
}

View File

@ -100,7 +100,7 @@ bool AccumulatorBufferGroup::isCurrent() const
return mCounts.isCurrent();
}
void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
void AccumulatorBufferGroup::append(const AccumulatorBufferGroup& other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mCounts.addSamples(other.mCounts, SEQUENTIAL);
@ -109,7 +109,7 @@ void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
mStackTimers.addSamples(other.mStackTimers, SEQUENTIAL);
}
void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
void AccumulatorBufferGroup::merge(const AccumulatorBufferGroup& other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mCounts.addSamples(other.mCounts, NON_SEQUENTIAL);
@ -140,7 +140,7 @@ void AccumulatorBufferGroup::sync()
F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b)
{
const F64 epsilon = 0.0000001;
constexpr F64 epsilon = 0.0000001;
if (a.getSamplingTime() > epsilon && b.getSamplingTime() > epsilon)
{
@ -170,7 +170,7 @@ F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const Samp
return a.getSumOfSquares();
}
void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type )
void SampleAccumulator::addSamples(const SampleAccumulator& other, EBufferAppendType append_type)
{
if (append_type == NON_SEQUENTIAL)
{
@ -205,7 +205,7 @@ void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppen
}
}
void SampleAccumulator::reset( const SampleAccumulator* other )
void SampleAccumulator::reset(const SampleAccumulator* other)
{
mLastValue = other ? other->mLastValue : NaN;
mHasValue = other ? other->mHasValue : false;
@ -243,7 +243,7 @@ F64 EventAccumulator::mergeSumsOfSquares(const EventAccumulator& a, const EventA
return a.mSumOfSquares;
}
void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendType append_type )
void EventAccumulator::addSamples(const EventAccumulator& other, EBufferAppendType append_type)
{
if (other.mNumSamples)
{
@ -269,12 +269,12 @@ void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendT
}
}
void EventAccumulator::reset( const EventAccumulator* other )
void EventAccumulator::reset(const EventAccumulator* other)
{
mNumSamples = 0;
mSum = 0;
mMin = F32(NaN);
mMax = F32(NaN);
mMin = NaN;
mMax = NaN;
mMean = NaN;
mSumOfSquares = 0;
mLastValue = other ? other->mLastValue : NaN;

Some files were not shown because too many files have changed in this diff Show More