kimjunhan commited on
Commit
340b406
·
verified ·
1 Parent(s): eef2bb1

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. third_party/tracy/.github/FUNDING.yml +1 -0
  2. third_party/tracy/.github/sponsor.png +0 -0
  3. third_party/tracy/.github/workflows/build.yml +78 -0
  4. third_party/tracy/.github/workflows/latex.yml +27 -0
  5. third_party/tracy/.github/workflows/linux.yml +75 -0
  6. third_party/tracy/cmake/CPM.cmake +1269 -0
  7. third_party/tracy/cmake/ECMFindModuleHelpers.cmake +300 -0
  8. third_party/tracy/cmake/FindWaylandScanner.cmake +170 -0
  9. third_party/tracy/cmake/config.cmake +56 -0
  10. third_party/tracy/cmake/server.cmake +39 -0
  11. third_party/tracy/cmake/vendor.cmake +238 -0
  12. third_party/tracy/cmake/version.cmake +24 -0
  13. third_party/tracy/csvexport/CMakeLists.txt +28 -0
  14. third_party/tracy/csvexport/src/csvexport.cpp +353 -0
  15. third_party/tracy/examples/OpenCLVectorAdd/CMakeLists.txt +17 -0
  16. third_party/tracy/examples/OpenCLVectorAdd/OpenCLVectorAdd.cpp +220 -0
  17. third_party/tracy/examples/ToyPathTracer/.gitignore +1 -0
  18. third_party/tracy/examples/ToyPathTracer/README +4 -0
  19. third_party/tracy/examples/ToyPathTracer/Source/Config.h +33 -0
  20. third_party/tracy/examples/ToyPathTracer/Source/MathSimd.h +192 -0
  21. third_party/tracy/examples/ToyPathTracer/Source/Maths.cpp +203 -0
  22. third_party/tracy/examples/ToyPathTracer/Source/Maths.h +436 -0
  23. third_party/tracy/examples/ToyPathTracer/Source/Test.cpp +392 -0
  24. third_party/tracy/examples/ToyPathTracer/Source/Test.h +17 -0
  25. third_party/tracy/examples/ToyPathTracer/Source/enkiTS/Atomics.h +79 -0
  26. third_party/tracy/examples/ToyPathTracer/Source/enkiTS/LockLessMultiReadPipe.h +240 -0
  27. third_party/tracy/examples/ToyPathTracer/Source/enkiTS/TaskScheduler.cpp +437 -0
  28. third_party/tracy/examples/ToyPathTracer/Source/enkiTS/TaskScheduler.h +177 -0
  29. third_party/tracy/examples/ToyPathTracer/Source/enkiTS/TaskScheduler_c.cpp +122 -0
  30. third_party/tracy/examples/ToyPathTracer/Source/enkiTS/TaskScheduler_c.h +104 -0
  31. third_party/tracy/examples/ToyPathTracer/Source/enkiTS/Threads.h +210 -0
  32. third_party/tracy/examples/ToyPathTracer/Windows/ComputeShader.hlsl +395 -0
  33. third_party/tracy/examples/ToyPathTracer/Windows/PixelShader.hlsl +15 -0
  34. third_party/tracy/examples/ToyPathTracer/Windows/TestCpu.sln +31 -0
  35. third_party/tracy/examples/ToyPathTracer/Windows/TestCpu.vcxproj +245 -0
  36. third_party/tracy/examples/ToyPathTracer/Windows/TestCpu.vcxproj.filters +67 -0
  37. third_party/tracy/examples/ToyPathTracer/Windows/TestWin.cpp +567 -0
  38. third_party/tracy/examples/ToyPathTracer/Windows/VertexShader.hlsl +13 -0
  39. third_party/tracy/examples/ToyPathTracer/license.md +24 -0
  40. third_party/tracy/examples/fibers.cpp +30 -0
  41. third_party/tracy/public/TracyClient.cpp +61 -0
  42. third_party/tracy/public/libbacktrace/alloc.cpp +174 -0
  43. third_party/tracy/public/libbacktrace/dwarf.cpp +0 -0
  44. third_party/tracy/public/libbacktrace/elf.cpp +0 -0
  45. third_party/tracy/public/libbacktrace/mmapio.cpp +115 -0
  46. third_party/tracy/public/libbacktrace/sort.cpp +113 -0
  47. third_party/tracy/public/libbacktrace/state.cpp +76 -0
  48. third_party/tracy/server/TracyCharUtil.hpp +76 -0
  49. third_party/tracy/server/TracyEvent.hpp +850 -0
  50. third_party/tracy/server/TracyFileHeader.hpp +22 -0
third_party/tracy/.github/FUNDING.yml ADDED
@@ -0,0 +1 @@
 
 
1
+ github: wolfpld
third_party/tracy/.github/sponsor.png ADDED
third_party/tracy/.github/workflows/build.yml ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: build
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ build:
11
+ strategy:
12
+ matrix:
13
+ os: [ windows-latest, macos-latest ]
14
+
15
+ runs-on: ${{ matrix.os }}
16
+ continue-on-error: true
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - if: startsWith(matrix.os, 'windows')
20
+ uses: microsoft/setup-msbuild@v2
21
+ - if: startsWith(matrix.os, 'windows')
22
+ uses: actions/setup-python@v2
23
+ with:
24
+ python-version: '3.x'
25
+ - if: startsWith(matrix.os, 'windows')
26
+ run: pip install meson ninja
27
+ - if: startsWith(matrix.os, 'macos')
28
+ name: Install macos dependencies
29
+ run: brew install pkg-config glfw meson
30
+ - name: Profiler GUI
31
+ run: |
32
+ cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release
33
+ cmake --build profiler/build --parallel --config Release
34
+ - name: Update utility
35
+ run: |
36
+ cmake -B update/build -S update -DCMAKE_BUILD_TYPE=Release
37
+ cmake --build update/build --parallel --config Release
38
+ - name: Capture utility
39
+ run: |
40
+ cmake -B capture/build -S capture -DCMAKE_BUILD_TYPE=Release
41
+ cmake --build capture/build --parallel --config Release
42
+ - name: Csvexport utility
43
+ run: |
44
+ cmake -B csvexport/build -S csvexport -DCMAKE_BUILD_TYPE=Release
45
+ cmake --build csvexport/build --parallel --config Release
46
+ - name: Import utilities
47
+ run: |
48
+ cmake -B import/build -S import -DCMAKE_BUILD_TYPE=Release
49
+ cmake --build import/build --parallel --config Release
50
+ - if: ${{ !startsWith(matrix.os, 'windows') }}
51
+ name: Library
52
+ run: meson setup -Dprefix=$GITHUB_WORKSPACE/bin/lib build && meson compile -C build && meson install -C build
53
+ - if: ${{ !startsWith(matrix.os, 'windows') }}
54
+ name: Find Artifacts
55
+ id: find_artifacts
56
+ run: |
57
+ mkdir -p bin
58
+ cp profiler/build/tracy-profiler bin
59
+ cp update/build/tracy-update bin
60
+ cp capture/build/tracy-capture bin
61
+ cp csvexport/build/tracy-csvexport bin
62
+ cp import/build/tracy-import-chrome bin
63
+ cp import/build/tracy-import-fuchsia bin
64
+ - if: startsWith(matrix.os, 'windows')
65
+ name: Find Artifacts
66
+ id: find_artifacts_windows
67
+ run: |
68
+ mkdir bin
69
+ copy profiler\build\Release\tracy-profiler.exe bin
70
+ copy update\build\Release\tracy-update.exe bin
71
+ copy capture\build\Release\tracy-capture.exe bin
72
+ copy csvexport\build\Release\tracy-csvexport.exe bin
73
+ copy import\build\Release\tracy-import-chrome.exe bin
74
+ copy import\build\Release\tracy-import-fuchsia.exe bin
75
+ - uses: actions/upload-artifact@v4
76
+ with:
77
+ name: ${{ matrix.os }}
78
+ path: bin
third_party/tracy/.github/workflows/latex.yml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Manual
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ build:
11
+
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - name: Fix stupidity
17
+ run: |
18
+ cp LICENSE LICENSE.
19
+ - name: Compile LaTeX
20
+ uses: xu-cheng/latex-action@v3
21
+ with:
22
+ working_directory: manual
23
+ root_file: tracy.tex
24
+ - uses: actions/upload-artifact@v4
25
+ with:
26
+ name: manual
27
+ path: manual/tracy.pdf
third_party/tracy/.github/workflows/linux.yml ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: linux
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+ container: archlinux:base-devel
13
+ steps:
14
+ - name: Install dependencies
15
+ run: pacman -Syu --noconfirm && pacman -S --noconfirm --needed freetype2 tbb debuginfod wayland dbus libxkbcommon libglvnd meson cmake git wayland-protocols nodejs
16
+ - uses: actions/checkout@v4
17
+ - name: Profiler GUI
18
+ run: |
19
+ cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release
20
+ cmake --build profiler/build --parallel
21
+ - name: Update utility
22
+ run: |
23
+ cmake -B update/build -S update -DCMAKE_BUILD_TYPE=Release
24
+ cmake --build update/build --parallel
25
+ - name: Capture utility
26
+ run: |
27
+ cmake -B capture/build -S capture -DCMAKE_BUILD_TYPE=Release
28
+ cmake --build capture/build --parallel
29
+ - name: Csvexport utility
30
+ run: |
31
+ cmake -B csvexport/build -S csvexport -DCMAKE_BUILD_TYPE=Release
32
+ cmake --build csvexport/build --parallel
33
+ - name: Import utilities
34
+ run: |
35
+ cmake -B import/build -S import -DCMAKE_BUILD_TYPE=Release
36
+ cmake --build import/build --parallel
37
+ - name: Library
38
+ run: meson setup -Dprefix=$GITHUB_WORKSPACE/bin/lib build && meson compile -C build && meson install -C build
39
+ - name: Test application
40
+ run: |
41
+ # test compilation with different flags
42
+ # we clean the build folder to reset cached variables between runs
43
+ cmake -B test/build -S test -DCMAKE_BUILD_TYPE=Release
44
+ cmake --build test/build --parallel
45
+ rm -rf test/build
46
+
47
+ # same with TRACY_ON_DEMAND
48
+ cmake -B test/build -S test -DCMAKE_BUILD_TYPE=Release -DTRACY_ON_DEMAND=ON .
49
+ cmake --build test/build --parallel
50
+ rm -rf test/build
51
+
52
+ # same with TRACY_DELAYED_INIT TRACY_MANUAL_LIFETIME
53
+ cmake -B test/build -S test -DCMAKE_BUILD_TYPE=Release -DTRACY_DELAYED_INIT=ON -DTRACY_MANUAL_LIFETIME=ON .
54
+ cmake --build test/build --parallel
55
+ rm -rf test/build
56
+
57
+ # same with TRACY_DEMANGLE
58
+ cmake -B test/build -S test -DCMAKE_BUILD_TYPE=Release -DTRACY_DEMANGLE=ON .
59
+ cmake --build test/build --parallel
60
+ rm -rf test/build
61
+ - name: Find Artifacts
62
+ id: find_artifacts
63
+ run: |
64
+ mkdir -p bin
65
+ cp profiler/build/tracy-profiler bin
66
+ cp update/build/tracy-update bin
67
+ cp capture/build/tracy-capture bin
68
+ cp csvexport/build/tracy-csvexport bin
69
+ cp import/build/tracy-import-chrome bin
70
+ cp import/build/tracy-import-fuchsia bin
71
+ strip bin/tracy-*
72
+ - uses: actions/upload-artifact@v4
73
+ with:
74
+ name: arch-linux
75
+ path: bin
third_party/tracy/cmake/CPM.cmake ADDED
@@ -0,0 +1,1269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CPM.cmake - CMake's missing package manager
2
+ # ===========================================
3
+ # See https://github.com/cpm-cmake/CPM.cmake for usage and update instructions.
4
+ #
5
+ # MIT License
6
+ # -----------
7
+ #[[
8
+ Copyright (c) 2019-2023 Lars Melchior and contributors
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ ]]
28
+
29
+ cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
30
+
31
+ # Initialize logging prefix
32
+ if(NOT CPM_INDENT)
33
+ set(CPM_INDENT
34
+ "CPM:"
35
+ CACHE INTERNAL ""
36
+ )
37
+ endif()
38
+
39
+ if(NOT COMMAND cpm_message)
40
+ function(cpm_message)
41
+ message(${ARGV})
42
+ endfunction()
43
+ endif()
44
+
45
+ set(CURRENT_CPM_VERSION 0.40.2)
46
+
47
+ get_filename_component(CPM_CURRENT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" REALPATH)
48
+ if(CPM_DIRECTORY)
49
+ if(NOT CPM_DIRECTORY STREQUAL CPM_CURRENT_DIRECTORY)
50
+ if(CPM_VERSION VERSION_LESS CURRENT_CPM_VERSION)
51
+ message(
52
+ AUTHOR_WARNING
53
+ "${CPM_INDENT} \
54
+ A dependency is using a more recent CPM version (${CURRENT_CPM_VERSION}) than the current project (${CPM_VERSION}). \
55
+ It is recommended to upgrade CPM to the most recent version. \
56
+ See https://github.com/cpm-cmake/CPM.cmake for more information."
57
+ )
58
+ endif()
59
+ if(${CMAKE_VERSION} VERSION_LESS "3.17.0")
60
+ include(FetchContent)
61
+ endif()
62
+ return()
63
+ endif()
64
+
65
+ get_property(
66
+ CPM_INITIALIZED GLOBAL ""
67
+ PROPERTY CPM_INITIALIZED
68
+ SET
69
+ )
70
+ if(CPM_INITIALIZED)
71
+ return()
72
+ endif()
73
+ endif()
74
+
75
+ if(CURRENT_CPM_VERSION MATCHES "development-version")
76
+ message(
77
+ WARNING "${CPM_INDENT} Your project is using an unstable development version of CPM.cmake. \
78
+ Please update to a recent release if possible. \
79
+ See https://github.com/cpm-cmake/CPM.cmake for details."
80
+ )
81
+ endif()
82
+
83
+ set_property(GLOBAL PROPERTY CPM_INITIALIZED true)
84
+
85
+ macro(cpm_set_policies)
86
+ # the policy allows us to change options without caching
87
+ cmake_policy(SET CMP0077 NEW)
88
+ set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
89
+
90
+ # the policy allows us to change set(CACHE) without caching
91
+ if(POLICY CMP0126)
92
+ cmake_policy(SET CMP0126 NEW)
93
+ set(CMAKE_POLICY_DEFAULT_CMP0126 NEW)
94
+ endif()
95
+
96
+ # The policy uses the download time for timestamp, instead of the timestamp in the archive. This
97
+ # allows for proper rebuilds when a projects url changes
98
+ if(POLICY CMP0135)
99
+ cmake_policy(SET CMP0135 NEW)
100
+ set(CMAKE_POLICY_DEFAULT_CMP0135 NEW)
101
+ endif()
102
+
103
+ # treat relative git repository paths as being relative to the parent project's remote
104
+ if(POLICY CMP0150)
105
+ cmake_policy(SET CMP0150 NEW)
106
+ set(CMAKE_POLICY_DEFAULT_CMP0150 NEW)
107
+ endif()
108
+ endmacro()
109
+ cpm_set_policies()
110
+
111
+ option(CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies"
112
+ $ENV{CPM_USE_LOCAL_PACKAGES}
113
+ )
114
+ option(CPM_LOCAL_PACKAGES_ONLY "Only use `find_package` to get dependencies"
115
+ $ENV{CPM_LOCAL_PACKAGES_ONLY}
116
+ )
117
+ option(CPM_DOWNLOAD_ALL "Always download dependencies from source" $ENV{CPM_DOWNLOAD_ALL})
118
+ option(CPM_DONT_UPDATE_MODULE_PATH "Don't update the module path to allow using find_package"
119
+ $ENV{CPM_DONT_UPDATE_MODULE_PATH}
120
+ )
121
+ option(CPM_DONT_CREATE_PACKAGE_LOCK "Don't create a package lock file in the binary path"
122
+ $ENV{CPM_DONT_CREATE_PACKAGE_LOCK}
123
+ )
124
+ option(CPM_INCLUDE_ALL_IN_PACKAGE_LOCK
125
+ "Add all packages added through CPM.cmake to the package lock"
126
+ $ENV{CPM_INCLUDE_ALL_IN_PACKAGE_LOCK}
127
+ )
128
+ option(CPM_USE_NAMED_CACHE_DIRECTORIES
129
+ "Use additional directory of package name in cache on the most nested level."
130
+ $ENV{CPM_USE_NAMED_CACHE_DIRECTORIES}
131
+ )
132
+
133
+ set(CPM_VERSION
134
+ ${CURRENT_CPM_VERSION}
135
+ CACHE INTERNAL ""
136
+ )
137
+ set(CPM_DIRECTORY
138
+ ${CPM_CURRENT_DIRECTORY}
139
+ CACHE INTERNAL ""
140
+ )
141
+ set(CPM_FILE
142
+ ${CMAKE_CURRENT_LIST_FILE}
143
+ CACHE INTERNAL ""
144
+ )
145
+ set(CPM_PACKAGES
146
+ ""
147
+ CACHE INTERNAL ""
148
+ )
149
+ set(CPM_DRY_RUN
150
+ OFF
151
+ CACHE INTERNAL "Don't download or configure dependencies (for testing)"
152
+ )
153
+
154
+ if(DEFINED ENV{CPM_SOURCE_CACHE})
155
+ set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE})
156
+ else()
157
+ set(CPM_SOURCE_CACHE_DEFAULT OFF)
158
+ endif()
159
+
160
+ set(CPM_SOURCE_CACHE
161
+ ${CPM_SOURCE_CACHE_DEFAULT}
162
+ CACHE PATH "Directory to download CPM dependencies"
163
+ )
164
+
165
+ if(NOT CPM_DONT_UPDATE_MODULE_PATH)
166
+ set(CPM_MODULE_PATH
167
+ "${CMAKE_BINARY_DIR}/CPM_modules"
168
+ CACHE INTERNAL ""
169
+ )
170
+ # remove old modules
171
+ file(REMOVE_RECURSE ${CPM_MODULE_PATH})
172
+ file(MAKE_DIRECTORY ${CPM_MODULE_PATH})
173
+ # locally added CPM modules should override global packages
174
+ set(CMAKE_MODULE_PATH "${CPM_MODULE_PATH};${CMAKE_MODULE_PATH}")
175
+ endif()
176
+
177
+ if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
178
+ set(CPM_PACKAGE_LOCK_FILE
179
+ "${CMAKE_BINARY_DIR}/cpm-package-lock.cmake"
180
+ CACHE INTERNAL ""
181
+ )
182
+ file(WRITE ${CPM_PACKAGE_LOCK_FILE}
183
+ "# CPM Package Lock\n# This file should be committed to version control\n\n"
184
+ )
185
+ endif()
186
+
187
+ include(FetchContent)
188
+
189
+ # Try to infer package name from git repository uri (path or url)
190
+ function(cpm_package_name_from_git_uri URI RESULT)
191
+ if("${URI}" MATCHES "([^/:]+)/?.git/?$")
192
+ set(${RESULT}
193
+ ${CMAKE_MATCH_1}
194
+ PARENT_SCOPE
195
+ )
196
+ else()
197
+ unset(${RESULT} PARENT_SCOPE)
198
+ endif()
199
+ endfunction()
200
+
201
+ # Try to infer package name and version from a url
202
+ function(cpm_package_name_and_ver_from_url url outName outVer)
203
+ if(url MATCHES "[/\\?]([a-zA-Z0-9_\\.-]+)\\.(tar|tar\\.gz|tar\\.bz2|zip|ZIP)(\\?|/|$)")
204
+ # We matched an archive
205
+ set(filename "${CMAKE_MATCH_1}")
206
+
207
+ if(filename MATCHES "([a-zA-Z0-9_\\.-]+)[_-]v?(([0-9]+\\.)*[0-9]+[a-zA-Z0-9]*)")
208
+ # We matched <name>-<version> (ie foo-1.2.3)
209
+ set(${outName}
210
+ "${CMAKE_MATCH_1}"
211
+ PARENT_SCOPE
212
+ )
213
+ set(${outVer}
214
+ "${CMAKE_MATCH_2}"
215
+ PARENT_SCOPE
216
+ )
217
+ elseif(filename MATCHES "(([0-9]+\\.)+[0-9]+[a-zA-Z0-9]*)")
218
+ # We couldn't find a name, but we found a version
219
+ #
220
+ # In many cases (which we don't handle here) the url would look something like
221
+ # `irrelevant/ACTUAL_PACKAGE_NAME/irrelevant/1.2.3.zip`. In such a case we can't possibly
222
+ # distinguish the package name from the irrelevant bits. Moreover if we try to match the
223
+ # package name from the filename, we'd get bogus at best.
224
+ unset(${outName} PARENT_SCOPE)
225
+ set(${outVer}
226
+ "${CMAKE_MATCH_1}"
227
+ PARENT_SCOPE
228
+ )
229
+ else()
230
+ # Boldly assume that the file name is the package name.
231
+ #
232
+ # Yes, something like `irrelevant/ACTUAL_NAME/irrelevant/download.zip` will ruin our day, but
233
+ # such cases should be quite rare. No popular service does this... we think.
234
+ set(${outName}
235
+ "${filename}"
236
+ PARENT_SCOPE
237
+ )
238
+ unset(${outVer} PARENT_SCOPE)
239
+ endif()
240
+ else()
241
+ # No ideas yet what to do with non-archives
242
+ unset(${outName} PARENT_SCOPE)
243
+ unset(${outVer} PARENT_SCOPE)
244
+ endif()
245
+ endfunction()
246
+
247
+ function(cpm_find_package NAME VERSION)
248
+ string(REPLACE " " ";" EXTRA_ARGS "${ARGN}")
249
+ find_package(${NAME} ${VERSION} ${EXTRA_ARGS} QUIET)
250
+ if(${CPM_ARGS_NAME}_FOUND)
251
+ if(DEFINED ${CPM_ARGS_NAME}_VERSION)
252
+ set(VERSION ${${CPM_ARGS_NAME}_VERSION})
253
+ endif()
254
+ cpm_message(STATUS "${CPM_INDENT} Using local package ${CPM_ARGS_NAME}@${VERSION}")
255
+ CPMRegisterPackage(${CPM_ARGS_NAME} "${VERSION}")
256
+ set(CPM_PACKAGE_FOUND
257
+ YES
258
+ PARENT_SCOPE
259
+ )
260
+ else()
261
+ set(CPM_PACKAGE_FOUND
262
+ NO
263
+ PARENT_SCOPE
264
+ )
265
+ endif()
266
+ endfunction()
267
+
268
+ # Create a custom FindXXX.cmake module for a CPM package This prevents `find_package(NAME)` from
269
+ # finding the system library
270
+ function(cpm_create_module_file Name)
271
+ if(NOT CPM_DONT_UPDATE_MODULE_PATH)
272
+ # erase any previous modules
273
+ file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake
274
+ "include(\"${CPM_FILE}\")\n${ARGN}\nset(${Name}_FOUND TRUE)"
275
+ )
276
+ endif()
277
+ endfunction()
278
+
279
+ # Find a package locally or fallback to CPMAddPackage
280
+ function(CPMFindPackage)
281
+ set(oneValueArgs NAME VERSION GIT_TAG FIND_PACKAGE_ARGUMENTS)
282
+
283
+ cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "" ${ARGN})
284
+
285
+ if(NOT DEFINED CPM_ARGS_VERSION)
286
+ if(DEFINED CPM_ARGS_GIT_TAG)
287
+ cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
288
+ endif()
289
+ endif()
290
+
291
+ set(downloadPackage ${CPM_DOWNLOAD_ALL})
292
+ if(DEFINED CPM_DOWNLOAD_${CPM_ARGS_NAME})
293
+ set(downloadPackage ${CPM_DOWNLOAD_${CPM_ARGS_NAME}})
294
+ elseif(DEFINED ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}})
295
+ set(downloadPackage $ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}})
296
+ endif()
297
+ if(downloadPackage)
298
+ CPMAddPackage(${ARGN})
299
+ cpm_export_variables(${CPM_ARGS_NAME})
300
+ return()
301
+ endif()
302
+
303
+ cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
304
+
305
+ if(NOT CPM_PACKAGE_FOUND)
306
+ CPMAddPackage(${ARGN})
307
+ cpm_export_variables(${CPM_ARGS_NAME})
308
+ endif()
309
+
310
+ endfunction()
311
+
312
+ # checks if a package has been added before
313
+ function(cpm_check_if_package_already_added CPM_ARGS_NAME CPM_ARGS_VERSION)
314
+ if("${CPM_ARGS_NAME}" IN_LIST CPM_PACKAGES)
315
+ CPMGetPackageVersion(${CPM_ARGS_NAME} CPM_PACKAGE_VERSION)
316
+ if("${CPM_PACKAGE_VERSION}" VERSION_LESS "${CPM_ARGS_VERSION}")
317
+ message(
318
+ WARNING
319
+ "${CPM_INDENT} Requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION})."
320
+ )
321
+ endif()
322
+ cpm_get_fetch_properties(${CPM_ARGS_NAME})
323
+ set(${CPM_ARGS_NAME}_ADDED NO)
324
+ set(CPM_PACKAGE_ALREADY_ADDED
325
+ YES
326
+ PARENT_SCOPE
327
+ )
328
+ cpm_export_variables(${CPM_ARGS_NAME})
329
+ else()
330
+ set(CPM_PACKAGE_ALREADY_ADDED
331
+ NO
332
+ PARENT_SCOPE
333
+ )
334
+ endif()
335
+ endfunction()
336
+
337
+ # Parse the argument of CPMAddPackage in case a single one was provided and convert it to a list of
338
+ # arguments which can then be parsed idiomatically. For example gh:foo/bar@1.2.3 will be converted
339
+ # to: GITHUB_REPOSITORY;foo/bar;VERSION;1.2.3
340
+ function(cpm_parse_add_package_single_arg arg outArgs)
341
+ # Look for a scheme
342
+ if("${arg}" MATCHES "^([a-zA-Z]+):(.+)$")
343
+ string(TOLOWER "${CMAKE_MATCH_1}" scheme)
344
+ set(uri "${CMAKE_MATCH_2}")
345
+
346
+ # Check for CPM-specific schemes
347
+ if(scheme STREQUAL "gh")
348
+ set(out "GITHUB_REPOSITORY;${uri}")
349
+ set(packageType "git")
350
+ elseif(scheme STREQUAL "gl")
351
+ set(out "GITLAB_REPOSITORY;${uri}")
352
+ set(packageType "git")
353
+ elseif(scheme STREQUAL "bb")
354
+ set(out "BITBUCKET_REPOSITORY;${uri}")
355
+ set(packageType "git")
356
+ # A CPM-specific scheme was not found. Looks like this is a generic URL so try to determine
357
+ # type
358
+ elseif(arg MATCHES ".git/?(@|#|$)")
359
+ set(out "GIT_REPOSITORY;${arg}")
360
+ set(packageType "git")
361
+ else()
362
+ # Fall back to a URL
363
+ set(out "URL;${arg}")
364
+ set(packageType "archive")
365
+
366
+ # We could also check for SVN since FetchContent supports it, but SVN is so rare these days.
367
+ # We just won't bother with the additional complexity it will induce in this function. SVN is
368
+ # done by multi-arg
369
+ endif()
370
+ else()
371
+ if(arg MATCHES ".git/?(@|#|$)")
372
+ set(out "GIT_REPOSITORY;${arg}")
373
+ set(packageType "git")
374
+ else()
375
+ # Give up
376
+ message(FATAL_ERROR "${CPM_INDENT} Can't determine package type of '${arg}'")
377
+ endif()
378
+ endif()
379
+
380
+ # For all packages we interpret @... as version. Only replace the last occurrence. Thus URIs
381
+ # containing '@' can be used
382
+ string(REGEX REPLACE "@([^@]+)$" ";VERSION;\\1" out "${out}")
383
+
384
+ # Parse the rest according to package type
385
+ if(packageType STREQUAL "git")
386
+ # For git repos we interpret #... as a tag or branch or commit hash
387
+ string(REGEX REPLACE "#([^#]+)$" ";GIT_TAG;\\1" out "${out}")
388
+ elseif(packageType STREQUAL "archive")
389
+ # For archives we interpret #... as a URL hash.
390
+ string(REGEX REPLACE "#([^#]+)$" ";URL_HASH;\\1" out "${out}")
391
+ # We don't try to parse the version if it's not provided explicitly. cpm_get_version_from_url
392
+ # should do this at a later point
393
+ else()
394
+ # We should never get here. This is an assertion and hitting it means there's a problem with the
395
+ # code above. A packageType was set, but not handled by this if-else.
396
+ message(FATAL_ERROR "${CPM_INDENT} Unsupported package type '${packageType}' of '${arg}'")
397
+ endif()
398
+
399
+ set(${outArgs}
400
+ ${out}
401
+ PARENT_SCOPE
402
+ )
403
+ endfunction()
404
+
405
+ # Check that the working directory for a git repo is clean
406
+ function(cpm_check_git_working_dir_is_clean repoPath gitTag isClean)
407
+
408
+ find_package(Git REQUIRED)
409
+
410
+ if(NOT GIT_EXECUTABLE)
411
+ # No git executable, assume directory is clean
412
+ set(${isClean}
413
+ TRUE
414
+ PARENT_SCOPE
415
+ )
416
+ return()
417
+ endif()
418
+
419
+ # check for uncommitted changes
420
+ execute_process(
421
+ COMMAND ${GIT_EXECUTABLE} status --porcelain
422
+ RESULT_VARIABLE resultGitStatus
423
+ OUTPUT_VARIABLE repoStatus
424
+ OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET
425
+ WORKING_DIRECTORY ${repoPath}
426
+ )
427
+ if(resultGitStatus)
428
+ # not supposed to happen, assume clean anyway
429
+ message(WARNING "${CPM_INDENT} Calling git status on folder ${repoPath} failed")
430
+ set(${isClean}
431
+ TRUE
432
+ PARENT_SCOPE
433
+ )
434
+ return()
435
+ endif()
436
+
437
+ if(NOT "${repoStatus}" STREQUAL "")
438
+ set(${isClean}
439
+ FALSE
440
+ PARENT_SCOPE
441
+ )
442
+ return()
443
+ endif()
444
+
445
+ # check for committed changes
446
+ execute_process(
447
+ COMMAND ${GIT_EXECUTABLE} diff -s --exit-code ${gitTag}
448
+ RESULT_VARIABLE resultGitDiff
449
+ OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_QUIET
450
+ WORKING_DIRECTORY ${repoPath}
451
+ )
452
+
453
+ if(${resultGitDiff} EQUAL 0)
454
+ set(${isClean}
455
+ TRUE
456
+ PARENT_SCOPE
457
+ )
458
+ else()
459
+ set(${isClean}
460
+ FALSE
461
+ PARENT_SCOPE
462
+ )
463
+ endif()
464
+
465
+ endfunction()
466
+
467
+ # Add PATCH_COMMAND to CPM_ARGS_UNPARSED_ARGUMENTS. This method consumes a list of files in ARGN
468
+ # then generates a `PATCH_COMMAND` appropriate for `ExternalProject_Add()`. This command is appended
469
+ # to the parent scope's `CPM_ARGS_UNPARSED_ARGUMENTS`.
470
+ function(cpm_add_patches)
471
+ # Return if no patch files are supplied.
472
+ if(NOT ARGN)
473
+ return()
474
+ endif()
475
+
476
+ # Find the patch program.
477
+ find_program(PATCH_EXECUTABLE patch)
478
+ if(WIN32 AND NOT PATCH_EXECUTABLE)
479
+ # The Windows git executable is distributed with patch.exe. Find the path to the executable, if
480
+ # it exists, then search `../usr/bin` and `../../usr/bin` for patch.exe.
481
+ find_package(Git QUIET)
482
+ if(GIT_EXECUTABLE)
483
+ get_filename_component(extra_search_path ${GIT_EXECUTABLE} DIRECTORY)
484
+ get_filename_component(extra_search_path_1up ${extra_search_path} DIRECTORY)
485
+ get_filename_component(extra_search_path_2up ${extra_search_path_1up} DIRECTORY)
486
+ find_program(
487
+ PATCH_EXECUTABLE patch HINTS "${extra_search_path_1up}/usr/bin"
488
+ "${extra_search_path_2up}/usr/bin"
489
+ )
490
+ endif()
491
+ endif()
492
+ if(NOT PATCH_EXECUTABLE)
493
+ message(FATAL_ERROR "Couldn't find `patch` executable to use with PATCHES keyword.")
494
+ endif()
495
+
496
+ # Create a temporary
497
+ set(temp_list ${CPM_ARGS_UNPARSED_ARGUMENTS})
498
+
499
+ # Ensure each file exists (or error out) and add it to the list.
500
+ set(first_item True)
501
+ foreach(PATCH_FILE ${ARGN})
502
+ # Make sure the patch file exists, if we can't find it, try again in the current directory.
503
+ if(NOT EXISTS "${PATCH_FILE}")
504
+ if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${PATCH_FILE}")
505
+ message(FATAL_ERROR "Couldn't find patch file: '${PATCH_FILE}'")
506
+ endif()
507
+ set(PATCH_FILE "${CMAKE_CURRENT_LIST_DIR}/${PATCH_FILE}")
508
+ endif()
509
+
510
+ # Convert to absolute path for use with patch file command.
511
+ get_filename_component(PATCH_FILE "${PATCH_FILE}" ABSOLUTE)
512
+
513
+ # The first patch entry must be preceded by "PATCH_COMMAND" while the following items are
514
+ # preceded by "&&".
515
+ if(first_item)
516
+ set(first_item False)
517
+ list(APPEND temp_list "PATCH_COMMAND")
518
+ else()
519
+ list(APPEND temp_list "&&")
520
+ endif()
521
+ # Add the patch command to the list
522
+ list(APPEND temp_list "${PATCH_EXECUTABLE}" "-p1" "<" "${PATCH_FILE}")
523
+ endforeach()
524
+
525
+ # Move temp out into parent scope.
526
+ set(CPM_ARGS_UNPARSED_ARGUMENTS
527
+ ${temp_list}
528
+ PARENT_SCOPE
529
+ )
530
+
531
+ endfunction()
532
+
533
+ # method to overwrite internal FetchContent properties, to allow using CPM.cmake to overload
534
+ # FetchContent calls. As these are internal cmake properties, this method should be used carefully
535
+ # and may need modification in future CMake versions. Source:
536
+ # https://github.com/Kitware/CMake/blob/dc3d0b5a0a7d26d43d6cfeb511e224533b5d188f/Modules/FetchContent.cmake#L1152
537
+ function(cpm_override_fetchcontent contentName)
538
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "SOURCE_DIR;BINARY_DIR" "")
539
+ if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "")
540
+ message(FATAL_ERROR "${CPM_INDENT} Unsupported arguments: ${arg_UNPARSED_ARGUMENTS}")
541
+ endif()
542
+
543
+ string(TOLOWER ${contentName} contentNameLower)
544
+ set(prefix "_FetchContent_${contentNameLower}")
545
+
546
+ set(propertyName "${prefix}_sourceDir")
547
+ define_property(
548
+ GLOBAL
549
+ PROPERTY ${propertyName}
550
+ BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
551
+ FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
552
+ )
553
+ set_property(GLOBAL PROPERTY ${propertyName} "${arg_SOURCE_DIR}")
554
+
555
+ set(propertyName "${prefix}_binaryDir")
556
+ define_property(
557
+ GLOBAL
558
+ PROPERTY ${propertyName}
559
+ BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
560
+ FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
561
+ )
562
+ set_property(GLOBAL PROPERTY ${propertyName} "${arg_BINARY_DIR}")
563
+
564
+ set(propertyName "${prefix}_populated")
565
+ define_property(
566
+ GLOBAL
567
+ PROPERTY ${propertyName}
568
+ BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
569
+ FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
570
+ )
571
+ set_property(GLOBAL PROPERTY ${propertyName} TRUE)
572
+ endfunction()
573
+
574
+ # Download and add a package from source
575
+ function(CPMAddPackage)
576
+ cpm_set_policies()
577
+
578
+ list(LENGTH ARGN argnLength)
579
+ if(argnLength EQUAL 1)
580
+ cpm_parse_add_package_single_arg("${ARGN}" ARGN)
581
+
582
+ # The shorthand syntax implies EXCLUDE_FROM_ALL and SYSTEM
583
+ set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;")
584
+ endif()
585
+
586
+ set(oneValueArgs
587
+ NAME
588
+ FORCE
589
+ VERSION
590
+ GIT_TAG
591
+ DOWNLOAD_ONLY
592
+ GITHUB_REPOSITORY
593
+ GITLAB_REPOSITORY
594
+ BITBUCKET_REPOSITORY
595
+ GIT_REPOSITORY
596
+ SOURCE_DIR
597
+ FIND_PACKAGE_ARGUMENTS
598
+ NO_CACHE
599
+ SYSTEM
600
+ GIT_SHALLOW
601
+ EXCLUDE_FROM_ALL
602
+ SOURCE_SUBDIR
603
+ CUSTOM_CACHE_KEY
604
+ )
605
+
606
+ set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND PATCHES)
607
+
608
+ cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
609
+
610
+ # Set default values for arguments
611
+
612
+ if(NOT DEFINED CPM_ARGS_VERSION)
613
+ if(DEFINED CPM_ARGS_GIT_TAG)
614
+ cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
615
+ endif()
616
+ endif()
617
+
618
+ if(CPM_ARGS_DOWNLOAD_ONLY)
619
+ set(DOWNLOAD_ONLY ${CPM_ARGS_DOWNLOAD_ONLY})
620
+ else()
621
+ set(DOWNLOAD_ONLY NO)
622
+ endif()
623
+
624
+ if(DEFINED CPM_ARGS_GITHUB_REPOSITORY)
625
+ set(CPM_ARGS_GIT_REPOSITORY "https://github.com/${CPM_ARGS_GITHUB_REPOSITORY}.git")
626
+ elseif(DEFINED CPM_ARGS_GITLAB_REPOSITORY)
627
+ set(CPM_ARGS_GIT_REPOSITORY "https://gitlab.com/${CPM_ARGS_GITLAB_REPOSITORY}.git")
628
+ elseif(DEFINED CPM_ARGS_BITBUCKET_REPOSITORY)
629
+ set(CPM_ARGS_GIT_REPOSITORY "https://bitbucket.org/${CPM_ARGS_BITBUCKET_REPOSITORY}.git")
630
+ endif()
631
+
632
+ if(DEFINED CPM_ARGS_GIT_REPOSITORY)
633
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_REPOSITORY ${CPM_ARGS_GIT_REPOSITORY})
634
+ if(NOT DEFINED CPM_ARGS_GIT_TAG)
635
+ set(CPM_ARGS_GIT_TAG v${CPM_ARGS_VERSION})
636
+ endif()
637
+
638
+ # If a name wasn't provided, try to infer it from the git repo
639
+ if(NOT DEFINED CPM_ARGS_NAME)
640
+ cpm_package_name_from_git_uri(${CPM_ARGS_GIT_REPOSITORY} CPM_ARGS_NAME)
641
+ endif()
642
+ endif()
643
+
644
+ set(CPM_SKIP_FETCH FALSE)
645
+
646
+ if(DEFINED CPM_ARGS_GIT_TAG)
647
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_TAG ${CPM_ARGS_GIT_TAG})
648
+ # If GIT_SHALLOW is explicitly specified, honor the value.
649
+ if(DEFINED CPM_ARGS_GIT_SHALLOW)
650
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW ${CPM_ARGS_GIT_SHALLOW})
651
+ endif()
652
+ endif()
653
+
654
+ if(DEFINED CPM_ARGS_URL)
655
+ # If a name or version aren't provided, try to infer them from the URL
656
+ list(GET CPM_ARGS_URL 0 firstUrl)
657
+ cpm_package_name_and_ver_from_url(${firstUrl} nameFromUrl verFromUrl)
658
+ # If we fail to obtain name and version from the first URL, we could try other URLs if any.
659
+ # However multiple URLs are expected to be quite rare, so for now we won't bother.
660
+
661
+ # If the caller provided their own name and version, they trump the inferred ones.
662
+ if(NOT DEFINED CPM_ARGS_NAME)
663
+ set(CPM_ARGS_NAME ${nameFromUrl})
664
+ endif()
665
+ if(NOT DEFINED CPM_ARGS_VERSION)
666
+ set(CPM_ARGS_VERSION ${verFromUrl})
667
+ endif()
668
+
669
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS URL "${CPM_ARGS_URL}")
670
+ endif()
671
+
672
+ # Check for required arguments
673
+
674
+ if(NOT DEFINED CPM_ARGS_NAME)
675
+ message(
676
+ FATAL_ERROR
677
+ "${CPM_INDENT} 'NAME' was not provided and couldn't be automatically inferred for package added with arguments: '${ARGN}'"
678
+ )
679
+ endif()
680
+
681
+ # Check if package has been added before
682
+ cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}")
683
+ if(CPM_PACKAGE_ALREADY_ADDED)
684
+ cpm_export_variables(${CPM_ARGS_NAME})
685
+ return()
686
+ endif()
687
+
688
+ # Check for manual overrides
689
+ if(NOT CPM_ARGS_FORCE AND NOT "${CPM_${CPM_ARGS_NAME}_SOURCE}" STREQUAL "")
690
+ set(PACKAGE_SOURCE ${CPM_${CPM_ARGS_NAME}_SOURCE})
691
+ set(CPM_${CPM_ARGS_NAME}_SOURCE "")
692
+ CPMAddPackage(
693
+ NAME "${CPM_ARGS_NAME}"
694
+ SOURCE_DIR "${PACKAGE_SOURCE}"
695
+ EXCLUDE_FROM_ALL "${CPM_ARGS_EXCLUDE_FROM_ALL}"
696
+ SYSTEM "${CPM_ARGS_SYSTEM}"
697
+ PATCHES "${CPM_ARGS_PATCHES}"
698
+ OPTIONS "${CPM_ARGS_OPTIONS}"
699
+ SOURCE_SUBDIR "${CPM_ARGS_SOURCE_SUBDIR}"
700
+ DOWNLOAD_ONLY "${DOWNLOAD_ONLY}"
701
+ FORCE True
702
+ )
703
+ cpm_export_variables(${CPM_ARGS_NAME})
704
+ return()
705
+ endif()
706
+
707
+ # Check for available declaration
708
+ if(NOT CPM_ARGS_FORCE AND NOT "${CPM_DECLARATION_${CPM_ARGS_NAME}}" STREQUAL "")
709
+ set(declaration ${CPM_DECLARATION_${CPM_ARGS_NAME}})
710
+ set(CPM_DECLARATION_${CPM_ARGS_NAME} "")
711
+ CPMAddPackage(${declaration})
712
+ cpm_export_variables(${CPM_ARGS_NAME})
713
+ # checking again to ensure version and option compatibility
714
+ cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}")
715
+ return()
716
+ endif()
717
+
718
+ if(NOT CPM_ARGS_FORCE)
719
+ if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY)
720
+ cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
721
+
722
+ if(CPM_PACKAGE_FOUND)
723
+ cpm_export_variables(${CPM_ARGS_NAME})
724
+ return()
725
+ endif()
726
+
727
+ if(CPM_LOCAL_PACKAGES_ONLY)
728
+ message(
729
+ SEND_ERROR
730
+ "${CPM_INDENT} ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})"
731
+ )
732
+ endif()
733
+ endif()
734
+ endif()
735
+
736
+ CPMRegisterPackage("${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}")
737
+
738
+ if(DEFINED CPM_ARGS_GIT_TAG)
739
+ set(PACKAGE_INFO "${CPM_ARGS_GIT_TAG}")
740
+ elseif(DEFINED CPM_ARGS_SOURCE_DIR)
741
+ set(PACKAGE_INFO "${CPM_ARGS_SOURCE_DIR}")
742
+ else()
743
+ set(PACKAGE_INFO "${CPM_ARGS_VERSION}")
744
+ endif()
745
+
746
+ if(DEFINED FETCHCONTENT_BASE_DIR)
747
+ # respect user's FETCHCONTENT_BASE_DIR if set
748
+ set(CPM_FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR})
749
+ else()
750
+ set(CPM_FETCHCONTENT_BASE_DIR ${CMAKE_BINARY_DIR}/_deps)
751
+ endif()
752
+
753
+ cpm_add_patches(${CPM_ARGS_PATCHES})
754
+
755
+ if(DEFINED CPM_ARGS_DOWNLOAD_COMMAND)
756
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND})
757
+ elseif(DEFINED CPM_ARGS_SOURCE_DIR)
758
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${CPM_ARGS_SOURCE_DIR})
759
+ if(NOT IS_ABSOLUTE ${CPM_ARGS_SOURCE_DIR})
760
+ # Expand `CPM_ARGS_SOURCE_DIR` relative path. This is important because EXISTS doesn't work
761
+ # for relative paths.
762
+ get_filename_component(
763
+ source_directory ${CPM_ARGS_SOURCE_DIR} REALPATH BASE_DIR ${CMAKE_CURRENT_BINARY_DIR}
764
+ )
765
+ else()
766
+ set(source_directory ${CPM_ARGS_SOURCE_DIR})
767
+ endif()
768
+ if(NOT EXISTS ${source_directory})
769
+ string(TOLOWER ${CPM_ARGS_NAME} lower_case_name)
770
+ # remove timestamps so CMake will re-download the dependency
771
+ file(REMOVE_RECURSE "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild")
772
+ endif()
773
+ elseif(CPM_SOURCE_CACHE AND NOT CPM_ARGS_NO_CACHE)
774
+ string(TOLOWER ${CPM_ARGS_NAME} lower_case_name)
775
+ set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS})
776
+ list(SORT origin_parameters)
777
+ if(CPM_ARGS_CUSTOM_CACHE_KEY)
778
+ # Application set a custom unique directory name
779
+ set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${CPM_ARGS_CUSTOM_CACHE_KEY})
780
+ elseif(CPM_USE_NAMED_CACHE_DIRECTORIES)
781
+ string(SHA1 origin_hash "${origin_parameters};NEW_CACHE_STRUCTURE_TAG")
782
+ set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}/${CPM_ARGS_NAME})
783
+ else()
784
+ string(SHA1 origin_hash "${origin_parameters}")
785
+ set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash})
786
+ endif()
787
+ # Expand `download_directory` relative path. This is important because EXISTS doesn't work for
788
+ # relative paths.
789
+ get_filename_component(download_directory ${download_directory} ABSOLUTE)
790
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${download_directory})
791
+
792
+ if(CPM_SOURCE_CACHE)
793
+ file(LOCK ${download_directory}/../cmake.lock)
794
+ endif()
795
+
796
+ if(EXISTS ${download_directory})
797
+ if(CPM_SOURCE_CACHE)
798
+ file(LOCK ${download_directory}/../cmake.lock RELEASE)
799
+ endif()
800
+
801
+ cpm_store_fetch_properties(
802
+ ${CPM_ARGS_NAME} "${download_directory}"
803
+ "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build"
804
+ )
805
+ cpm_get_fetch_properties("${CPM_ARGS_NAME}")
806
+
807
+ if(DEFINED CPM_ARGS_GIT_TAG AND NOT (PATCH_COMMAND IN_LIST CPM_ARGS_UNPARSED_ARGUMENTS))
808
+ # warn if cache has been changed since checkout
809
+ cpm_check_git_working_dir_is_clean(${download_directory} ${CPM_ARGS_GIT_TAG} IS_CLEAN)
810
+ if(NOT ${IS_CLEAN})
811
+ message(
812
+ WARNING "${CPM_INDENT} Cache for ${CPM_ARGS_NAME} (${download_directory}) is dirty"
813
+ )
814
+ endif()
815
+ endif()
816
+
817
+ cpm_add_subdirectory(
818
+ "${CPM_ARGS_NAME}"
819
+ "${DOWNLOAD_ONLY}"
820
+ "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}"
821
+ "${${CPM_ARGS_NAME}_BINARY_DIR}"
822
+ "${CPM_ARGS_EXCLUDE_FROM_ALL}"
823
+ "${CPM_ARGS_SYSTEM}"
824
+ "${CPM_ARGS_OPTIONS}"
825
+ )
826
+ set(PACKAGE_INFO "${PACKAGE_INFO} at ${download_directory}")
827
+
828
+ # As the source dir is already cached/populated, we override the call to FetchContent.
829
+ set(CPM_SKIP_FETCH TRUE)
830
+ cpm_override_fetchcontent(
831
+ "${lower_case_name}" SOURCE_DIR "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}"
832
+ BINARY_DIR "${${CPM_ARGS_NAME}_BINARY_DIR}"
833
+ )
834
+
835
+ else()
836
+ # Enable shallow clone when GIT_TAG is not a commit hash. Our guess may not be accurate, but
837
+ # it should guarantee no commit hash get mis-detected.
838
+ if(NOT DEFINED CPM_ARGS_GIT_SHALLOW)
839
+ cpm_is_git_tag_commit_hash("${CPM_ARGS_GIT_TAG}" IS_HASH)
840
+ if(NOT ${IS_HASH})
841
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW TRUE)
842
+ endif()
843
+ endif()
844
+
845
+ # remove timestamps so CMake will re-download the dependency
846
+ file(REMOVE_RECURSE ${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild)
847
+ set(PACKAGE_INFO "${PACKAGE_INFO} to ${download_directory}")
848
+ endif()
849
+ endif()
850
+
851
+ cpm_create_module_file(${CPM_ARGS_NAME} "CPMAddPackage(\"${ARGN}\")")
852
+
853
+ if(CPM_PACKAGE_LOCK_ENABLED)
854
+ if((CPM_ARGS_VERSION AND NOT CPM_ARGS_SOURCE_DIR) OR CPM_INCLUDE_ALL_IN_PACKAGE_LOCK)
855
+ cpm_add_to_package_lock(${CPM_ARGS_NAME} "${ARGN}")
856
+ elseif(CPM_ARGS_SOURCE_DIR)
857
+ cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "local directory")
858
+ else()
859
+ cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "${ARGN}")
860
+ endif()
861
+ endif()
862
+
863
+ cpm_message(
864
+ STATUS "${CPM_INDENT} Adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} (${PACKAGE_INFO})"
865
+ )
866
+
867
+ if(NOT CPM_SKIP_FETCH)
868
+ # CMake 3.28 added EXCLUDE, SYSTEM (3.25), and SOURCE_SUBDIR (3.18) to FetchContent_Declare.
869
+ # Calling FetchContent_MakeAvailable will then internally forward these options to
870
+ # add_subdirectory. Up until these changes, we had to call FetchContent_Populate and
871
+ # add_subdirectory separately, which is no longer necessary and has been deprecated as of 3.30.
872
+ set(fetchContentDeclareExtraArgs "")
873
+ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.28.0")
874
+ if(${CPM_ARGS_EXCLUDE_FROM_ALL})
875
+ list(APPEND fetchContentDeclareExtraArgs EXCLUDE_FROM_ALL)
876
+ endif()
877
+ if(${CPM_ARGS_SYSTEM})
878
+ list(APPEND fetchContentDeclareExtraArgs SYSTEM)
879
+ endif()
880
+ if(DEFINED CPM_ARGS_SOURCE_SUBDIR)
881
+ list(APPEND fetchContentDeclareExtraArgs SOURCE_SUBDIR ${CPM_ARGS_SOURCE_SUBDIR})
882
+ endif()
883
+ # For CMake version <3.28 OPTIONS are parsed in cpm_add_subdirectory
884
+ if(CPM_ARGS_OPTIONS AND NOT DOWNLOAD_ONLY)
885
+ foreach(OPTION ${CPM_ARGS_OPTIONS})
886
+ cpm_parse_option("${OPTION}")
887
+ set(${OPTION_KEY} "${OPTION_VALUE}")
888
+ endforeach()
889
+ endif()
890
+ endif()
891
+ cpm_declare_fetch(
892
+ "${CPM_ARGS_NAME}" ${fetchContentDeclareExtraArgs} "${CPM_ARGS_UNPARSED_ARGUMENTS}"
893
+ )
894
+
895
+ cpm_fetch_package("${CPM_ARGS_NAME}" ${DOWNLOAD_ONLY} populated ${CPM_ARGS_UNPARSED_ARGUMENTS})
896
+ if(CPM_SOURCE_CACHE AND download_directory)
897
+ file(LOCK ${download_directory}/../cmake.lock RELEASE)
898
+ endif()
899
+ if(${populated} AND ${CMAKE_VERSION} VERSION_LESS "3.28.0")
900
+ cpm_add_subdirectory(
901
+ "${CPM_ARGS_NAME}"
902
+ "${DOWNLOAD_ONLY}"
903
+ "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}"
904
+ "${${CPM_ARGS_NAME}_BINARY_DIR}"
905
+ "${CPM_ARGS_EXCLUDE_FROM_ALL}"
906
+ "${CPM_ARGS_SYSTEM}"
907
+ "${CPM_ARGS_OPTIONS}"
908
+ )
909
+ endif()
910
+ cpm_get_fetch_properties("${CPM_ARGS_NAME}")
911
+ endif()
912
+
913
+ set(${CPM_ARGS_NAME}_ADDED YES)
914
+ cpm_export_variables("${CPM_ARGS_NAME}")
915
+ endfunction()
916
+
917
+ # Fetch a previously declared package
918
+ macro(CPMGetPackage Name)
919
+ if(DEFINED "CPM_DECLARATION_${Name}")
920
+ CPMAddPackage(NAME ${Name})
921
+ else()
922
+ message(SEND_ERROR "${CPM_INDENT} Cannot retrieve package ${Name}: no declaration available")
923
+ endif()
924
+ endmacro()
925
+
926
+ # export variables available to the caller to the parent scope expects ${CPM_ARGS_NAME} to be set
927
+ macro(cpm_export_variables name)
928
+ set(${name}_SOURCE_DIR
929
+ "${${name}_SOURCE_DIR}"
930
+ PARENT_SCOPE
931
+ )
932
+ set(${name}_BINARY_DIR
933
+ "${${name}_BINARY_DIR}"
934
+ PARENT_SCOPE
935
+ )
936
+ set(${name}_ADDED
937
+ "${${name}_ADDED}"
938
+ PARENT_SCOPE
939
+ )
940
+ set(CPM_LAST_PACKAGE_NAME
941
+ "${name}"
942
+ PARENT_SCOPE
943
+ )
944
+ endmacro()
945
+
946
+ # declares a package, so that any call to CPMAddPackage for the package name will use these
947
+ # arguments instead. Previous declarations will not be overridden.
948
+ macro(CPMDeclarePackage Name)
949
+ if(NOT DEFINED "CPM_DECLARATION_${Name}")
950
+ set("CPM_DECLARATION_${Name}" "${ARGN}")
951
+ endif()
952
+ endmacro()
953
+
954
+ function(cpm_add_to_package_lock Name)
955
+ if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
956
+ cpm_prettify_package_arguments(PRETTY_ARGN false ${ARGN})
957
+ file(APPEND ${CPM_PACKAGE_LOCK_FILE} "# ${Name}\nCPMDeclarePackage(${Name}\n${PRETTY_ARGN})\n")
958
+ endif()
959
+ endfunction()
960
+
961
+ function(cpm_add_comment_to_package_lock Name)
962
+ if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
963
+ cpm_prettify_package_arguments(PRETTY_ARGN true ${ARGN})
964
+ file(APPEND ${CPM_PACKAGE_LOCK_FILE}
965
+ "# ${Name} (unversioned)\n# CPMDeclarePackage(${Name}\n${PRETTY_ARGN}#)\n"
966
+ )
967
+ endif()
968
+ endfunction()
969
+
970
+ # includes the package lock file if it exists and creates a target `cpm-update-package-lock` to
971
+ # update it
972
+ macro(CPMUsePackageLock file)
973
+ if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
974
+ get_filename_component(CPM_ABSOLUTE_PACKAGE_LOCK_PATH ${file} ABSOLUTE)
975
+ if(EXISTS ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH})
976
+ include(${CPM_ABSOLUTE_PACKAGE_LOCK_PATH})
977
+ endif()
978
+ if(NOT TARGET cpm-update-package-lock)
979
+ add_custom_target(
980
+ cpm-update-package-lock COMMAND ${CMAKE_COMMAND} -E copy ${CPM_PACKAGE_LOCK_FILE}
981
+ ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH}
982
+ )
983
+ endif()
984
+ set(CPM_PACKAGE_LOCK_ENABLED true)
985
+ endif()
986
+ endmacro()
987
+
988
+ # registers a package that has been added to CPM
989
+ function(CPMRegisterPackage PACKAGE VERSION)
990
+ list(APPEND CPM_PACKAGES ${PACKAGE})
991
+ set(CPM_PACKAGES
992
+ ${CPM_PACKAGES}
993
+ CACHE INTERNAL ""
994
+ )
995
+ set("CPM_PACKAGE_${PACKAGE}_VERSION"
996
+ ${VERSION}
997
+ CACHE INTERNAL ""
998
+ )
999
+ endfunction()
1000
+
1001
+ # retrieve the current version of the package to ${OUTPUT}
1002
+ function(CPMGetPackageVersion PACKAGE OUTPUT)
1003
+ set(${OUTPUT}
1004
+ "${CPM_PACKAGE_${PACKAGE}_VERSION}"
1005
+ PARENT_SCOPE
1006
+ )
1007
+ endfunction()
1008
+
1009
+ # declares a package in FetchContent_Declare
1010
+ function(cpm_declare_fetch PACKAGE)
1011
+ if(${CPM_DRY_RUN})
1012
+ cpm_message(STATUS "${CPM_INDENT} Package not declared (dry run)")
1013
+ return()
1014
+ endif()
1015
+
1016
+ FetchContent_Declare(${PACKAGE} ${ARGN})
1017
+ endfunction()
1018
+
1019
+ # returns properties for a package previously defined by cpm_declare_fetch
1020
+ function(cpm_get_fetch_properties PACKAGE)
1021
+ if(${CPM_DRY_RUN})
1022
+ return()
1023
+ endif()
1024
+
1025
+ set(${PACKAGE}_SOURCE_DIR
1026
+ "${CPM_PACKAGE_${PACKAGE}_SOURCE_DIR}"
1027
+ PARENT_SCOPE
1028
+ )
1029
+ set(${PACKAGE}_BINARY_DIR
1030
+ "${CPM_PACKAGE_${PACKAGE}_BINARY_DIR}"
1031
+ PARENT_SCOPE
1032
+ )
1033
+ endfunction()
1034
+
1035
+ function(cpm_store_fetch_properties PACKAGE source_dir binary_dir)
1036
+ if(${CPM_DRY_RUN})
1037
+ return()
1038
+ endif()
1039
+
1040
+ set(CPM_PACKAGE_${PACKAGE}_SOURCE_DIR
1041
+ "${source_dir}"
1042
+ CACHE INTERNAL ""
1043
+ )
1044
+ set(CPM_PACKAGE_${PACKAGE}_BINARY_DIR
1045
+ "${binary_dir}"
1046
+ CACHE INTERNAL ""
1047
+ )
1048
+ endfunction()
1049
+
1050
+ # adds a package as a subdirectory if viable, according to provided options
1051
+ function(
1052
+ cpm_add_subdirectory
1053
+ PACKAGE
1054
+ DOWNLOAD_ONLY
1055
+ SOURCE_DIR
1056
+ BINARY_DIR
1057
+ EXCLUDE
1058
+ SYSTEM
1059
+ OPTIONS
1060
+ )
1061
+
1062
+ if(NOT DOWNLOAD_ONLY AND EXISTS ${SOURCE_DIR}/CMakeLists.txt)
1063
+ set(addSubdirectoryExtraArgs "")
1064
+ if(EXCLUDE)
1065
+ list(APPEND addSubdirectoryExtraArgs EXCLUDE_FROM_ALL)
1066
+ endif()
1067
+ if("${SYSTEM}" AND "${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.25")
1068
+ # https://cmake.org/cmake/help/latest/prop_dir/SYSTEM.html#prop_dir:SYSTEM
1069
+ list(APPEND addSubdirectoryExtraArgs SYSTEM)
1070
+ endif()
1071
+ if(OPTIONS)
1072
+ foreach(OPTION ${OPTIONS})
1073
+ cpm_parse_option("${OPTION}")
1074
+ set(${OPTION_KEY} "${OPTION_VALUE}")
1075
+ endforeach()
1076
+ endif()
1077
+ set(CPM_OLD_INDENT "${CPM_INDENT}")
1078
+ set(CPM_INDENT "${CPM_INDENT} ${PACKAGE}:")
1079
+ add_subdirectory(${SOURCE_DIR} ${BINARY_DIR} ${addSubdirectoryExtraArgs})
1080
+ set(CPM_INDENT "${CPM_OLD_INDENT}")
1081
+ endif()
1082
+ endfunction()
1083
+
1084
+ # downloads a previously declared package via FetchContent and exports the variables
1085
+ # `${PACKAGE}_SOURCE_DIR` and `${PACKAGE}_BINARY_DIR` to the parent scope
1086
+ function(cpm_fetch_package PACKAGE DOWNLOAD_ONLY populated)
1087
+ set(${populated}
1088
+ FALSE
1089
+ PARENT_SCOPE
1090
+ )
1091
+ if(${CPM_DRY_RUN})
1092
+ cpm_message(STATUS "${CPM_INDENT} Package ${PACKAGE} not fetched (dry run)")
1093
+ return()
1094
+ endif()
1095
+
1096
+ FetchContent_GetProperties(${PACKAGE})
1097
+
1098
+ string(TOLOWER "${PACKAGE}" lower_case_name)
1099
+
1100
+ if(NOT ${lower_case_name}_POPULATED)
1101
+ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.28.0")
1102
+ if(DOWNLOAD_ONLY)
1103
+ # MakeAvailable will call add_subdirectory internally which is not what we want when
1104
+ # DOWNLOAD_ONLY is set. Populate will only download the dependency without adding it to the
1105
+ # build
1106
+ FetchContent_Populate(
1107
+ ${PACKAGE}
1108
+ SOURCE_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-src"
1109
+ BINARY_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build"
1110
+ SUBBUILD_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild"
1111
+ ${ARGN}
1112
+ )
1113
+ else()
1114
+ FetchContent_MakeAvailable(${PACKAGE})
1115
+ endif()
1116
+ else()
1117
+ FetchContent_Populate(${PACKAGE})
1118
+ endif()
1119
+ set(${populated}
1120
+ TRUE
1121
+ PARENT_SCOPE
1122
+ )
1123
+ endif()
1124
+
1125
+ cpm_store_fetch_properties(
1126
+ ${CPM_ARGS_NAME} ${${lower_case_name}_SOURCE_DIR} ${${lower_case_name}_BINARY_DIR}
1127
+ )
1128
+
1129
+ set(${PACKAGE}_SOURCE_DIR
1130
+ ${${lower_case_name}_SOURCE_DIR}
1131
+ PARENT_SCOPE
1132
+ )
1133
+ set(${PACKAGE}_BINARY_DIR
1134
+ ${${lower_case_name}_BINARY_DIR}
1135
+ PARENT_SCOPE
1136
+ )
1137
+ endfunction()
1138
+
1139
+ # splits a package option
1140
+ function(cpm_parse_option OPTION)
1141
+ string(REGEX MATCH "^[^ ]+" OPTION_KEY "${OPTION}")
1142
+ string(LENGTH "${OPTION}" OPTION_LENGTH)
1143
+ string(LENGTH "${OPTION_KEY}" OPTION_KEY_LENGTH)
1144
+ if(OPTION_KEY_LENGTH STREQUAL OPTION_LENGTH)
1145
+ # no value for key provided, assume user wants to set option to "ON"
1146
+ set(OPTION_VALUE "ON")
1147
+ else()
1148
+ math(EXPR OPTION_KEY_LENGTH "${OPTION_KEY_LENGTH}+1")
1149
+ string(SUBSTRING "${OPTION}" "${OPTION_KEY_LENGTH}" "-1" OPTION_VALUE)
1150
+ endif()
1151
+ set(OPTION_KEY
1152
+ "${OPTION_KEY}"
1153
+ PARENT_SCOPE
1154
+ )
1155
+ set(OPTION_VALUE
1156
+ "${OPTION_VALUE}"
1157
+ PARENT_SCOPE
1158
+ )
1159
+ endfunction()
1160
+
1161
+ # guesses the package version from a git tag
1162
+ function(cpm_get_version_from_git_tag GIT_TAG RESULT)
1163
+ string(LENGTH ${GIT_TAG} length)
1164
+ if(length EQUAL 40)
1165
+ # GIT_TAG is probably a git hash
1166
+ set(${RESULT}
1167
+ 0
1168
+ PARENT_SCOPE
1169
+ )
1170
+ else()
1171
+ string(REGEX MATCH "v?([0123456789.]*).*" _ ${GIT_TAG})
1172
+ set(${RESULT}
1173
+ ${CMAKE_MATCH_1}
1174
+ PARENT_SCOPE
1175
+ )
1176
+ endif()
1177
+ endfunction()
1178
+
1179
+ # guesses if the git tag is a commit hash or an actual tag or a branch name.
1180
+ function(cpm_is_git_tag_commit_hash GIT_TAG RESULT)
1181
+ string(LENGTH "${GIT_TAG}" length)
1182
+ # full hash has 40 characters, and short hash has at least 7 characters.
1183
+ if(length LESS 7 OR length GREATER 40)
1184
+ set(${RESULT}
1185
+ 0
1186
+ PARENT_SCOPE
1187
+ )
1188
+ else()
1189
+ if(${GIT_TAG} MATCHES "^[a-fA-F0-9]+$")
1190
+ set(${RESULT}
1191
+ 1
1192
+ PARENT_SCOPE
1193
+ )
1194
+ else()
1195
+ set(${RESULT}
1196
+ 0
1197
+ PARENT_SCOPE
1198
+ )
1199
+ endif()
1200
+ endif()
1201
+ endfunction()
1202
+
1203
+ function(cpm_prettify_package_arguments OUT_VAR IS_IN_COMMENT)
1204
+ set(oneValueArgs
1205
+ NAME
1206
+ FORCE
1207
+ VERSION
1208
+ GIT_TAG
1209
+ DOWNLOAD_ONLY
1210
+ GITHUB_REPOSITORY
1211
+ GITLAB_REPOSITORY
1212
+ BITBUCKET_REPOSITORY
1213
+ GIT_REPOSITORY
1214
+ SOURCE_DIR
1215
+ FIND_PACKAGE_ARGUMENTS
1216
+ NO_CACHE
1217
+ SYSTEM
1218
+ GIT_SHALLOW
1219
+ EXCLUDE_FROM_ALL
1220
+ SOURCE_SUBDIR
1221
+ )
1222
+ set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND)
1223
+ cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
1224
+
1225
+ foreach(oneArgName ${oneValueArgs})
1226
+ if(DEFINED CPM_ARGS_${oneArgName})
1227
+ if(${IS_IN_COMMENT})
1228
+ string(APPEND PRETTY_OUT_VAR "#")
1229
+ endif()
1230
+ if(${oneArgName} STREQUAL "SOURCE_DIR")
1231
+ string(REPLACE ${CMAKE_SOURCE_DIR} "\${CMAKE_SOURCE_DIR}" CPM_ARGS_${oneArgName}
1232
+ ${CPM_ARGS_${oneArgName}}
1233
+ )
1234
+ endif()
1235
+ string(APPEND PRETTY_OUT_VAR " ${oneArgName} ${CPM_ARGS_${oneArgName}}\n")
1236
+ endif()
1237
+ endforeach()
1238
+ foreach(multiArgName ${multiValueArgs})
1239
+ if(DEFINED CPM_ARGS_${multiArgName})
1240
+ if(${IS_IN_COMMENT})
1241
+ string(APPEND PRETTY_OUT_VAR "#")
1242
+ endif()
1243
+ string(APPEND PRETTY_OUT_VAR " ${multiArgName}\n")
1244
+ foreach(singleOption ${CPM_ARGS_${multiArgName}})
1245
+ if(${IS_IN_COMMENT})
1246
+ string(APPEND PRETTY_OUT_VAR "#")
1247
+ endif()
1248
+ string(APPEND PRETTY_OUT_VAR " \"${singleOption}\"\n")
1249
+ endforeach()
1250
+ endif()
1251
+ endforeach()
1252
+
1253
+ if(NOT "${CPM_ARGS_UNPARSED_ARGUMENTS}" STREQUAL "")
1254
+ if(${IS_IN_COMMENT})
1255
+ string(APPEND PRETTY_OUT_VAR "#")
1256
+ endif()
1257
+ string(APPEND PRETTY_OUT_VAR " ")
1258
+ foreach(CPM_ARGS_UNPARSED_ARGUMENT ${CPM_ARGS_UNPARSED_ARGUMENTS})
1259
+ string(APPEND PRETTY_OUT_VAR " ${CPM_ARGS_UNPARSED_ARGUMENT}")
1260
+ endforeach()
1261
+ string(APPEND PRETTY_OUT_VAR "\n")
1262
+ endif()
1263
+
1264
+ set(${OUT_VAR}
1265
+ ${PRETTY_OUT_VAR}
1266
+ PARENT_SCOPE
1267
+ )
1268
+
1269
+ endfunction()
third_party/tracy/cmake/ECMFindModuleHelpers.cmake ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #.rst:
2
+ # ECMFindModuleHelpers
3
+ # --------------------
4
+ #
5
+ # Helper macros for find modules: ecm_find_package_version_check(),
6
+ # ecm_find_package_parse_components() and
7
+ # ecm_find_package_handle_library_components().
8
+ #
9
+ # ::
10
+ #
11
+ # ecm_find_package_version_check(<name>)
12
+ #
13
+ # Prints warnings if the CMake version or the project's required CMake version
14
+ # is older than that required by extra-cmake-modules.
15
+ #
16
+ # ::
17
+ #
18
+ # ecm_find_package_parse_components(<name>
19
+ # RESULT_VAR <variable>
20
+ # KNOWN_COMPONENTS <component1> [<component2> [...]]
21
+ # [SKIP_DEPENDENCY_HANDLING])
22
+ #
23
+ # This macro will populate <variable> with a list of components found in
24
+ # <name>_FIND_COMPONENTS, after checking that all those components are in the
25
+ # list of KNOWN_COMPONENTS; if there are any unknown components, it will print
26
+ # an error or warning (depending on the value of <name>_FIND_REQUIRED) and call
27
+ # return().
28
+ #
29
+ # The order of components in <variable> is guaranteed to match the order they
30
+ # are listed in the KNOWN_COMPONENTS argument.
31
+ #
32
+ # If SKIP_DEPENDENCY_HANDLING is not set, for each component the variable
33
+ # <name>_<component>_component_deps will be checked for dependent components.
34
+ # If <component> is listed in <name>_FIND_COMPONENTS, then all its (transitive)
35
+ # dependencies will also be added to <variable>.
36
+ #
37
+ # ::
38
+ #
39
+ # ecm_find_package_handle_library_components(<name>
40
+ # COMPONENTS <component> [<component> [...]]
41
+ # [SKIP_DEPENDENCY_HANDLING])
42
+ # [SKIP_PKG_CONFIG])
43
+ #
44
+ # Creates an imported library target for each component. The operation of this
45
+ # macro depends on the presence of a number of CMake variables.
46
+ #
47
+ # The <name>_<component>_lib variable should contain the name of this library,
48
+ # and <name>_<component>_header variable should contain the name of a header
49
+ # file associated with it (whatever relative path is normally passed to
50
+ # '#include'). <name>_<component>_header_subdir variable can be used to specify
51
+ # which subdirectory of the include path the headers will be found in.
52
+ # ecm_find_package_components() will then search for the library
53
+ # and include directory (creating appropriate cache variables) and create an
54
+ # imported library target named <name>::<component>.
55
+ #
56
+ # Additional variables can be used to provide additional information:
57
+ #
58
+ # If SKIP_PKG_CONFIG, the <name>_<component>_pkg_config variable is set, and
59
+ # pkg-config is found, the pkg-config module given by
60
+ # <name>_<component>_pkg_config will be searched for and used to help locate the
61
+ # library and header file. It will also be used to set
62
+ # <name>_<component>_VERSION.
63
+ #
64
+ # Note that if version information is found via pkg-config,
65
+ # <name>_<component>_FIND_VERSION can be set to require a particular version
66
+ # for each component.
67
+ #
68
+ # If SKIP_DEPENDENCY_HANDLING is not set, the INTERFACE_LINK_LIBRARIES property
69
+ # of the imported target for <component> will be set to contain the imported
70
+ # targets for the components listed in <name>_<component>_component_deps.
71
+ # <component>_FOUND will also be set to false if any of the components in
72
+ # <name>_<component>_component_deps are not found. This requires the components
73
+ # in <name>_<component>_component_deps to be listed before <component> in the
74
+ # COMPONENTS argument.
75
+ #
76
+ # The following variables will be set:
77
+ #
78
+ # ``<name>_TARGETS``
79
+ # the imported targets
80
+ # ``<name>_LIBRARIES``
81
+ # the found libraries
82
+ # ``<name>_INCLUDE_DIRS``
83
+ # the combined required include directories for the components
84
+ # ``<name>_DEFINITIONS``
85
+ # the "other" CFLAGS provided by pkg-config, if any
86
+ # ``<name>_VERSION``
87
+ # the value of ``<name>_<component>_VERSION`` for the first component that
88
+ # has this variable set (note that components are searched for in the order
89
+ # they are passed to the macro), although if it is already set, it will not
90
+ # be altered
91
+ #
92
+ # Note that these variables are never cleared, so if
93
+ # ecm_find_package_handle_library_components() is called multiple times with
94
+ # different components (typically because of multiple find_package() calls) then
95
+ # ``<name>_TARGETS``, for example, will contain all the targets found in any
96
+ # call (although no duplicates).
97
+ #
98
+ # Since pre-1.0.0.
99
+
100
+ #=============================================================================
101
+ # Copyright 2014 Alex Merry <alex.merry@kde.org>
102
+ #
103
+ # Redistribution and use in source and binary forms, with or without
104
+ # modification, are permitted provided that the following conditions
105
+ # are met:
106
+ #
107
+ # 1. Redistributions of source code must retain the copyright
108
+ # notice, this list of conditions and the following disclaimer.
109
+ # 2. Redistributions in binary form must reproduce the copyright
110
+ # notice, this list of conditions and the following disclaimer in the
111
+ # documentation and/or other materials provided with the distribution.
112
+ # 3. The name of the author may not be used to endorse or promote products
113
+ # derived from this software without specific prior written permission.
114
+ #
115
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
116
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
117
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
118
+ # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
119
+ # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
120
+ # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
121
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
122
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
123
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
124
+ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
125
+
126
+ macro(ecm_find_package_version_check module_name)
127
+ if(CMAKE_VERSION VERSION_LESS 2.8.12)
128
+ message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake")
129
+ endif()
130
+ if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
131
+ message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Find${module_name}.cmake")
132
+ endif()
133
+ endmacro()
134
+
135
+ macro(ecm_find_package_parse_components module_name)
136
+ set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING)
137
+ set(ecm_fppc_oneValueArgs RESULT_VAR)
138
+ set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS)
139
+ cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN})
140
+
141
+ if(ECM_FPPC_UNPARSED_ARGUMENTS)
142
+ message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}")
143
+ endif()
144
+ if(NOT ECM_FPPC_RESULT_VAR)
145
+ message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components")
146
+ endif()
147
+ if(NOT ECM_FPPC_KNOWN_COMPONENTS)
148
+ message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components")
149
+ endif()
150
+ if(NOT ECM_FPPC_DEFAULT_COMPONENTS)
151
+ set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS})
152
+ endif()
153
+
154
+ if(${module_name}_FIND_COMPONENTS)
155
+ set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS})
156
+
157
+ if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING)
158
+ # Make sure deps are included
159
+ foreach(ecm_fppc_comp ${ecm_fppc_requestedComps})
160
+ foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps})
161
+ list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index)
162
+ if("${ecm_fppc_index}" STREQUAL "-1")
163
+ if(NOT ${module_name}_FIND_QUIETLY)
164
+ message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}")
165
+ endif()
166
+ list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}")
167
+ endif()
168
+ endforeach()
169
+ endforeach()
170
+ else()
171
+ message(STATUS "Skipping dependency handling for ${module_name}")
172
+ endif()
173
+ list(REMOVE_DUPLICATES ecm_fppc_requestedComps)
174
+
175
+ # This makes sure components are listed in the same order as
176
+ # KNOWN_COMPONENTS (potentially important for inter-dependencies)
177
+ set(${ECM_FPPC_RESULT_VAR})
178
+ foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS})
179
+ list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index)
180
+ if(NOT "${ecm_fppc_index}" STREQUAL "-1")
181
+ list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}")
182
+ list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index})
183
+ endif()
184
+ endforeach()
185
+ # if there are any left, they are unknown components
186
+ if(ecm_fppc_requestedComps)
187
+ set(ecm_fppc_msgType STATUS)
188
+ if(${module_name}_FIND_REQUIRED)
189
+ set(ecm_fppc_msgType FATAL_ERROR)
190
+ endif()
191
+ if(NOT ${module_name}_FIND_QUIETLY)
192
+ message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}")
193
+ endif()
194
+ return()
195
+ endif()
196
+ else()
197
+ set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS})
198
+ endif()
199
+ endmacro()
200
+
201
+ macro(ecm_find_package_handle_library_components module_name)
202
+ set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING)
203
+ set(ecm_fpwc_oneValueArgs)
204
+ set(ecm_fpwc_multiValueArgs COMPONENTS)
205
+ cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN})
206
+
207
+ if(ECM_FPWC_UNPARSED_ARGUMENTS)
208
+ message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}")
209
+ endif()
210
+ if(NOT ECM_FPWC_COMPONENTS)
211
+ message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components")
212
+ endif()
213
+
214
+ include(FindPackageHandleStandardArgs)
215
+ find_package(PkgConfig QUIET)
216
+ foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS})
217
+ set(ecm_fpwc_dep_vars)
218
+ set(ecm_fpwc_dep_targets)
219
+ if(NOT SKIP_DEPENDENCY_HANDLING)
220
+ foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps})
221
+ list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND")
222
+ list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}")
223
+ endforeach()
224
+ endif()
225
+
226
+ if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config)
227
+ pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET
228
+ ${${module_name}_${ecm_fpwc_comp}_pkg_config})
229
+ endif()
230
+
231
+ find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
232
+ NAMES ${${module_name}_${ecm_fpwc_comp}_header}
233
+ HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS}
234
+ PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir}
235
+ )
236
+ find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY
237
+ NAMES ${${module_name}_${ecm_fpwc_comp}_lib}
238
+ HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS}
239
+ )
240
+
241
+ set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}")
242
+ if(NOT ${module_name}_VERSION)
243
+ set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION})
244
+ endif()
245
+
246
+ set(_name_mismatched_arg)
247
+ if(NOT CMAKE_VERSION VERSION_LESS 3.17)
248
+ set(_name_mismatched_arg NAME_MISMATCHED)
249
+ endif()
250
+ find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp}
251
+ FOUND_VAR
252
+ ${module_name}_${ecm_fpwc_comp}_FOUND
253
+ REQUIRED_VARS
254
+ ${module_name}_${ecm_fpwc_comp}_LIBRARY
255
+ ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
256
+ ${ecm_fpwc_dep_vars}
257
+ VERSION_VAR
258
+ ${module_name}_${ecm_fpwc_comp}_VERSION
259
+ ${_name_mismatched_arg}
260
+ )
261
+
262
+ mark_as_advanced(
263
+ ${module_name}_${ecm_fpwc_comp}_LIBRARY
264
+ ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
265
+ )
266
+
267
+ if(${module_name}_${ecm_fpwc_comp}_FOUND)
268
+ list(APPEND ${module_name}_LIBRARIES
269
+ "${${module_name}_${ecm_fpwc_comp}_LIBRARY}")
270
+ list(APPEND ${module_name}_INCLUDE_DIRS
271
+ "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}")
272
+ set(${module_name}_DEFINITIONS
273
+ ${${module_name}_DEFINITIONS}
274
+ ${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS})
275
+ if(NOT TARGET ${module_name}::${ecm_fpwc_comp})
276
+ add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED)
277
+ set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES
278
+ IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}"
279
+ INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}"
280
+ INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}"
281
+ INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}"
282
+ )
283
+ endif()
284
+ list(APPEND ${module_name}_TARGETS
285
+ "${module_name}::${ecm_fpwc_comp}")
286
+ endif()
287
+ endforeach()
288
+ if(${module_name}_LIBRARIES)
289
+ list(REMOVE_DUPLICATES ${module_name}_LIBRARIES)
290
+ endif()
291
+ if(${module_name}_INCLUDE_DIRS)
292
+ list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS)
293
+ endif()
294
+ if(${module_name}_DEFINITIONS)
295
+ list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS)
296
+ endif()
297
+ if(${module_name}_TARGETS)
298
+ list(REMOVE_DUPLICATES ${module_name}_TARGETS)
299
+ endif()
300
+ endmacro()
third_party/tracy/cmake/FindWaylandScanner.cmake ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #.rst:
2
+ # FindWaylandScanner
3
+ # ------------------
4
+ #
5
+ # Try to find wayland-scanner.
6
+ #
7
+ # If the wayland-scanner executable is not in your PATH, you can provide
8
+ # an alternative name or full path location with the ``WaylandScanner_EXECUTABLE``
9
+ # variable.
10
+ #
11
+ # This will define the following variables:
12
+ #
13
+ # ``WaylandScanner_FOUND``
14
+ # True if wayland-scanner is available.
15
+ #
16
+ # ``WaylandScanner_EXECUTABLE``
17
+ # The wayland-scanner executable.
18
+ #
19
+ # If ``WaylandScanner_FOUND`` is TRUE, it will also define the following imported
20
+ # target:
21
+ #
22
+ # ``Wayland::Scanner``
23
+ # The wayland-scanner executable.
24
+ #
25
+ # This module provides the following functions to generate C protocol
26
+ # implementations:
27
+ #
28
+ # - ``ecm_add_wayland_client_protocol``
29
+ # - ``ecm_add_wayland_server_protocol``
30
+ #
31
+ # ::
32
+ #
33
+ # ecm_add_wayland_client_protocol(<source_files_var>
34
+ # PROTOCOL <xmlfile>
35
+ # BASENAME <basename>)
36
+ #
37
+ # Generate Wayland client protocol files from ``<xmlfile>`` XML
38
+ # definition for the ``<basename>`` interface and append those files
39
+ # to ``<source_files_var>``.
40
+ #
41
+ # ::
42
+ #
43
+ # ecm_add_wayland_server_protocol(<source_files_var>
44
+ # PROTOCOL <xmlfile>
45
+ # BASENAME <basename>)
46
+ #
47
+ # Generate Wayland server protocol files from ``<xmlfile>`` XML
48
+ # definition for the ``<basename>`` interface and append those files
49
+ # to ``<source_files_var>``.
50
+ #
51
+ # Since 1.4.0.
52
+
53
+ #=============================================================================
54
+ # Copyright 2012-2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
55
+ #
56
+ # Redistribution and use in source and binary forms, with or without
57
+ # modification, are permitted provided that the following conditions
58
+ # are met:
59
+ #
60
+ # 1. Redistributions of source code must retain the copyright
61
+ # notice, this list of conditions and the following disclaimer.
62
+ # 2. Redistributions in binary form must reproduce the copyright
63
+ # notice, this list of conditions and the following disclaimer in the
64
+ # documentation and/or other materials provided with the distribution.
65
+ # 3. The name of the author may not be used to endorse or promote products
66
+ # derived from this software without specific prior written permission.
67
+ #
68
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
69
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
70
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
71
+ # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
72
+ # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
73
+ # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
74
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
75
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
76
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
77
+ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
78
+ #=============================================================================
79
+
80
+ include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpers.cmake)
81
+
82
+ ecm_find_package_version_check(WaylandScanner)
83
+
84
+ # Find wayland-scanner
85
+ find_program(WaylandScanner_EXECUTABLE NAMES wayland-scanner)
86
+
87
+ include(FindPackageHandleStandardArgs)
88
+ find_package_handle_standard_args(WaylandScanner
89
+ FOUND_VAR
90
+ WaylandScanner_FOUND
91
+ REQUIRED_VARS
92
+ WaylandScanner_EXECUTABLE
93
+ )
94
+
95
+ mark_as_advanced(WaylandScanner_EXECUTABLE)
96
+
97
+ if(NOT TARGET Wayland::Scanner AND WaylandScanner_FOUND)
98
+ add_executable(Wayland::Scanner IMPORTED)
99
+ set_target_properties(Wayland::Scanner PROPERTIES
100
+ IMPORTED_LOCATION "${WaylandScanner_EXECUTABLE}"
101
+ )
102
+ endif()
103
+
104
+ include(FeatureSummary)
105
+ set_package_properties(WaylandScanner PROPERTIES
106
+ URL "https://wayland.freedesktop.org/"
107
+ DESCRIPTION "Executable that converts XML protocol files to C code"
108
+ )
109
+
110
+ function(ecm_add_wayland_client_protocol out_var)
111
+ # Parse arguments
112
+ set(oneValueArgs PROTOCOL BASENAME)
113
+ cmake_parse_arguments(ARGS "" "${oneValueArgs}" "" ${ARGN})
114
+
115
+ if(ARGS_UNPARSED_ARGUMENTS)
116
+ message(FATAL_ERROR "Unknown keywords given to ecm_add_wayland_client_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
117
+ endif()
118
+
119
+ get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE)
120
+ set(_client_header "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-client-protocol.h")
121
+ set(_code "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-protocol.c")
122
+
123
+ set_source_files_properties(${_client_header} GENERATED)
124
+ set_source_files_properties(${_code} GENERATED)
125
+ set_property(SOURCE ${_client_header} PROPERTY SKIP_AUTOMOC ON)
126
+
127
+ add_custom_command(OUTPUT "${_client_header}"
128
+ COMMAND ${WaylandScanner_EXECUTABLE} client-header ${_infile} ${_client_header}
129
+ DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile}
130
+ VERBATIM
131
+ )
132
+
133
+ add_custom_command(OUTPUT "${_code}"
134
+ COMMAND ${WaylandScanner_EXECUTABLE} private-code ${_infile} ${_code}
135
+ DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile} ${_client_header}
136
+ VERBATIM
137
+ )
138
+
139
+ list(APPEND ${out_var} "${_client_header}" "${_code}")
140
+ set(${out_var} ${${out_var}} PARENT_SCOPE)
141
+ endfunction()
142
+
143
+
144
+ function(ecm_add_wayland_server_protocol out_var)
145
+ # Parse arguments
146
+ set(oneValueArgs PROTOCOL BASENAME)
147
+ cmake_parse_arguments(ARGS "" "${oneValueArgs}" "" ${ARGN})
148
+
149
+ if(ARGS_UNPARSED_ARGUMENTS)
150
+ message(FATAL_ERROR "Unknown keywords given to ecm_add_wayland_server_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
151
+ endif()
152
+
153
+ ecm_add_wayland_client_protocol(${out_var}
154
+ PROTOCOL ${ARGS_PROTOCOL}
155
+ BASENAME ${ARGS_BASENAME})
156
+
157
+ get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE)
158
+ set(_server_header "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-server-protocol.h")
159
+ set_property(SOURCE ${_server_header} PROPERTY SKIP_AUTOMOC ON)
160
+ set_source_files_properties(${_server_header} GENERATED)
161
+
162
+ add_custom_command(OUTPUT "${_server_header}"
163
+ COMMAND ${WaylandScanner_EXECUTABLE} server-header ${_infile} ${_server_header}
164
+ DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile}
165
+ VERBATIM
166
+ )
167
+
168
+ list(APPEND ${out_var} "${_server_header}")
169
+ set(${out_var} ${${out_var}} PARENT_SCOPE)
170
+ endfunction()
third_party/tracy/cmake/config.cmake ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ if (NOT NO_ISA_EXTENSIONS)
2
+ include(CheckCXXCompilerFlag)
3
+ if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
4
+ CHECK_CXX_COMPILER_FLAG("-mcpu=native" COMPILER_SUPPORTS_MCPU_NATIVE)
5
+ if(COMPILER_SUPPORTS_MARCH_NATIVE)
6
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
7
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=native")
8
+ endif()
9
+ else()
10
+ CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
11
+ if(COMPILER_SUPPORTS_MARCH_NATIVE)
12
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
13
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
14
+ endif()
15
+ endif()
16
+ if(WIN32)
17
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX2")
18
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:AVX2")
19
+ endif()
20
+ endif()
21
+
22
+ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT LEGACY)
23
+ set(USE_WAYLAND ON)
24
+ else()
25
+ set(USE_WAYLAND OFF)
26
+ endif()
27
+
28
+ if(WIN32)
29
+ add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
30
+ add_compile_options(/MP)
31
+ else()
32
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
33
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always")
34
+ endif()
35
+
36
+ if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT EMSCRIPTEN)
37
+ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
38
+ endif()
39
+
40
+ if(EMSCRIPTEN)
41
+ add_compile_options(-pthread)
42
+ add_link_options(-pthread)
43
+ endif()
44
+
45
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT EMSCRIPTEN)
46
+ find_program(MOLD_LINKER mold)
47
+ if(MOLD_LINKER)
48
+ set(CMAKE_LINKER_TYPE "MOLD")
49
+ endif()
50
+ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
51
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-eliminate-unused-debug-types")
52
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-eliminate-unused-debug-types")
53
+ endif()
54
+ endif()
55
+
56
+ file(GENERATE OUTPUT .gitignore CONTENT "*")
third_party/tracy/cmake/server.cmake ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ set(TRACY_COMMON_DIR ${CMAKE_CURRENT_LIST_DIR}/../public/common)
2
+
3
+ set(TRACY_COMMON_SOURCES
4
+ tracy_lz4.cpp
5
+ tracy_lz4hc.cpp
6
+ TracySocket.cpp
7
+ TracyStackFrames.cpp
8
+ TracySystem.cpp
9
+ )
10
+
11
+ list(TRANSFORM TRACY_COMMON_SOURCES PREPEND "${TRACY_COMMON_DIR}/")
12
+
13
+
14
+ set(TRACY_SERVER_DIR ${CMAKE_CURRENT_LIST_DIR}/../server)
15
+
16
+ set(TRACY_SERVER_SOURCES
17
+ TracyMemory.cpp
18
+ TracyMmap.cpp
19
+ TracyPrint.cpp
20
+ TracySysUtil.cpp
21
+ TracyTaskDispatch.cpp
22
+ TracyTextureCompression.cpp
23
+ TracyThreadCompress.cpp
24
+ TracyWorker.cpp
25
+ )
26
+
27
+ list(TRANSFORM TRACY_SERVER_SOURCES PREPEND "${TRACY_SERVER_DIR}/")
28
+
29
+
30
+ add_library(TracyServer STATIC ${TRACY_COMMON_SOURCES} ${TRACY_SERVER_SOURCES})
31
+ target_include_directories(TracyServer PUBLIC ${TRACY_COMMON_DIR} ${TRACY_SERVER_DIR})
32
+ target_link_libraries(TracyServer PUBLIC TracyCapstone TracyZstd)
33
+ if(NO_STATISTICS)
34
+ target_compile_definitions(TracyServer PUBLIC TRACY_NO_STATISTICS)
35
+ endif()
36
+
37
+ if(NOT NO_PARALLEL_STL AND UNIX AND NOT APPLE AND NOT EMSCRIPTEN)
38
+ target_link_libraries(TracyServer PRIVATE TracyTbb)
39
+ endif()
third_party/tracy/cmake/vendor.cmake ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Vendor Specific CMake
2
+ # The Tracy project keeps most vendor source locally
3
+
4
+ set (ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../")
5
+
6
+ # Dependencies are taken from the system first and if not found, they are pulled with CPM and built from source
7
+
8
+ include(FindPkgConfig)
9
+ include(${CMAKE_CURRENT_LIST_DIR}/CPM.cmake)
10
+
11
+ option(DOWNLOAD_CAPSTONE "Force download capstone" ON)
12
+ option(DOWNLOAD_GLFW "Force download glfw" OFF)
13
+ option(DOWNLOAD_FREETYPE "Force download freetype" OFF)
14
+
15
+ # capstone
16
+
17
+ pkg_check_modules(CAPSTONE capstone)
18
+ if(CAPSTONE_FOUND AND NOT DOWNLOAD_CAPSTONE)
19
+ message(STATUS "Capstone found: ${CAPSTONE}")
20
+ add_library(TracyCapstone INTERFACE)
21
+ target_include_directories(TracyCapstone INTERFACE ${CAPSTONE_INCLUDE_DIRS})
22
+ target_link_libraries(TracyCapstone INTERFACE ${CAPSTONE_LINK_LIBRARIES})
23
+ else()
24
+ CPMAddPackage(
25
+ NAME capstone
26
+ GITHUB_REPOSITORY capstone-engine/capstone
27
+ GIT_TAG 5.0.3
28
+ )
29
+ add_library(TracyCapstone INTERFACE)
30
+ target_include_directories(TracyCapstone INTERFACE ${capstone_SOURCE_DIR}/include/capstone)
31
+ target_link_libraries(TracyCapstone INTERFACE capstone)
32
+ endif()
33
+
34
+ # GLFW
35
+
36
+ if(NOT USE_WAYLAND AND NOT EMSCRIPTEN)
37
+ pkg_check_modules(GLFW glfw3)
38
+ if (GLFW_FOUND AND NOT DOWNLOAD_GLFW)
39
+ add_library(TracyGlfw3 INTERFACE)
40
+ target_include_directories(TracyGlfw3 INTERFACE ${GLFW_INCLUDE_DIRS})
41
+ target_link_libraries(TracyGlfw3 INTERFACE ${GLFW_LINK_LIBRARIES})
42
+ else()
43
+ CPMAddPackage(
44
+ NAME glfw
45
+ GITHUB_REPOSITORY glfw/glfw
46
+ GIT_TAG 3.4
47
+ OPTIONS
48
+ "GLFW_BUILD_EXAMPLES OFF"
49
+ "GLFW_BUILD_TESTS OFF"
50
+ "GLFW_BUILD_DOCS OFF"
51
+ "GLFW_INSTALL OFF"
52
+ )
53
+ add_library(TracyGlfw3 INTERFACE)
54
+ target_link_libraries(TracyGlfw3 INTERFACE glfw)
55
+ endif()
56
+ endif()
57
+
58
+ # freetype
59
+
60
+ pkg_check_modules(FREETYPE freetype2)
61
+ if (FREETYPE_FOUND AND NOT DOWNLOAD_FREETYPE)
62
+ add_library(TracyFreetype INTERFACE)
63
+ target_include_directories(TracyFreetype INTERFACE ${FREETYPE_INCLUDE_DIRS})
64
+ target_link_libraries(TracyFreetype INTERFACE ${FREETYPE_LINK_LIBRARIES})
65
+ else()
66
+ CPMAddPackage(
67
+ NAME freetype
68
+ GITHUB_REPOSITORY freetype/freetype
69
+ GIT_TAG VER-2-13-2
70
+ OPTIONS
71
+ "FT_DISABLE_HARFBUZZ ON"
72
+ "FT_WITH_HARFBUZZ OFF"
73
+ )
74
+ add_library(TracyFreetype INTERFACE)
75
+ target_link_libraries(TracyFreetype INTERFACE freetype)
76
+ endif()
77
+
78
+ # zstd
79
+
80
+ set(ZSTD_DIR "${ROOT_DIR}/zstd")
81
+
82
+ set(ZSTD_SOURCES
83
+ decompress/zstd_ddict.c
84
+ decompress/zstd_decompress_block.c
85
+ decompress/huf_decompress.c
86
+ decompress/zstd_decompress.c
87
+ common/zstd_common.c
88
+ common/error_private.c
89
+ common/xxhash.c
90
+ common/entropy_common.c
91
+ common/debug.c
92
+ common/threading.c
93
+ common/pool.c
94
+ common/fse_decompress.c
95
+ compress/zstd_ldm.c
96
+ compress/zstd_compress_superblock.c
97
+ compress/zstd_opt.c
98
+ compress/zstd_compress_sequences.c
99
+ compress/fse_compress.c
100
+ compress/zstd_double_fast.c
101
+ compress/zstd_compress.c
102
+ compress/zstd_compress_literals.c
103
+ compress/hist.c
104
+ compress/zstdmt_compress.c
105
+ compress/zstd_lazy.c
106
+ compress/huf_compress.c
107
+ compress/zstd_fast.c
108
+ dictBuilder/zdict.c
109
+ dictBuilder/cover.c
110
+ dictBuilder/divsufsort.c
111
+ dictBuilder/fastcover.c
112
+ )
113
+
114
+ list(TRANSFORM ZSTD_SOURCES PREPEND "${ZSTD_DIR}/")
115
+
116
+ set_property(SOURCE ${ZSTD_DIR}/decompress/huf_decompress_amd64.S APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp")
117
+
118
+ add_library(TracyZstd STATIC ${ZSTD_SOURCES})
119
+ target_include_directories(TracyZstd PUBLIC ${ZSTD_DIR})
120
+ target_compile_definitions(TracyZstd PRIVATE ZSTD_DISABLE_ASM)
121
+
122
+
123
+ # Diff Template Library
124
+
125
+ set(DTL_DIR "${ROOT_DIR}/dtl")
126
+ file(GLOB_RECURSE DTL_HEADERS CONFIGURE_DEPENDS RELATIVE ${DTL_DIR} "*.hpp")
127
+ add_library(TracyDtl INTERFACE)
128
+ target_sources(TracyDtl INTERFACE ${DTL_HEADERS})
129
+ target_include_directories(TracyDtl INTERFACE ${DTL_DIR})
130
+
131
+
132
+ # Get Opt
133
+
134
+ set(GETOPT_DIR "${ROOT_DIR}/getopt")
135
+ set(GETOPT_SOURCES ${GETOPT_DIR}/getopt.c)
136
+ set(GETOPT_HEADERS ${GETOPT_DIR}/getopt.h)
137
+ add_library(TracyGetOpt STATIC ${GETOPT_SOURCES} ${GETOPT_HEADERS})
138
+ target_include_directories(TracyGetOpt PUBLIC ${GETOPT_DIR})
139
+
140
+
141
+ # ImGui
142
+
143
+ set(IMGUI_DIR "${ROOT_DIR}/imgui")
144
+
145
+ set(IMGUI_SOURCES
146
+ imgui_widgets.cpp
147
+ imgui_draw.cpp
148
+ imgui_demo.cpp
149
+ imgui.cpp
150
+ imgui_tables.cpp
151
+ misc/freetype/imgui_freetype.cpp
152
+ )
153
+
154
+ list(TRANSFORM IMGUI_SOURCES PREPEND "${IMGUI_DIR}/")
155
+
156
+ add_definitions(-DIMGUI_ENABLE_FREETYPE)
157
+
158
+ add_library(TracyImGui STATIC ${IMGUI_SOURCES})
159
+ target_include_directories(TracyImGui PUBLIC ${IMGUI_DIR})
160
+ target_link_libraries(TracyImGui PUBLIC TracyFreetype)
161
+
162
+ # NFD
163
+
164
+ if (NOT NO_FILESELECTOR AND NOT EMSCRIPTEN)
165
+ set(NFD_DIR "${ROOT_DIR}/nfd")
166
+
167
+ if (WIN32)
168
+ set(NFD_SOURCES "${NFD_DIR}/nfd_win.cpp")
169
+ elseif (APPLE)
170
+ set(NFD_SOURCES "${NFD_DIR}/nfd_cocoa.m")
171
+ else()
172
+ if (GTK_FILESELECTOR)
173
+ set(NFD_SOURCES "${NFD_DIR}/nfd_gtk.cpp")
174
+ else()
175
+ set(NFD_SOURCES "${NFD_DIR}/nfd_portal.cpp")
176
+ endif()
177
+ endif()
178
+
179
+ file(GLOB_RECURSE NFD_HEADERS CONFIGURE_DEPENDS RELATIVE ${NFD_DIR} "*.h")
180
+ add_library(TracyNfd STATIC ${NFD_SOURCES} ${NFD_HEADERS})
181
+ target_include_directories(TracyNfd PUBLIC ${NFD_DIR})
182
+
183
+ if (APPLE)
184
+ find_library(APPKIT_LIBRARY AppKit)
185
+ find_library(UNIFORMTYPEIDENTIFIERS_LIBRARY UniformTypeIdentifiers)
186
+ target_link_libraries(TracyNfd PUBLIC ${APPKIT_LIBRARY} ${UNIFORMTYPEIDENTIFIERS_LIBRARY})
187
+ elseif (UNIX)
188
+ if (GTK_FILESELECTOR)
189
+ pkg_check_modules(GTK3 gtk+-3.0)
190
+ if (NOT GTK3_FOUND)
191
+ message(FATAL_ERROR "GTK3 not found. Please install it or set TRACY_GTK_FILESELECTOR to OFF.")
192
+ endif()
193
+ add_library(TracyGtk3 INTERFACE)
194
+ target_include_directories(TracyGtk3 INTERFACE ${GTK3_INCLUDE_DIRS})
195
+ target_link_libraries(TracyGtk3 INTERFACE ${GTK3_LINK_LIBRARIES})
196
+ target_link_libraries(TracyNfd PUBLIC TracyGtk3)
197
+ else()
198
+ pkg_check_modules(DBUS dbus-1)
199
+ if (NOT DBUS_FOUND)
200
+ message(FATAL_ERROR "D-Bus not found. Please install it or set TRACY_GTK_FILESELECTOR to ON.")
201
+ endif()
202
+ add_library(TracyDbus INTERFACE)
203
+ target_include_directories(TracyDbus INTERFACE ${DBUS_INCLUDE_DIRS})
204
+ target_link_libraries(TracyDbus INTERFACE ${DBUS_LINK_LIBRARIES})
205
+ target_link_libraries(TracyNfd PUBLIC TracyDbus)
206
+ endif()
207
+ endif()
208
+ endif()
209
+
210
+ # TBB
211
+ if (NO_PARALLEL_STL)
212
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_PARALLEL_SORT")
213
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_PARALLEL_SORT")
214
+ else()
215
+ if (UNIX AND NOT APPLE AND NOT EMSCRIPTEN)
216
+ # Tracy does not use TBB directly, but the implementation of parallel algorithms
217
+ # in some versions of libstdc++ depends on TBB. When it does, you must
218
+ # explicitly link against -ltbb.
219
+ #
220
+ # Some distributions have pgk-config files for TBB, others don't.
221
+
222
+ pkg_check_modules(TBB tbb)
223
+ if (TBB_FOUND)
224
+ add_library(TracyTbb INTERFACE)
225
+ target_include_directories(TracyTbb INTERFACE ${TBB_INCLUDE_DIRS})
226
+ target_link_libraries(TracyTbb INTERFACE ${TBB_LINK_LIBRARIES})
227
+ else()
228
+ CPMAddPackage(
229
+ NAME tbb
230
+ GITHUB_REPOSITORY oneapi-src/oneTBB
231
+ GIT_TAG v2021.12.0-rc2
232
+ OPTIONS "TBB_TEST OFF"
233
+ )
234
+ add_library(TracyTbb INTERFACE)
235
+ target_link_libraries(TracyTbb INTERFACE tbb)
236
+ endif()
237
+ endif()
238
+ endif()
third_party/tracy/cmake/version.cmake ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cmake_minimum_required(VERSION 3.10)
2
+
3
+ message("Parsing public/common/TracyVersion.hpp file")
4
+
5
+ file(READ "${CMAKE_CURRENT_LIST_DIR}/../public/common/TracyVersion.hpp" version)
6
+
7
+ # Note: This looks for a specific pattern in TracyVersion.hpp, if it changes
8
+ # this needs updating.
9
+ string(REGEX MATCH "Major = ([0-9]+)" _ ${version})
10
+
11
+ # This works do to the above () subexpression selection. See
12
+ # https://cmake.org/cmake/help/latest/command/string.html#regex-match for more
13
+ # details
14
+ set(TRACY_VERSION_MAJOR ${CMAKE_MATCH_1})
15
+
16
+ string(REGEX MATCH "Minor = ([0-9]+)" _ ${version})
17
+ set(TRACY_VERSION_MINOR ${CMAKE_MATCH_1})
18
+
19
+ string(REGEX MATCH "Patch = ([0-9]+)" _ ${version})
20
+ set(TRACY_VERSION_PATCH ${CMAKE_MATCH_1})
21
+
22
+ set(TRACY_VERSION_STRING "${TRACY_VERSION_MAJOR}.${TRACY_VERSION_MINOR}.${TRACY_VERSION_PATCH}")
23
+
24
+ message("VERSION ${TRACY_VERSION_STRING}")
third_party/tracy/csvexport/CMakeLists.txt ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cmake_minimum_required(VERSION 3.16)
2
+
3
+ option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
4
+ option(NO_PARALLEL_STL "Disable parallel STL" OFF)
5
+
6
+ set(NO_STATISTICS OFF)
7
+
8
+ include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
9
+
10
+ set(CMAKE_CXX_STANDARD 20)
11
+
12
+ project(
13
+ tracy-csvexport
14
+ LANGUAGES C CXX
15
+ VERSION ${TRACY_VERSION_STRING}
16
+ )
17
+
18
+ include(${CMAKE_CURRENT_LIST_DIR}/../cmake/config.cmake)
19
+ include(${CMAKE_CURRENT_LIST_DIR}/../cmake/vendor.cmake)
20
+ include(${CMAKE_CURRENT_LIST_DIR}/../cmake/server.cmake)
21
+
22
+ set(PROGRAM_FILES
23
+ src/csvexport.cpp
24
+ )
25
+
26
+ add_executable(${PROJECT_NAME} ${PROGRAM_FILES} ${COMMON_FILES} ${SERVER_FILES})
27
+ target_link_libraries(${PROJECT_NAME} PRIVATE TracyServer TracyGetOpt)
28
+ set_property(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
third_party/tracy/csvexport/src/csvexport.cpp ADDED
@@ -0,0 +1,353 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ifdef _WIN32
2
+ # include <windows.h>
3
+ #endif
4
+
5
+ #include <algorithm>
6
+ #include <cctype>
7
+ #include <fstream>
8
+ #include <iostream>
9
+ #include <sstream>
10
+ #include <string>
11
+
12
+ #include <math.h>
13
+ #include <stdio.h>
14
+ #include <stdint.h>
15
+
16
+ #include "../../server/TracyFileRead.hpp"
17
+ #include "../../server/TracyWorker.hpp"
18
+ #include "../../getopt/getopt.h"
19
+
20
+ void print_usage_exit(int e)
21
+ {
22
+ fprintf(stderr, "Extract statistics from a trace to a CSV format\n");
23
+ fprintf(stderr, "Usage:\n");
24
+ fprintf(stderr, " extract [OPTION...] <trace file>\n");
25
+ fprintf(stderr, "\n");
26
+ fprintf(stderr, " -h, --help Print usage\n");
27
+ fprintf(stderr, " -f, --filter arg Filter zone names (default: "")\n");
28
+ fprintf(stderr, " -s, --sep arg CSV separator (default: ,)\n");
29
+ fprintf(stderr, " -c, --case Case sensitive filtering\n");
30
+ fprintf(stderr, " -e, --self Get self times\n");
31
+ fprintf(stderr, " -u, --unwrap Report each zone event\n");
32
+ fprintf(stderr, " -m, --messages Report only messages\n");
33
+
34
+ exit(e);
35
+ }
36
+
37
+ struct Args {
38
+ const char* filter;
39
+ const char* separator;
40
+ const char* trace_file;
41
+ bool case_sensitive;
42
+ bool self_time;
43
+ bool unwrap;
44
+ bool unwrapMessages;
45
+ };
46
+
47
+ Args parse_args(int argc, char** argv)
48
+ {
49
+ if (argc == 1)
50
+ {
51
+ print_usage_exit(1);
52
+ }
53
+
54
+ Args args = { "", ",", "", false, false, false, false };
55
+
56
+ struct option long_opts[] = {
57
+ { "help", no_argument, NULL, 'h' },
58
+ { "filter", optional_argument, NULL, 'f' },
59
+ { "sep", optional_argument, NULL, 's' },
60
+ { "case", no_argument, NULL, 'c' },
61
+ { "self", no_argument, NULL, 'e' },
62
+ { "unwrap", no_argument, NULL, 'u' },
63
+ { "messages", no_argument, NULL, 'm' },
64
+ { NULL, 0, NULL, 0 }
65
+ };
66
+
67
+ int c;
68
+ while ((c = getopt_long(argc, argv, "hf:s:ceum", long_opts, NULL)) != -1)
69
+ {
70
+ switch (c)
71
+ {
72
+ case 'h':
73
+ print_usage_exit(0);
74
+ break;
75
+ case 'f':
76
+ args.filter = optarg;
77
+ break;
78
+ case 's':
79
+ args.separator = optarg;
80
+ break;
81
+ case 'c':
82
+ args.case_sensitive = true;
83
+ break;
84
+ case 'e':
85
+ args.self_time = true;
86
+ break;
87
+ case 'u':
88
+ args.unwrap = true;
89
+ break;
90
+ case 'm':
91
+ args.unwrapMessages = true;
92
+ break;
93
+ default:
94
+ print_usage_exit(1);
95
+ break;
96
+ }
97
+ }
98
+
99
+ if (argc != optind + 1)
100
+ {
101
+ print_usage_exit(1);
102
+ }
103
+
104
+ args.trace_file = argv[optind];
105
+
106
+ return args;
107
+ }
108
+
109
+ bool is_substring(
110
+ const char* term,
111
+ const char* s,
112
+ bool case_sensitive = false
113
+ ){
114
+ auto new_term = std::string(term);
115
+ auto new_s = std::string(s);
116
+
117
+ if (!case_sensitive) {
118
+ std::transform(
119
+ new_term.begin(),
120
+ new_term.end(),
121
+ new_term.begin(),
122
+ [](unsigned char c){ return std::tolower(c); }
123
+ );
124
+
125
+ std::transform(
126
+ new_s.begin(),
127
+ new_s.end(),
128
+ new_s.begin(),
129
+ [](unsigned char c){ return std::tolower(c); }
130
+ );
131
+ }
132
+
133
+ return new_s.find(new_term) != std::string::npos;
134
+ }
135
+
136
+ const char* get_name(int32_t id, const tracy::Worker& worker)
137
+ {
138
+ auto& srcloc = worker.GetSourceLocation(id);
139
+ return worker.GetString(srcloc.name.active ? srcloc.name : srcloc.function);
140
+ }
141
+
142
+ template <typename T>
143
+ std::string join(const T& v, const char* sep) {
144
+ std::ostringstream s;
145
+ for (const auto& i : v) {
146
+ if (&i != &v[0]) {
147
+ s << sep;
148
+ }
149
+ s << i;
150
+ }
151
+ return s.str();
152
+ }
153
+
154
+ // From TracyView.cpp
155
+ int64_t GetZoneChildTimeFast(
156
+ const tracy::Worker& worker,
157
+ const tracy::ZoneEvent& zone
158
+ ){
159
+ int64_t time = 0;
160
+ if( zone.HasChildren() )
161
+ {
162
+ auto& children = worker.GetZoneChildren( zone.Child() );
163
+ if( children.is_magic() )
164
+ {
165
+ auto& vec = *(tracy::Vector<tracy::ZoneEvent>*)&children;
166
+ for( auto& v : vec )
167
+ {
168
+ assert( v.IsEndValid() );
169
+ time += v.End() - v.Start();
170
+ }
171
+ }
172
+ else
173
+ {
174
+ for( auto& v : children )
175
+ {
176
+ assert( v->IsEndValid() );
177
+ time += v->End() - v->Start();
178
+ }
179
+ }
180
+ }
181
+ return time;
182
+ }
183
+
184
+ int main(int argc, char** argv)
185
+ {
186
+ #ifdef _WIN32
187
+ if (!AttachConsole(ATTACH_PARENT_PROCESS))
188
+ {
189
+ AllocConsole();
190
+ SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), 0x07);
191
+ }
192
+ #endif
193
+
194
+ Args args = parse_args(argc, argv);
195
+
196
+ auto f = std::unique_ptr<tracy::FileRead>(
197
+ tracy::FileRead::Open(args.trace_file)
198
+ );
199
+ if (!f)
200
+ {
201
+ fprintf(stderr, "Could not open file %s\n", args.trace_file);
202
+ return 1;
203
+ }
204
+
205
+ auto worker = tracy::Worker(*f);
206
+
207
+ if (args.unwrapMessages)
208
+ {
209
+ const auto& msgs = worker.GetMessages();
210
+
211
+ if (msgs.size() > 0)
212
+ {
213
+ std::vector<const char*> columnsForMessages;
214
+ columnsForMessages = {
215
+ "MessageName", "total_ns"
216
+ };
217
+ std::string headerForMessages = join(columnsForMessages, args.separator);
218
+ printf("%s\n", headerForMessages.data());
219
+
220
+ for(auto& it : msgs)
221
+ {
222
+ std::vector<std::string> values(columnsForMessages.size());
223
+
224
+ values[0] = worker.GetString(it->ref);
225
+ values[1] = std::to_string(it->time);
226
+
227
+ std::string row = join(values, args.separator);
228
+ printf("%s\n", row.data());
229
+ }
230
+ }
231
+ else
232
+ {
233
+ printf("There are currently no messages!\n");
234
+ }
235
+
236
+ return 0;
237
+ }
238
+
239
+ while (!worker.AreSourceLocationZonesReady())
240
+ {
241
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
242
+ }
243
+
244
+ auto& slz = worker.GetSourceLocationZones();
245
+ tracy::Vector<decltype(slz.begin())> slz_selected;
246
+ slz_selected.reserve(slz.size());
247
+
248
+ uint32_t total_cnt = 0;
249
+ for(auto it = slz.begin(); it != slz.end(); ++it)
250
+ {
251
+ if(it->second.total != 0)
252
+ {
253
+ ++total_cnt;
254
+ if(args.filter[0] == '\0')
255
+ {
256
+ slz_selected.push_back_no_space_check(it);
257
+ }
258
+ else
259
+ {
260
+ auto name = get_name(it->first, worker);
261
+ if(is_substring(args.filter, name, args.case_sensitive))
262
+ {
263
+ slz_selected.push_back_no_space_check(it);
264
+ }
265
+ }
266
+ }
267
+ }
268
+
269
+ std::vector<const char*> columns;
270
+ if (args.unwrap)
271
+ {
272
+ columns = {
273
+ "name", "src_file", "src_line", "ns_since_start", "exec_time_ns", "thread"
274
+ };
275
+ }
276
+ else
277
+ {
278
+ columns = {
279
+ "name", "src_file", "src_line", "total_ns", "total_perc",
280
+ "counts", "mean_ns", "min_ns", "max_ns", "std_ns"
281
+ };
282
+ }
283
+ std::string header = join(columns, args.separator);
284
+ printf("%s\n", header.data());
285
+
286
+ const auto last_time = worker.GetLastTime();
287
+ for(auto& it : slz_selected)
288
+ {
289
+ std::vector<std::string> values(columns.size());
290
+
291
+ values[0] = get_name(it->first, worker);
292
+
293
+ const auto& srcloc = worker.GetSourceLocation(it->first);
294
+ values[1] = worker.GetString(srcloc.file);
295
+ values[2] = std::to_string(srcloc.line);
296
+
297
+ const auto& zone_data = it->second;
298
+
299
+ if (args.unwrap)
300
+ {
301
+ int i = 0;
302
+ for (const auto& zone_thread_data : zone_data.zones) {
303
+ const auto zone_event = zone_thread_data.Zone();
304
+ const auto tId = zone_thread_data.Thread();
305
+ const auto start = zone_event->Start();
306
+ const auto end = zone_event->End();
307
+
308
+ values[3] = std::to_string(start);
309
+
310
+ auto timespan = end - start;
311
+ if (args.self_time) {
312
+ timespan -= GetZoneChildTimeFast(worker, *zone_event);
313
+ }
314
+ values[4] = std::to_string(timespan);
315
+ values[5] = std::to_string(tId);
316
+
317
+ std::string row = join(values, args.separator);
318
+ printf("%s\n", row.data());
319
+ }
320
+ }
321
+ else
322
+ {
323
+ const auto time = args.self_time ? zone_data.selfTotal : zone_data.total;
324
+ values[3] = std::to_string(time);
325
+ values[4] = std::to_string(100. * time / last_time);
326
+
327
+ values[5] = std::to_string(zone_data.zones.size());
328
+
329
+ const auto avg = (args.self_time ? zone_data.selfTotal : zone_data.total)
330
+ / zone_data.zones.size();
331
+ values[6] = std::to_string(avg);
332
+
333
+ const auto tmin = args.self_time ? zone_data.selfMin : zone_data.min;
334
+ const auto tmax = args.self_time ? zone_data.selfMax : zone_data.max;
335
+ values[7] = std::to_string(tmin);
336
+ values[8] = std::to_string(tmax);
337
+
338
+ const auto sz = zone_data.zones.size();
339
+ const auto ss = zone_data.sumSq
340
+ - 2. * zone_data.total * avg
341
+ + avg * avg * sz;
342
+ double std = 0;
343
+ if( sz > 1 )
344
+ std = sqrt(ss / (sz - 1));
345
+ values[9] = std::to_string(std);
346
+
347
+ std::string row = join(values, args.separator);
348
+ printf("%s\n", row.data());
349
+ }
350
+ }
351
+
352
+ return 0;
353
+ }
third_party/tracy/examples/OpenCLVectorAdd/CMakeLists.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cmake_minimum_required(VERSION 3.10)
2
+
3
+ project(OpenCLVectorAdd)
4
+
5
+ set(THREADS_PREFER_PTHREAD_FLAG ON)
6
+ find_package(Threads REQUIRED)
7
+
8
+ find_package(OpenCL REQUIRED)
9
+
10
+ add_executable(OpenCLVectorAdd OpenCLVectorAdd.cpp)
11
+
12
+ add_library(TracyClient STATIC ../../public/TracyClient.cpp
13
+ ../../public/tracy/TracyOpenCL.hpp)
14
+ target_include_directories(TracyClient PUBLIC ../../public/tracy)
15
+ target_compile_definitions(TracyClient PUBLIC TRACY_ENABLE=1)
16
+
17
+ target_link_libraries(OpenCLVectorAdd PUBLIC OpenCL::OpenCL TracyClient ${CMAKE_DL_LIBS} Threads::Threads)
third_party/tracy/examples/OpenCLVectorAdd/OpenCLVectorAdd.cpp ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include <algorithm>
2
+ #include <iostream>
3
+ #include <cassert>
4
+ #include <string>
5
+ #include <vector>
6
+ #include <numeric>
7
+
8
+ #include <CL/cl.h>
9
+
10
+ #include <Tracy.hpp>
11
+ #include <TracyOpenCL.hpp>
12
+
13
+ #define CL_ASSERT(err) \
14
+ if((err) != CL_SUCCESS) \
15
+ { \
16
+ std::cerr << "OpenCL Call Returned " << err << std::endl; \
17
+ assert(false); \
18
+ }
19
+
20
+ const char kernelSource[] =
21
+ " void __kernel vectorAdd(global float* C, global float* A, global float* B, int N) "
22
+ " { "
23
+ " int i = get_global_id(0); "
24
+ " if (i < N) { "
25
+ " C[i] = A[i] + B[i]; "
26
+ " } "
27
+ " } ";
28
+
29
+ int main()
30
+ {
31
+ cl_platform_id platform;
32
+ cl_device_id device;
33
+ cl_context context;
34
+ cl_command_queue commandQueue;
35
+ cl_kernel vectorAddKernel;
36
+ cl_program program;
37
+ cl_int err;
38
+ cl_mem bufferA, bufferB, bufferC;
39
+
40
+ TracyCLCtx tracyCLCtx;
41
+
42
+ {
43
+ ZoneScopedN("OpenCL Init");
44
+
45
+ cl_uint numPlatforms = 0;
46
+ CL_ASSERT(clGetPlatformIDs(0, nullptr, &numPlatforms));
47
+
48
+ if (numPlatforms == 0)
49
+ {
50
+ std::cerr << "Cannot find OpenCL platform to run this application" << std::endl;
51
+ return 1;
52
+ }
53
+
54
+ CL_ASSERT(clGetPlatformIDs(1, &platform, nullptr));
55
+
56
+ size_t platformNameBufferSize = 0;
57
+ CL_ASSERT(clGetPlatformInfo(platform, CL_PLATFORM_NAME, 0, nullptr, &platformNameBufferSize));
58
+ std::string platformName(platformNameBufferSize, '\0');
59
+ CL_ASSERT(clGetPlatformInfo(platform, CL_PLATFORM_NAME, platformNameBufferSize, &platformName[0], nullptr));
60
+
61
+ std::cout << "OpenCL Platform: " << platformName << std::endl;
62
+
63
+ CL_ASSERT(clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 1, &device, nullptr));
64
+ size_t deviceNameBufferSize = 0;
65
+ CL_ASSERT(clGetDeviceInfo(device, CL_DEVICE_NAME, 0, nullptr, &deviceNameBufferSize));
66
+ std::string deviceName(deviceNameBufferSize, '\0');
67
+ CL_ASSERT(clGetDeviceInfo(device, CL_DEVICE_NAME, deviceNameBufferSize, &deviceName[0], nullptr));
68
+
69
+ std::cout << "OpenCL Device: " << deviceName << std::endl;
70
+
71
+ err = CL_SUCCESS;
72
+ context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
73
+ CL_ASSERT(err);
74
+
75
+ size_t kernelSourceLength = sizeof(kernelSource);
76
+ const char* kernelSourceArray = { kernelSource };
77
+ program = clCreateProgramWithSource(context, 1, &kernelSourceArray, &kernelSourceLength, &err);
78
+ CL_ASSERT(err);
79
+
80
+ if (clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr) != CL_SUCCESS)
81
+ {
82
+ size_t programBuildLogBufferSize = 0;
83
+ CL_ASSERT(clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &programBuildLogBufferSize));
84
+ std::string programBuildLog(programBuildLogBufferSize, '\0');
85
+ CL_ASSERT(clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, programBuildLogBufferSize, &programBuildLog[0], nullptr));
86
+ std::clog << programBuildLog << std::endl;
87
+ return 1;
88
+ }
89
+
90
+ vectorAddKernel = clCreateKernel(program, "vectorAdd", &err);
91
+ CL_ASSERT(err);
92
+
93
+ commandQueue = clCreateCommandQueue(context, device, CL_QUEUE_PROFILING_ENABLE, &err);
94
+ CL_ASSERT(err);
95
+ }
96
+
97
+ tracyCLCtx = TracyCLContext(context, device);
98
+
99
+ size_t N = 10 * 1024 * 1024 / sizeof(float); // 10MB of floats
100
+ std::vector<float> hostA, hostB, hostC;
101
+
102
+ {
103
+ ZoneScopedN("Host Data Init");
104
+ hostA.resize(N);
105
+ hostB.resize(N);
106
+ hostC.resize(N);
107
+
108
+ std::iota(std::begin(hostA), std::end(hostA), 0.0f);
109
+ std::iota(std::begin(hostB), std::end(hostB), 0.0f);
110
+ }
111
+
112
+ {
113
+ ZoneScopedN("Host to Device Memory Copy");
114
+
115
+ bufferA = clCreateBuffer(context, CL_MEM_READ_WRITE, N * sizeof(float), nullptr, &err);
116
+ CL_ASSERT(err);
117
+ bufferB = clCreateBuffer(context, CL_MEM_READ_WRITE, N * sizeof(float), nullptr, &err);
118
+ CL_ASSERT(err);
119
+ bufferC = clCreateBuffer(context, CL_MEM_READ_WRITE, N * sizeof(float), nullptr, &err);
120
+ CL_ASSERT(err);
121
+
122
+ cl_event writeBufferAEvent, writeBufferBEvent;
123
+ {
124
+ ZoneScopedN("Write Buffer A");
125
+ TracyCLZoneS(tracyCLCtx, "Write BufferA", 5);
126
+
127
+ CL_ASSERT(clEnqueueWriteBuffer(commandQueue, bufferA, CL_FALSE, 0, N * sizeof(float), hostA.data(), 0, nullptr, &writeBufferAEvent));
128
+
129
+ TracyCLZoneSetEvent(writeBufferAEvent);
130
+ }
131
+ {
132
+ ZoneScopedN("Write Buffer B");
133
+ TracyCLZone(tracyCLCtx, "Write BufferB");
134
+
135
+ CL_ASSERT(clEnqueueWriteBuffer(commandQueue, bufferB, CL_FALSE, 0, N * sizeof(float), hostB.data(), 0, nullptr, &writeBufferBEvent));
136
+
137
+ TracyCLZoneSetEvent(writeBufferBEvent);
138
+ }
139
+ }
140
+
141
+ cl_int clN = static_cast<cl_int>(N);
142
+ const int numFrames = 10;
143
+ const int launchsPerFrame = 10;
144
+ constexpr int numLaunchs = numFrames * launchsPerFrame;
145
+ std::vector<cl_event> kernelLaunchEvts;
146
+ kernelLaunchEvts.reserve(numLaunchs);
147
+ for (int i = 0; i < numFrames; ++i)
148
+ {
149
+ FrameMark;
150
+ for (int j = 0; j < launchsPerFrame; ++j) {
151
+ ZoneScopedN("VectorAdd Kernel Launch");
152
+ TracyCLZoneC(tracyCLCtx, "VectorAdd Kernel", tracy::Color::Blue4);
153
+
154
+ CL_ASSERT(clSetKernelArg(vectorAddKernel, 0, sizeof(cl_mem), &bufferC));
155
+ CL_ASSERT(clSetKernelArg(vectorAddKernel, 1, sizeof(cl_mem), &bufferA));
156
+ CL_ASSERT(clSetKernelArg(vectorAddKernel, 2, sizeof(cl_mem), &bufferB));
157
+ CL_ASSERT(clSetKernelArg(vectorAddKernel, 3, sizeof(cl_int), &clN));
158
+
159
+ cl_event vectorAddKernelEvent;
160
+ CL_ASSERT(clEnqueueNDRangeKernel(commandQueue, vectorAddKernel, 1, nullptr, &N, nullptr, 0, nullptr, &vectorAddKernelEvent));
161
+ TracyCLZoneSetEvent(vectorAddKernelEvent);
162
+ CL_ASSERT(clRetainEvent(vectorAddKernelEvent));
163
+ kernelLaunchEvts.push_back(vectorAddKernelEvent);
164
+ std::cout << "VectorAdd Kernel Enqueued" << std::endl;
165
+ }
166
+ {
167
+ // Wait frame events to be finished
168
+ ZoneScopedN("clFinish");
169
+ CL_ASSERT(clFinish(commandQueue));
170
+ }
171
+ // You should collect on each 'frame' ends, so that streaming can be achieved.
172
+ TracyCLCollect(tracyCLCtx);
173
+ }
174
+
175
+ {
176
+ ZoneScopedN("Device to Host Memory Copy");
177
+ TracyCLZone(tracyCLCtx, "Read Buffer C");
178
+
179
+ cl_event readbufferCEvent;
180
+ CL_ASSERT(clEnqueueReadBuffer(commandQueue, bufferC, CL_TRUE, 0, N * sizeof(float), hostC.data(), 0, nullptr, &readbufferCEvent));
181
+ TracyCLZoneSetEvent(readbufferCEvent);
182
+ }
183
+
184
+ CL_ASSERT(clFinish(commandQueue));
185
+ std::vector<float> durations(kernelLaunchEvts.size());
186
+ for (int i=0; i<kernelLaunchEvts.size(); i++) {
187
+ cl_event evt = kernelLaunchEvts[i];
188
+ cl_ulong start;
189
+ cl_ulong end;
190
+ CL_ASSERT(clGetEventProfilingInfo(evt, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, nullptr));
191
+ CL_ASSERT(clGetEventProfilingInfo(evt, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, nullptr));
192
+ CL_ASSERT(clReleaseEvent(evt));
193
+ durations[i] = (end - start) * 0.001f;
194
+ std::cout << "VectorAdd Kernel " << i << " tooks " << static_cast<int>(durations[i]) << "us" << std::endl;
195
+ };
196
+ float avg = std::accumulate(durations.cbegin(), durations.cend(), 0.0f) / durations.size();
197
+ float stddev2 = std::accumulate(durations.cbegin(), durations.cend(), 0.0f, [avg](const float& acc, const float& v) {
198
+ auto d = v - avg;
199
+ return acc + d*d;
200
+ }) / (durations.size() - 1.0f);
201
+ std::cout << "VectorAdd runtime avg: " << avg << "us, std: " << sqrt(stddev2) << "us over " << numLaunchs << " runs." << std::endl;
202
+
203
+ // User should ensure all events are finished, in this case, collect after the clFinish will do the trick.
204
+ TracyCLCollect(tracyCLCtx);
205
+
206
+ {
207
+ ZoneScopedN("Checking results");
208
+
209
+ for (int i = 0; i < N; ++i)
210
+ {
211
+ assert(hostC[i] == hostA[i] + hostB[i]);
212
+ }
213
+ }
214
+
215
+ std::cout << "Results are correct!" << std::endl;
216
+
217
+ TracyCLDestroy(tracyCLCtx);
218
+
219
+ return 0;
220
+ }
third_party/tracy/examples/ToyPathTracer/.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ Windows/Compiled*Shader.h
third_party/tracy/examples/ToyPathTracer/README ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ https://github.com/aras-p/ToyPathTracer
2
+
3
+ Modified to render only 10 frames. Client part requires 12 GB, server part
4
+ requires 6.4 GB.
third_party/tracy/examples/ToyPathTracer/Source/Config.h ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ #if defined(__APPLE__) && !defined(__METAL_VERSION__)
3
+ #include <TargetConditionals.h>
4
+ #endif
5
+
6
+ #define kBackbufferWidth 1280
7
+ #define kBackbufferHeight 720
8
+
9
+ #if defined(__EMSCRIPTEN__)
10
+ #define CPU_CAN_DO_SIMD 0
11
+ #define CPU_CAN_DO_THREADS 0
12
+ #else
13
+ #define CPU_CAN_DO_SIMD 1
14
+ #define CPU_CAN_DO_THREADS 1
15
+ #endif
16
+
17
+
18
+ #define DO_SAMPLES_PER_PIXEL 4
19
+ #define DO_ANIMATE_SMOOTHING 0.9f
20
+ #define DO_LIGHT_SAMPLING 1
21
+ #define DO_MITSUBA_COMPARE 0
22
+
23
+ // Should path tracing be done on the GPU with a compute shader?
24
+ #define DO_COMPUTE_GPU 0
25
+ #define kCSGroupSizeX 8
26
+ #define kCSGroupSizeY 8
27
+ #define kCSMaxObjects 64
28
+
29
+ // Should float3 struct use SSE/NEON?
30
+ #define DO_FLOAT3_WITH_SIMD (!(DO_COMPUTE_GPU) && CPU_CAN_DO_SIMD && 1)
31
+
32
+ // Should HitSpheres function use SSE/NEON?
33
+ #define DO_HIT_SPHERES_SIMD (CPU_CAN_DO_SIMD && 1)
third_party/tracy/examples/ToyPathTracer/Source/MathSimd.h ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+
3
+ #if defined(_MSC_VER)
4
+ #define VM_INLINE __forceinline
5
+ #else
6
+ #define VM_INLINE __attribute__((unused, always_inline, nodebug)) inline
7
+ #endif
8
+
9
+ #define kSimdWidth 4
10
+
11
+ #if !defined(__arm__) && !defined(__arm64__) && !defined(__EMSCRIPTEN__)
12
+
13
+ // ---- SSE implementation
14
+
15
+ #include <xmmintrin.h>
16
+ #include <emmintrin.h>
17
+ #include <smmintrin.h>
18
+
19
+ #define SHUFFLE4(V, X,Y,Z,W) float4(_mm_shuffle_ps((V).m, (V).m, _MM_SHUFFLE(W,Z,Y,X)))
20
+
21
+ struct float4
22
+ {
23
+ VM_INLINE float4() {}
24
+ VM_INLINE explicit float4(const float *p) { m = _mm_loadu_ps(p); }
25
+ VM_INLINE explicit float4(float x, float y, float z, float w) { m = _mm_set_ps(w, z, y, x); }
26
+ VM_INLINE explicit float4(float v) { m = _mm_set_ps1(v); }
27
+ VM_INLINE explicit float4(__m128 v) { m = v; }
28
+
29
+ VM_INLINE float getX() const { return _mm_cvtss_f32(m); }
30
+ VM_INLINE float getY() const { return _mm_cvtss_f32(_mm_shuffle_ps(m, m, _MM_SHUFFLE(1, 1, 1, 1))); }
31
+ VM_INLINE float getZ() const { return _mm_cvtss_f32(_mm_shuffle_ps(m, m, _MM_SHUFFLE(2, 2, 2, 2))); }
32
+ VM_INLINE float getW() const { return _mm_cvtss_f32(_mm_shuffle_ps(m, m, _MM_SHUFFLE(3, 3, 3, 3))); }
33
+
34
+ __m128 m;
35
+ };
36
+
37
+ typedef float4 bool4;
38
+
39
+ VM_INLINE float4 operator+ (float4 a, float4 b) { a.m = _mm_add_ps(a.m, b.m); return a; }
40
+ VM_INLINE float4 operator- (float4 a, float4 b) { a.m = _mm_sub_ps(a.m, b.m); return a; }
41
+ VM_INLINE float4 operator* (float4 a, float4 b) { a.m = _mm_mul_ps(a.m, b.m); return a; }
42
+ VM_INLINE bool4 operator==(float4 a, float4 b) { a.m = _mm_cmpeq_ps(a.m, b.m); return a; }
43
+ VM_INLINE bool4 operator!=(float4 a, float4 b) { a.m = _mm_cmpneq_ps(a.m, b.m); return a; }
44
+ VM_INLINE bool4 operator< (float4 a, float4 b) { a.m = _mm_cmplt_ps(a.m, b.m); return a; }
45
+ VM_INLINE bool4 operator> (float4 a, float4 b) { a.m = _mm_cmpgt_ps(a.m, b.m); return a; }
46
+ VM_INLINE bool4 operator<=(float4 a, float4 b) { a.m = _mm_cmple_ps(a.m, b.m); return a; }
47
+ VM_INLINE bool4 operator>=(float4 a, float4 b) { a.m = _mm_cmpge_ps(a.m, b.m); return a; }
48
+ VM_INLINE bool4 operator&(bool4 a, bool4 b) { a.m = _mm_and_ps(a.m, b.m); return a; }
49
+ VM_INLINE bool4 operator|(bool4 a, bool4 b) { a.m = _mm_or_ps(a.m, b.m); return a; }
50
+ VM_INLINE float4 operator- (float4 a) { a.m = _mm_xor_ps(a.m, _mm_set1_ps(-0.0f)); return a; }
51
+ VM_INLINE float4 min(float4 a, float4 b) { a.m = _mm_min_ps(a.m, b.m); return a; }
52
+ VM_INLINE float4 max(float4 a, float4 b) { a.m = _mm_max_ps(a.m, b.m); return a; }
53
+
54
+ VM_INLINE float hmin(float4 v)
55
+ {
56
+ v = min(v, SHUFFLE4(v, 2, 3, 0, 0));
57
+ v = min(v, SHUFFLE4(v, 1, 0, 0, 0));
58
+ return v.getX();
59
+ }
60
+
61
+ // Returns a 4-bit code where bit0..bit3 is X..W
62
+ VM_INLINE unsigned mask(float4 v) { return _mm_movemask_ps(v.m); }
63
+ // Once we have a comparison, we can branch based on its results:
64
+ VM_INLINE bool any(bool4 v) { return mask(v) != 0; }
65
+ VM_INLINE bool all(bool4 v) { return mask(v) == 15; }
66
+
67
+ // "select", i.e. hibit(cond) ? b : a
68
+ // on SSE4.1 and up this can be done easily via "blend" instruction;
69
+ // on older SSEs has to do a bunch of hoops, see
70
+ // https://fgiesen.wordpress.com/2016/04/03/sse-mind-the-gap/
71
+
72
+ VM_INLINE float4 select(float4 a, float4 b, bool4 cond)
73
+ {
74
+ #if defined(__SSE4_1__) || defined(_MSC_VER) // on windows assume we always have SSE4.1
75
+ a.m = _mm_blendv_ps(a.m, b.m, cond.m);
76
+ #else
77
+ __m128 d = _mm_castsi128_ps(_mm_srai_epi32(_mm_castps_si128(cond.m), 31));
78
+ a.m = _mm_or_ps(_mm_and_ps(d, b.m), _mm_andnot_ps(d, a.m));
79
+ #endif
80
+ return a;
81
+ }
82
+ VM_INLINE __m128i select(__m128i a, __m128i b, bool4 cond)
83
+ {
84
+ #if defined(__SSE4_1__) || defined(_MSC_VER) // on windows assume we always have SSE4.1
85
+ return _mm_blendv_epi8(a, b, _mm_castps_si128(cond.m));
86
+ #else
87
+ __m128i d = _mm_srai_epi32(_mm_castps_si128(cond.m), 31);
88
+ return _mm_or_si128(_mm_and_si128(d, b), _mm_andnot_si128(d, a));
89
+ #endif
90
+ }
91
+
92
+ VM_INLINE float4 sqrtf(float4 v) { return float4(_mm_sqrt_ps(v.m)); }
93
+
94
+ #elif !defined(__EMSCRIPTEN__)
95
+
96
+ // ---- NEON implementation
97
+
98
+ #define USE_NEON 1
99
+ #include <arm_neon.h>
100
+
101
+ struct float4
102
+ {
103
+ VM_INLINE float4() {}
104
+ VM_INLINE explicit float4(const float *p) { m = vld1q_f32(p); }
105
+ VM_INLINE explicit float4(float x, float y, float z, float w) { float v[4] = {x, y, z, w}; m = vld1q_f32(v); }
106
+ VM_INLINE explicit float4(float v) { m = vdupq_n_f32(v); }
107
+ VM_INLINE explicit float4(float32x4_t v) { m = v; }
108
+
109
+ VM_INLINE float getX() const { return vgetq_lane_f32(m, 0); }
110
+ VM_INLINE float getY() const { return vgetq_lane_f32(m, 1); }
111
+ VM_INLINE float getZ() const { return vgetq_lane_f32(m, 2); }
112
+ VM_INLINE float getW() const { return vgetq_lane_f32(m, 3); }
113
+
114
+ float32x4_t m;
115
+ };
116
+
117
+ typedef float4 bool4;
118
+
119
+ VM_INLINE float4 operator+ (float4 a, float4 b) { a.m = vaddq_f32(a.m, b.m); return a; }
120
+ VM_INLINE float4 operator- (float4 a, float4 b) { a.m = vsubq_f32(a.m, b.m); return a; }
121
+ VM_INLINE float4 operator* (float4 a, float4 b) { a.m = vmulq_f32(a.m, b.m); return a; }
122
+ VM_INLINE bool4 operator==(float4 a, float4 b) { a.m = vceqq_f32(a.m, b.m); return a; }
123
+ VM_INLINE bool4 operator!=(float4 a, float4 b) { a.m = a.m = vmvnq_u32(vceqq_f32(a.m, b.m)); return a; }
124
+ VM_INLINE bool4 operator< (float4 a, float4 b) { a.m = vcltq_f32(a.m, b.m); return a; }
125
+ VM_INLINE bool4 operator> (float4 a, float4 b) { a.m = vcgtq_f32(a.m, b.m); return a; }
126
+ VM_INLINE bool4 operator<=(float4 a, float4 b) { a.m = vcleq_f32(a.m, b.m); return a; }
127
+ VM_INLINE bool4 operator>=(float4 a, float4 b) { a.m = vcgeq_f32(a.m, b.m); return a; }
128
+ VM_INLINE bool4 operator&(bool4 a, bool4 b) { a.m = vandq_u32(a.m, b.m); return a; }
129
+ VM_INLINE bool4 operator|(bool4 a, bool4 b) { a.m = vorrq_u32(a.m, b.m); return a; }
130
+ VM_INLINE float4 operator- (float4 a) { a.m = vnegq_f32(a.m); return a; }
131
+ VM_INLINE float4 min(float4 a, float4 b) { a.m = vminq_f32(a.m, b.m); return a; }
132
+ VM_INLINE float4 max(float4 a, float4 b) { a.m = vmaxq_f32(a.m, b.m); return a; }
133
+
134
+ VM_INLINE float hmin(float4 v)
135
+ {
136
+ float32x2_t minOfHalfs = vpmin_f32(vget_low_f32(v.m), vget_high_f32(v.m));
137
+ float32x2_t minOfMinOfHalfs = vpmin_f32(minOfHalfs, minOfHalfs);
138
+ return vget_lane_f32(minOfMinOfHalfs, 0);
139
+ }
140
+
141
+ // Returns a 4-bit code where bit0..bit3 is X..W
142
+ VM_INLINE unsigned mask(float4 v)
143
+ {
144
+ static const uint32x4_t movemask = { 1, 2, 4, 8 };
145
+ static const uint32x4_t highbit = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
146
+ uint32x4_t t0 = vreinterpretq_u32_f32(v.m);
147
+ uint32x4_t t1 = vtstq_u32(t0, highbit);
148
+ uint32x4_t t2 = vandq_u32(t1, movemask);
149
+ uint32x2_t t3 = vorr_u32(vget_low_u32(t2), vget_high_u32(t2));
150
+ return vget_lane_u32(t3, 0) | vget_lane_u32(t3, 1);
151
+ }
152
+ // Once we have a comparison, we can branch based on its results:
153
+ VM_INLINE bool any(bool4 v) { return mask(v) != 0; }
154
+ VM_INLINE bool all(bool4 v) { return mask(v) == 15; }
155
+
156
+ // "select", i.e. hibit(cond) ? b : a
157
+ // on SSE4.1 and up this can be done easily via "blend" instruction;
158
+ // on older SSEs has to do a bunch of hoops, see
159
+ // https://fgiesen.wordpress.com/2016/04/03/sse-mind-the-gap/
160
+
161
+ VM_INLINE float4 select(float4 a, float4 b, bool4 cond)
162
+ {
163
+ a.m = vbslq_f32(cond.m, b.m, a.m);
164
+ return a;
165
+ }
166
+ VM_INLINE int32x4_t select(int32x4_t a, int32x4_t b, bool4 cond)
167
+ {
168
+ return vbslq_f32(cond.m, b, a);
169
+ }
170
+
171
+ VM_INLINE float4 sqrtf(float4 v)
172
+ {
173
+ float32x4_t V = v.m;
174
+ float32x4_t S0 = vrsqrteq_f32(V);
175
+ float32x4_t P0 = vmulq_f32( V, S0 );
176
+ float32x4_t R0 = vrsqrtsq_f32( P0, S0 );
177
+ float32x4_t S1 = vmulq_f32( S0, R0 );
178
+ float32x4_t P1 = vmulq_f32( V, S1 );
179
+ float32x4_t R1 = vrsqrtsq_f32( P1, S1 );
180
+ float32x4_t S2 = vmulq_f32( S1, R1 );
181
+ float32x4_t P2 = vmulq_f32( V, S2 );
182
+ float32x4_t R2 = vrsqrtsq_f32( P2, S2 );
183
+ float32x4_t S3 = vmulq_f32( S2, R2 );
184
+ return float4(vmulq_f32(V, S3));
185
+ }
186
+
187
+ VM_INLINE float4 splatX(float32x4_t v) { return float4(vdupq_lane_f32(vget_low_f32(v), 0)); }
188
+ VM_INLINE float4 splatY(float32x4_t v) { return float4(vdupq_lane_f32(vget_low_f32(v), 1)); }
189
+ VM_INLINE float4 splatZ(float32x4_t v) { return float4(vdupq_lane_f32(vget_high_f32(v), 0)); }
190
+ VM_INLINE float4 splatW(float32x4_t v) { return float4(vdupq_lane_f32(vget_high_f32(v), 1)); }
191
+
192
+ #endif
third_party/tracy/examples/ToyPathTracer/Source/Maths.cpp ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "Maths.h"
2
+ #include <stdlib.h>
3
+ #include <stdint.h>
4
+
5
+ static uint32_t XorShift32(uint32_t& state)
6
+ {
7
+ uint32_t x = state;
8
+ x ^= x << 13;
9
+ x ^= x >> 17;
10
+ x ^= x << 15;
11
+ state = x;
12
+ return x;
13
+ }
14
+
15
+ float RandomFloat01(uint32_t& state)
16
+ {
17
+ return (XorShift32(state) & 0xFFFFFF) / 16777216.0f;
18
+ }
19
+
20
+ float3 RandomInUnitDisk(uint32_t& state)
21
+ {
22
+ float3 p;
23
+ do
24
+ {
25
+ p = 2.0 * float3(RandomFloat01(state),RandomFloat01(state),0) - float3(1,1,0);
26
+ } while (dot(p,p) >= 1.0);
27
+ return p;
28
+ }
29
+
30
+ float3 RandomInUnitSphere(uint32_t& state)
31
+ {
32
+ float3 p;
33
+ do {
34
+ p = 2.0*float3(RandomFloat01(state),RandomFloat01(state),RandomFloat01(state)) - float3(1,1,1);
35
+ } while (sqLength(p) >= 1.0);
36
+ return p;
37
+ }
38
+
39
+ float3 RandomUnitVector(uint32_t& state)
40
+ {
41
+ float z = RandomFloat01(state) * 2.0f - 1.0f;
42
+ float a = RandomFloat01(state) * 2.0f * kPI;
43
+ float r = sqrtf(1.0f - z * z);
44
+ float x = r * cosf(a);
45
+ float y = r * sinf(a);
46
+ return float3(x, y, z);
47
+ }
48
+
49
+
50
+ int HitSpheres(const Ray& r, const SpheresSoA& spheres, float tMin, float tMax, Hit& outHit)
51
+ {
52
+ #if DO_HIT_SPHERES_SIMD
53
+ float4 hitT = float4(tMax);
54
+ #if USE_NEON
55
+ int32x4_t id = vdupq_n_s32(-1);
56
+ #else
57
+ __m128i id = _mm_set1_epi32(-1);
58
+ #endif
59
+
60
+ #if DO_FLOAT3_WITH_SIMD && !USE_NEON
61
+ float4 rOrigX = SHUFFLE4(r.orig, 0, 0, 0, 0);
62
+ float4 rOrigY = SHUFFLE4(r.orig, 1, 1, 1, 1);
63
+ float4 rOrigZ = SHUFFLE4(r.orig, 2, 2, 2, 2);
64
+ float4 rDirX = SHUFFLE4(r.dir, 0, 0, 0, 0);
65
+ float4 rDirY = SHUFFLE4(r.dir, 1, 1, 1, 1);
66
+ float4 rDirZ = SHUFFLE4(r.dir, 2, 2, 2, 2);
67
+ #elif DO_FLOAT3_WITH_SIMD
68
+ float4 rOrigX = splatX(r.orig.m);
69
+ float4 rOrigY = splatY(r.orig.m);
70
+ float4 rOrigZ = splatZ(r.orig.m);
71
+ float4 rDirX = splatX(r.dir.m);
72
+ float4 rDirY = splatY(r.dir.m);
73
+ float4 rDirZ = splatZ(r.dir.m);
74
+ #else
75
+ float4 rOrigX = float4(r.orig.x);
76
+ float4 rOrigY = float4(r.orig.y);
77
+ float4 rOrigZ = float4(r.orig.z);
78
+ float4 rDirX = float4(r.dir.x);
79
+ float4 rDirY = float4(r.dir.y);
80
+ float4 rDirZ = float4(r.dir.z);
81
+ #endif
82
+ float4 tMin4 = float4(tMin);
83
+ #if USE_NEON
84
+ int32x4_t curId = vcombine_u32(vcreate_u32(0ULL | (1ULL<<32)), vcreate_u32(2ULL | (3ULL<<32)));
85
+ #else
86
+ __m128i curId = _mm_set_epi32(3, 2, 1, 0);
87
+ #endif
88
+ // process 4 spheres at once
89
+ for (int i = 0; i < spheres.simdCount; i += kSimdWidth)
90
+ {
91
+ // load data for 4 spheres
92
+ float4 sCenterX = float4(spheres.centerX + i);
93
+ float4 sCenterY = float4(spheres.centerY + i);
94
+ float4 sCenterZ = float4(spheres.centerZ + i);
95
+ float4 sSqRadius = float4(spheres.sqRadius + i);
96
+ // note: we flip this vector and calculate -b (nb) since that happens to be slightly preferable computationally
97
+ float4 coX = sCenterX - rOrigX;
98
+ float4 coY = sCenterY - rOrigY;
99
+ float4 coZ = sCenterZ - rOrigZ;
100
+ float4 nb = coX * rDirX + coY * rDirY + coZ * rDirZ;
101
+ float4 c = coX * coX + coY * coY + coZ * coZ - sSqRadius;
102
+ float4 discr = nb * nb - c;
103
+ bool4 discrPos = discr > float4(0.0f);
104
+ // if ray hits any of the 4 spheres
105
+ if (any(discrPos))
106
+ {
107
+ float4 discrSq = sqrtf(discr);
108
+
109
+ // ray could hit spheres at t0 & t1
110
+ float4 t0 = nb - discrSq;
111
+ float4 t1 = nb + discrSq;
112
+
113
+ float4 t = select(t1, t0, t0 > tMin4); // if t0 is above min, take it (since it's the earlier hit); else try t1.
114
+ bool4 msk = discrPos & (t > tMin4) & (t < hitT);
115
+ // if hit, take it
116
+ id = select(id, curId, msk);
117
+ hitT = select(hitT, t, msk);
118
+ }
119
+ #if USE_NEON
120
+ curId = vaddq_s32(curId, vdupq_n_s32(kSimdWidth));
121
+ #else
122
+ curId = _mm_add_epi32(curId, _mm_set1_epi32(kSimdWidth));
123
+ #endif
124
+ }
125
+ // now we have up to 4 hits, find and return closest one
126
+ float minT = hmin(hitT);
127
+ if (minT < tMax) // any actual hits?
128
+ {
129
+ int minMask = mask(hitT == float4(minT));
130
+ if (minMask != 0)
131
+ {
132
+ int id_scalar[4];
133
+ float hitT_scalar[4];
134
+ #if USE_NEON
135
+ vst1q_s32(id_scalar, id);
136
+ vst1q_f32(hitT_scalar, hitT.m);
137
+ #else
138
+ _mm_storeu_si128((__m128i *)id_scalar, id);
139
+ _mm_storeu_ps(hitT_scalar, hitT.m);
140
+ #endif
141
+
142
+ // In general, you would do this with a bit scan (first set/trailing zero count).
143
+ // But who cares, it's only 16 options.
144
+ static const int laneId[16] =
145
+ {
146
+ 0, 0, 1, 0, // 00xx
147
+ 2, 0, 1, 0, // 01xx
148
+ 3, 0, 1, 0, // 10xx
149
+ 2, 0, 1, 0, // 11xx
150
+ };
151
+
152
+ int lane = laneId[minMask];
153
+ int hitId = id_scalar[lane];
154
+ float finalHitT = hitT_scalar[lane];
155
+
156
+ outHit.pos = r.pointAt(finalHitT);
157
+ outHit.normal = (outHit.pos - float3(spheres.centerX[hitId], spheres.centerY[hitId], spheres.centerZ[hitId])) * spheres.invRadius[hitId];
158
+ outHit.t = finalHitT;
159
+ return hitId;
160
+ }
161
+ }
162
+
163
+ return -1;
164
+
165
+ #else // #if DO_HIT_SPHERES_SIMD
166
+
167
+ float hitT = tMax;
168
+ int id = -1;
169
+ for (int i = 0; i < spheres.count; ++i)
170
+ {
171
+ float coX = spheres.centerX[i] - r.orig.getX();
172
+ float coY = spheres.centerY[i] - r.orig.getY();
173
+ float coZ = spheres.centerZ[i] - r.orig.getZ();
174
+ float nb = coX * r.dir.getX() + coY * r.dir.getY() + coZ * r.dir.getZ();
175
+ float c = coX * coX + coY * coY + coZ * coZ - spheres.sqRadius[i];
176
+ float discr = nb * nb - c;
177
+ if (discr > 0)
178
+ {
179
+ float discrSq = sqrtf(discr);
180
+
181
+ // Try earlier t
182
+ float t = nb - discrSq;
183
+ if (t <= tMin) // before min, try later t!
184
+ t = nb + discrSq;
185
+
186
+ if (t > tMin && t < hitT)
187
+ {
188
+ id = i;
189
+ hitT = t;
190
+ }
191
+ }
192
+ }
193
+ if (id != -1)
194
+ {
195
+ outHit.pos = r.pointAt(hitT);
196
+ outHit.normal = (outHit.pos - float3(spheres.centerX[id], spheres.centerY[id], spheres.centerZ[id])) * spheres.invRadius[id];
197
+ outHit.t = hitT;
198
+ return id;
199
+ }
200
+ else
201
+ return -1;
202
+ #endif // #else of #if DO_HIT_SPHERES_SIMD
203
+ }
third_party/tracy/examples/ToyPathTracer/Source/Maths.h ADDED
@@ -0,0 +1,436 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+
3
+ #include <math.h>
4
+ #include <assert.h>
5
+ #include <stdint.h>
6
+ #include "Config.h"
7
+ #include "MathSimd.h"
8
+
9
+ #define kPI 3.1415926f
10
+
11
+ // SSE/SIMD vector largely based on http://www.codersnotes.com/notes/maths-lib-2016/
12
+ #if DO_FLOAT3_WITH_SIMD
13
+
14
+
15
+ #if !defined(__arm__) && !defined(__arm64__)
16
+
17
+ // ---- SSE implementation
18
+
19
+ // SHUFFLE3(v, 0,1,2) leaves the vector unchanged (v.xyz).
20
+ // SHUFFLE3(v, 0,0,0) splats the X (v.xxx).
21
+ #define SHUFFLE3(V, X,Y,Z) float3(_mm_shuffle_ps((V).m, (V).m, _MM_SHUFFLE(Z,Z,Y,X)))
22
+
23
+ struct float3
24
+ {
25
+ VM_INLINE float3() {}
26
+ VM_INLINE explicit float3(const float *p) { m = _mm_set_ps(p[2], p[2], p[1], p[0]); }
27
+ VM_INLINE explicit float3(float x, float y, float z) { m = _mm_set_ps(z, z, y, x); }
28
+ VM_INLINE explicit float3(float v) { m = _mm_set1_ps(v); }
29
+ VM_INLINE explicit float3(__m128 v) { m = v; }
30
+
31
+ VM_INLINE float getX() const { return _mm_cvtss_f32(m); }
32
+ VM_INLINE float getY() const { return _mm_cvtss_f32(_mm_shuffle_ps(m, m, _MM_SHUFFLE(1, 1, 1, 1))); }
33
+ VM_INLINE float getZ() const { return _mm_cvtss_f32(_mm_shuffle_ps(m, m, _MM_SHUFFLE(2, 2, 2, 2))); }
34
+
35
+ VM_INLINE float3 yzx() const { return SHUFFLE3(*this, 1, 2, 0); }
36
+ VM_INLINE float3 zxy() const { return SHUFFLE3(*this, 2, 0, 1); }
37
+
38
+ VM_INLINE void store(float *p) const { p[0] = getX(); p[1] = getY(); p[2] = getZ(); }
39
+
40
+ void setX(float x)
41
+ {
42
+ m = _mm_move_ss(m, _mm_set_ss(x));
43
+ }
44
+ void setY(float y)
45
+ {
46
+ __m128 t = _mm_move_ss(m, _mm_set_ss(y));
47
+ t = _mm_shuffle_ps(t, t, _MM_SHUFFLE(3, 2, 0, 0));
48
+ m = _mm_move_ss(t, m);
49
+ }
50
+ void setZ(float z)
51
+ {
52
+ __m128 t = _mm_move_ss(m, _mm_set_ss(z));
53
+ t = _mm_shuffle_ps(t, t, _MM_SHUFFLE(3, 0, 1, 0));
54
+ m = _mm_move_ss(t, m);
55
+ }
56
+
57
+ __m128 m;
58
+ };
59
+
60
+ typedef float3 bool3;
61
+
62
+ VM_INLINE float3 operator+ (float3 a, float3 b) { a.m = _mm_add_ps(a.m, b.m); return a; }
63
+ VM_INLINE float3 operator- (float3 a, float3 b) { a.m = _mm_sub_ps(a.m, b.m); return a; }
64
+ VM_INLINE float3 operator* (float3 a, float3 b) { a.m = _mm_mul_ps(a.m, b.m); return a; }
65
+ VM_INLINE float3 operator/ (float3 a, float3 b) { a.m = _mm_div_ps(a.m, b.m); return a; }
66
+ VM_INLINE float3 operator* (float3 a, float b) { a.m = _mm_mul_ps(a.m, _mm_set1_ps(b)); return a; }
67
+ VM_INLINE float3 operator/ (float3 a, float b) { a.m = _mm_div_ps(a.m, _mm_set1_ps(b)); return a; }
68
+ VM_INLINE float3 operator* (float a, float3 b) { b.m = _mm_mul_ps(_mm_set1_ps(a), b.m); return b; }
69
+ VM_INLINE float3 operator/ (float a, float3 b) { b.m = _mm_div_ps(_mm_set1_ps(a), b.m); return b; }
70
+ VM_INLINE float3& operator+= (float3 &a, float3 b) { a = a + b; return a; }
71
+ VM_INLINE float3& operator-= (float3 &a, float3 b) { a = a - b; return a; }
72
+ VM_INLINE float3& operator*= (float3 &a, float3 b) { a = a * b; return a; }
73
+ VM_INLINE float3& operator/= (float3 &a, float3 b) { a = a / b; return a; }
74
+ VM_INLINE float3& operator*= (float3 &a, float b) { a = a * b; return a; }
75
+ VM_INLINE float3& operator/= (float3 &a, float b) { a = a / b; return a; }
76
+ VM_INLINE bool3 operator==(float3 a, float3 b) { a.m = _mm_cmpeq_ps(a.m, b.m); return a; }
77
+ VM_INLINE bool3 operator!=(float3 a, float3 b) { a.m = _mm_cmpneq_ps(a.m, b.m); return a; }
78
+ VM_INLINE bool3 operator< (float3 a, float3 b) { a.m = _mm_cmplt_ps(a.m, b.m); return a; }
79
+ VM_INLINE bool3 operator> (float3 a, float3 b) { a.m = _mm_cmpgt_ps(a.m, b.m); return a; }
80
+ VM_INLINE bool3 operator<=(float3 a, float3 b) { a.m = _mm_cmple_ps(a.m, b.m); return a; }
81
+ VM_INLINE bool3 operator>=(float3 a, float3 b) { a.m = _mm_cmpge_ps(a.m, b.m); return a; }
82
+ VM_INLINE float3 min(float3 a, float3 b) { a.m = _mm_min_ps(a.m, b.m); return a; }
83
+ VM_INLINE float3 max(float3 a, float3 b) { a.m = _mm_max_ps(a.m, b.m); return a; }
84
+
85
+ VM_INLINE float3 operator- (float3 a) { return float3(_mm_setzero_ps()) - a; }
86
+
87
+ VM_INLINE float hmin(float3 v)
88
+ {
89
+ v = min(v, SHUFFLE3(v, 1, 0, 2));
90
+ return min(v, SHUFFLE3(v, 2, 0, 1)).getX();
91
+ }
92
+ VM_INLINE float hmax(float3 v)
93
+ {
94
+ v = max(v, SHUFFLE3(v, 1, 0, 2));
95
+ return max(v, SHUFFLE3(v, 2, 0, 1)).getX();
96
+ }
97
+
98
+ VM_INLINE float3 cross(float3 a, float3 b)
99
+ {
100
+ // x <- a.y*b.z - a.z*b.y
101
+ // y <- a.z*b.x - a.x*b.z
102
+ // z <- a.x*b.y - a.y*b.x
103
+ // We can save a shuffle by grouping it in this wacky order:
104
+ return (a.zxy()*b - a*b.zxy()).zxy();
105
+ }
106
+
107
+ // Returns a 3-bit code where bit0..bit2 is X..Z
108
+ VM_INLINE unsigned mask(float3 v) { return _mm_movemask_ps(v.m) & 7; }
109
+ // Once we have a comparison, we can branch based on its results:
110
+ VM_INLINE bool any(bool3 v) { return mask(v) != 0; }
111
+ VM_INLINE bool all(bool3 v) { return mask(v) == 7; }
112
+
113
+ VM_INLINE float3 clamp(float3 t, float3 a, float3 b) { return min(max(t, a), b); }
114
+ VM_INLINE float sum(float3 v) { return v.getX() + v.getY() + v.getZ(); }
115
+ VM_INLINE float dot(float3 a, float3 b) { return sum(a*b); }
116
+
117
+ #else // #if !defined(__arm__) && !defined(__arm64__)
118
+
119
+ // ---- NEON implementation
120
+
121
+ #include <arm_neon.h>
122
+
123
+ struct float3
124
+ {
125
+ VM_INLINE float3() {}
126
+ VM_INLINE explicit float3(const float *p) { float v[4] = {p[0], p[1], p[2], 0}; m = vld1q_f32(v); }
127
+ VM_INLINE explicit float3(float x, float y, float z) { float v[4] = {x, y, z, 0}; m = vld1q_f32(v); }
128
+ VM_INLINE explicit float3(float v) { m = vdupq_n_f32(v); }
129
+ VM_INLINE explicit float3(float32x4_t v) { m = v; }
130
+
131
+ VM_INLINE float getX() const { return vgetq_lane_f32(m, 0); }
132
+ VM_INLINE float getY() const { return vgetq_lane_f32(m, 1); }
133
+ VM_INLINE float getZ() const { return vgetq_lane_f32(m, 2); }
134
+
135
+ VM_INLINE float3 yzx() const
136
+ {
137
+ float32x2_t low = vget_low_f32(m);
138
+ float32x4_t yzx = vcombine_f32(vext_f32(low, vget_high_f32(m), 1), low);
139
+ return float3(yzx);
140
+ }
141
+ VM_INLINE float3 zxy() const
142
+ {
143
+ float32x4_t p = m;
144
+ p = vuzpq_f32(vreinterpretq_f32_s32(vextq_s32(vreinterpretq_s32_f32(p), vreinterpretq_s32_f32(p), 1)), p).val[1];
145
+ return float3(p);
146
+ }
147
+
148
+ VM_INLINE void store(float *p) const { p[0] = getX(); p[1] = getY(); p[2] = getZ(); }
149
+
150
+ void setX(float x)
151
+ {
152
+ m = vsetq_lane_f32(x, m, 0);
153
+ }
154
+ void setY(float y)
155
+ {
156
+ m = vsetq_lane_f32(y, m, 1);
157
+ }
158
+ void setZ(float z)
159
+ {
160
+ m = vsetq_lane_f32(z, m, 2);
161
+ }
162
+
163
+ float32x4_t m;
164
+ };
165
+
166
+ typedef float3 bool3;
167
+
168
+ VM_INLINE float32x4_t rcp_2(float32x4_t v)
169
+ {
170
+ float32x4_t e = vrecpeq_f32(v);
171
+ e = vmulq_f32(vrecpsq_f32(e, v), e);
172
+ e = vmulq_f32(vrecpsq_f32(e, v), e);
173
+ return e;
174
+ }
175
+
176
+ VM_INLINE float3 operator+ (float3 a, float3 b) { a.m = vaddq_f32(a.m, b.m); return a; }
177
+ VM_INLINE float3 operator- (float3 a, float3 b) { a.m = vsubq_f32(a.m, b.m); return a; }
178
+ VM_INLINE float3 operator* (float3 a, float3 b) { a.m = vmulq_f32(a.m, b.m); return a; }
179
+ VM_INLINE float3 operator/ (float3 a, float3 b) { float32x4_t recip = rcp_2(b.m); a.m = vmulq_f32(a.m, recip); return a; }
180
+ VM_INLINE float3 operator* (float3 a, float b) { a.m = vmulq_f32(a.m, vdupq_n_f32(b)); return a; }
181
+ VM_INLINE float3 operator/ (float3 a, float b) { float32x4_t recip = rcp_2(vdupq_n_f32(b)); a.m = vmulq_f32(a.m, recip); return a; }
182
+ VM_INLINE float3 operator* (float a, float3 b) { b.m = vmulq_f32(vdupq_n_f32(a), b.m); return b; }
183
+ VM_INLINE float3 operator/ (float a, float3 b) { float32x4_t recip = rcp_2(b.m); b.m = vmulq_f32(vdupq_n_f32(a), recip); return b; }
184
+ VM_INLINE float3& operator+= (float3 &a, float3 b) { a = a + b; return a; }
185
+ VM_INLINE float3& operator-= (float3 &a, float3 b) { a = a - b; return a; }
186
+ VM_INLINE float3& operator*= (float3 &a, float3 b) { a = a * b; return a; }
187
+ VM_INLINE float3& operator/= (float3 &a, float3 b) { a = a / b; return a; }
188
+ VM_INLINE float3& operator*= (float3 &a, float b) { a = a * b; return a; }
189
+ VM_INLINE float3& operator/= (float3 &a, float b) { a = a / b; return a; }
190
+ VM_INLINE bool3 operator==(float3 a, float3 b) { a.m = vceqq_f32(a.m, b.m); return a; }
191
+ VM_INLINE bool3 operator!=(float3 a, float3 b) { a.m = vmvnq_u32(vceqq_f32(a.m, b.m)); return a; }
192
+ VM_INLINE bool3 operator< (float3 a, float3 b) { a.m = vcltq_f32(a.m, b.m); return a; }
193
+ VM_INLINE bool3 operator> (float3 a, float3 b) { a.m = vcgtq_f32(a.m, b.m); return a; }
194
+ VM_INLINE bool3 operator<=(float3 a, float3 b) { a.m = vcleq_f32(a.m, b.m); return a; }
195
+ VM_INLINE bool3 operator>=(float3 a, float3 b) { a.m = vcgeq_f32(a.m, b.m); return a; }
196
+ VM_INLINE float3 min(float3 a, float3 b) { a.m = vminq_f32(a.m, b.m); return a; }
197
+ VM_INLINE float3 max(float3 a, float3 b) { a.m = vmaxq_f32(a.m, b.m); return a; }
198
+
199
+ VM_INLINE float3 operator- (float3 a) { a.m = vnegq_f32(a.m); return a; }
200
+
201
+ VM_INLINE float hmin(float3 v)
202
+ {
203
+ float32x2_t minOfHalfs = vpmin_f32(vget_low_f32(v.m), vget_high_f32(v.m));
204
+ float32x2_t minOfMinOfHalfs = vpmin_f32(minOfHalfs, minOfHalfs);
205
+ return vget_lane_f32(minOfMinOfHalfs, 0);
206
+ }
207
+ VM_INLINE float hmax(float3 v)
208
+ {
209
+ float32x2_t maxOfHalfs = vpmax_f32(vget_low_f32(v.m), vget_high_f32(v.m));
210
+ float32x2_t maxOfMaxOfHalfs = vpmax_f32(maxOfHalfs, maxOfHalfs);
211
+ return vget_lane_f32(maxOfMaxOfHalfs, 0);
212
+ }
213
+
214
+ VM_INLINE float3 cross(float3 a, float3 b)
215
+ {
216
+ // x <- a.y*b.z - a.z*b.y
217
+ // y <- a.z*b.x - a.x*b.z
218
+ // z <- a.x*b.y - a.y*b.x
219
+ // We can save a shuffle by grouping it in this wacky order:
220
+ return (a.zxy()*b - a*b.zxy()).zxy();
221
+ }
222
+
223
+ // Returns a 3-bit code where bit0..bit2 is X..Z
224
+ VM_INLINE unsigned mask(float3 v)
225
+ {
226
+ static const uint32x4_t movemask = { 1, 2, 4, 8 };
227
+ static const uint32x4_t highbit = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
228
+ uint32x4_t t0 = vreinterpretq_u32_f32(v.m);
229
+ uint32x4_t t1 = vtstq_u32(t0, highbit);
230
+ uint32x4_t t2 = vandq_u32(t1, movemask);
231
+ uint32x2_t t3 = vorr_u32(vget_low_u32(t2), vget_high_u32(t2));
232
+ return vget_lane_u32(t3, 0) | vget_lane_u32(t3, 1);
233
+ }
234
+ // Once we have a comparison, we can branch based on its results:
235
+ VM_INLINE bool any(bool3 v) { return mask(v) != 0; }
236
+ VM_INLINE bool all(bool3 v) { return mask(v) == 7; }
237
+
238
+ VM_INLINE float3 clamp(float3 t, float3 a, float3 b) { return min(max(t, a), b); }
239
+ VM_INLINE float sum(float3 v) { return v.getX() + v.getY() + v.getZ(); }
240
+ VM_INLINE float dot(float3 a, float3 b) { return sum(a*b); }
241
+
242
+
243
+ #endif // #else of #if !defined(__arm__) && !defined(__arm64__)
244
+
245
+ #else // #if DO_FLOAT3_WITH_SIMD
246
+
247
+ // ---- Simple scalar C implementation
248
+
249
+
250
+ struct float3
251
+ {
252
+ float3() : x(0), y(0), z(0) {}
253
+ float3(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
254
+
255
+ float3 operator-() const { return float3(-x, -y, -z); }
256
+ float3& operator+=(const float3& o) { x+=o.x; y+=o.y; z+=o.z; return *this; }
257
+ float3& operator-=(const float3& o) { x-=o.x; y-=o.y; z-=o.z; return *this; }
258
+ float3& operator*=(const float3& o) { x*=o.x; y*=o.y; z*=o.z; return *this; }
259
+ float3& operator*=(float o) { x*=o; y*=o; z*=o; return *this; }
260
+
261
+ VM_INLINE float getX() const { return x; }
262
+ VM_INLINE float getY() const { return y; }
263
+ VM_INLINE float getZ() const { return z; }
264
+ VM_INLINE void setX(float x_) { x = x_; }
265
+ VM_INLINE void setY(float y_) { y = y_; }
266
+ VM_INLINE void setZ(float z_) { z = z_; }
267
+ VM_INLINE void store(float *p) const { p[0] = getX(); p[1] = getY(); p[2] = getZ(); }
268
+
269
+ float x, y, z;
270
+ };
271
+
272
+ VM_INLINE float3 operator+(const float3& a, const float3& b) { return float3(a.x+b.x,a.y+b.y,a.z+b.z); }
273
+ VM_INLINE float3 operator-(const float3& a, const float3& b) { return float3(a.x-b.x,a.y-b.y,a.z-b.z); }
274
+ VM_INLINE float3 operator*(const float3& a, const float3& b) { return float3(a.x*b.x,a.y*b.y,a.z*b.z); }
275
+ VM_INLINE float3 operator*(const float3& a, float b) { return float3(a.x*b,a.y*b,a.z*b); }
276
+ VM_INLINE float3 operator*(float a, const float3& b) { return float3(a*b.x,a*b.y,a*b.z); }
277
+ VM_INLINE float dot(const float3& a, const float3& b) { return a.x*b.x+a.y*b.y+a.z*b.z; }
278
+ VM_INLINE float3 cross(const float3& a, const float3& b)
279
+ {
280
+ return float3(
281
+ a.y*b.z - a.z*b.y,
282
+ -(a.x*b.z - a.z*b.x),
283
+ a.x*b.y - a.y*b.x
284
+ );
285
+ }
286
+ #endif // #else of #if DO_FLOAT3_WITH_SIMD
287
+
288
+ VM_INLINE float length(float3 v) { return sqrtf(dot(v, v)); }
289
+ VM_INLINE float sqLength(float3 v) { return dot(v, v); }
290
+ VM_INLINE float3 normalize(float3 v) { return v * (1.0f / length(v)); }
291
+ VM_INLINE float3 lerp(float3 a, float3 b, float t) { return a + (b-a)*t; }
292
+
293
+
294
+ inline void AssertUnit(float3 v)
295
+ {
296
+ assert(fabsf(sqLength(v) - 1.0f) < 0.01f);
297
+ }
298
+
299
+ inline float3 reflect(float3 v, float3 n)
300
+ {
301
+ return v - 2*dot(v,n)*n;
302
+ }
303
+
304
+ inline bool refract(float3 v, float3 n, float nint, float3& outRefracted)
305
+ {
306
+ AssertUnit(v);
307
+ float dt = dot(v, n);
308
+ float discr = 1.0f - nint*nint*(1-dt*dt);
309
+ if (discr > 0)
310
+ {
311
+ outRefracted = nint * (v - n*dt) - n*sqrtf(discr);
312
+ return true;
313
+ }
314
+ return false;
315
+ }
316
+ inline float schlick(float cosine, float ri)
317
+ {
318
+ float r0 = (1-ri) / (1+ri);
319
+ r0 = r0*r0;
320
+ return r0 + (1-r0)*powf(1-cosine, 5);
321
+ }
322
+
323
+ struct Ray
324
+ {
325
+ Ray() {}
326
+ Ray(float3 orig_, float3 dir_) : orig(orig_), dir(dir_) { AssertUnit(dir); }
327
+
328
+ float3 pointAt(float t) const { return orig + dir * t; }
329
+
330
+ float3 orig;
331
+ float3 dir;
332
+ };
333
+
334
+
335
+ struct Hit
336
+ {
337
+ float3 pos;
338
+ float3 normal;
339
+ float t;
340
+ };
341
+
342
+
343
+ struct Sphere
344
+ {
345
+ Sphere() : radius(1.0f), invRadius(0.0f) {}
346
+ Sphere(float3 center_, float radius_) : center(center_), radius(radius_), invRadius(0.0f) {}
347
+
348
+ void UpdateDerivedData() { invRadius = 1.0f/radius; }
349
+
350
+ float3 center;
351
+ float radius;
352
+ float invRadius;
353
+ };
354
+
355
+
356
+ // data for all spheres in a "structure of arrays" layout
357
+ struct SpheresSoA
358
+ {
359
+ SpheresSoA(int c)
360
+ {
361
+ count = c;
362
+ // we'll be processing spheres in kSimdWidth chunks, so make sure to allocate
363
+ // enough space
364
+ simdCount = (c + (kSimdWidth - 1)) / kSimdWidth * kSimdWidth;
365
+ centerX = new float[simdCount];
366
+ centerY = new float[simdCount];
367
+ centerZ = new float[simdCount];
368
+ sqRadius = new float[simdCount];
369
+ invRadius = new float[simdCount];
370
+ // set all data to "impossible sphere" state
371
+ for (int i = count; i < simdCount; ++i)
372
+ {
373
+ centerX[i] = centerY[i] = centerZ[i] = 10000.0f;
374
+ sqRadius[i] = 0.0f;
375
+ invRadius[i] = 0.0f;
376
+ }
377
+ }
378
+ ~SpheresSoA()
379
+ {
380
+ delete[] centerX;
381
+ delete[] centerY;
382
+ delete[] centerZ;
383
+ delete[] sqRadius;
384
+ delete[] invRadius;
385
+ }
386
+ float* centerX;
387
+ float* centerY;
388
+ float* centerZ;
389
+ float* sqRadius;
390
+ float* invRadius;
391
+ int simdCount;
392
+ int count;
393
+ };
394
+
395
+
396
+ int HitSpheres(const Ray& r, const SpheresSoA& spheres, float tMin, float tMax, Hit& outHit);
397
+
398
+ float RandomFloat01(uint32_t& state);
399
+ float3 RandomInUnitDisk(uint32_t& state);
400
+ float3 RandomInUnitSphere(uint32_t& state);
401
+ float3 RandomUnitVector(uint32_t& state);
402
+
403
+ struct Camera
404
+ {
405
+ Camera() {}
406
+ // vfov is top to bottom in degrees
407
+ Camera(const float3& lookFrom, const float3& lookAt, const float3& vup, float vfov, float aspect, float aperture, float focusDist)
408
+ {
409
+ lensRadius = aperture / 2;
410
+ float theta = vfov*kPI/180;
411
+ float halfHeight = tanf(theta/2);
412
+ float halfWidth = aspect * halfHeight;
413
+ origin = lookFrom;
414
+ w = normalize(lookFrom - lookAt);
415
+ u = normalize(cross(vup, w));
416
+ v = cross(w, u);
417
+ lowerLeftCorner = origin - halfWidth*focusDist*u - halfHeight*focusDist*v - focusDist*w;
418
+ horizontal = 2*halfWidth*focusDist*u;
419
+ vertical = 2*halfHeight*focusDist*v;
420
+ }
421
+
422
+ Ray GetRay(float s, float t, uint32_t& state) const
423
+ {
424
+ float3 rd = lensRadius * RandomInUnitDisk(state);
425
+ float3 offset = u * rd.getX() + v * rd.getY();
426
+ return Ray(origin + offset, normalize(lowerLeftCorner + s*horizontal + t*vertical - origin - offset));
427
+ }
428
+
429
+ float3 origin;
430
+ float3 lowerLeftCorner;
431
+ float3 horizontal;
432
+ float3 vertical;
433
+ float3 u, v, w;
434
+ float lensRadius;
435
+ };
436
+
third_party/tracy/examples/ToyPathTracer/Source/Test.cpp ADDED
@@ -0,0 +1,392 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "Config.h"
2
+ #include "Test.h"
3
+ #include "Maths.h"
4
+ #include <algorithm>
5
+ #if CPU_CAN_DO_THREADS
6
+ #include "enkiTS/TaskScheduler_c.h"
7
+ #include <thread>
8
+ #endif
9
+ #include <atomic>
10
+
11
+ #include "../../../public/tracy/Tracy.hpp"
12
+
13
+ // 46 spheres (2 emissive) when enabled; 9 spheres (1 emissive) when disabled
14
+ #define DO_BIG_SCENE 1
15
+
16
+ static Sphere s_Spheres[] =
17
+ {
18
+ {float3(0,-100.5,-1), 100},
19
+ {float3(2,0,-1), 0.5f},
20
+ {float3(0,0,-1), 0.5f},
21
+ {float3(-2,0,-1), 0.5f},
22
+ {float3(2,0,1), 0.5f},
23
+ {float3(0,0,1), 0.5f},
24
+ {float3(-2,0,1), 0.5f},
25
+ {float3(0.5f,1,0.5f), 0.5f},
26
+ {float3(-1.5f,1.5f,0.f), 0.3f},
27
+ #if DO_BIG_SCENE
28
+ {float3(4,0,-3), 0.5f}, {float3(3,0,-3), 0.5f}, {float3(2,0,-3), 0.5f}, {float3(1,0,-3), 0.5f}, {float3(0,0,-3), 0.5f}, {float3(-1,0,-3), 0.5f}, {float3(-2,0,-3), 0.5f}, {float3(-3,0,-3), 0.5f}, {float3(-4,0,-3), 0.5f},
29
+ {float3(4,0,-4), 0.5f}, {float3(3,0,-4), 0.5f}, {float3(2,0,-4), 0.5f}, {float3(1,0,-4), 0.5f}, {float3(0,0,-4), 0.5f}, {float3(-1,0,-4), 0.5f}, {float3(-2,0,-4), 0.5f}, {float3(-3,0,-4), 0.5f}, {float3(-4,0,-4), 0.5f},
30
+ {float3(4,0,-5), 0.5f}, {float3(3,0,-5), 0.5f}, {float3(2,0,-5), 0.5f}, {float3(1,0,-5), 0.5f}, {float3(0,0,-5), 0.5f}, {float3(-1,0,-5), 0.5f}, {float3(-2,0,-5), 0.5f}, {float3(-3,0,-5), 0.5f}, {float3(-4,0,-5), 0.5f},
31
+ {float3(4,0,-6), 0.5f}, {float3(3,0,-6), 0.5f}, {float3(2,0,-6), 0.5f}, {float3(1,0,-6), 0.5f}, {float3(0,0,-6), 0.5f}, {float3(-1,0,-6), 0.5f}, {float3(-2,0,-6), 0.5f}, {float3(-3,0,-6), 0.5f}, {float3(-4,0,-6), 0.5f},
32
+ {float3(1.5f,1.5f,-2), 0.3f},
33
+ #endif // #if DO_BIG_SCENE
34
+ };
35
+ const int kSphereCount = sizeof(s_Spheres) / sizeof(s_Spheres[0]);
36
+
37
+ static SpheresSoA s_SpheresSoA(kSphereCount);
38
+
39
+ struct Material
40
+ {
41
+ enum Type { Lambert, Metal, Dielectric };
42
+ Type type;
43
+ float3 albedo;
44
+ float3 emissive;
45
+ float roughness;
46
+ float ri;
47
+ };
48
+
49
+ static Material s_SphereMats[kSphereCount] =
50
+ {
51
+ { Material::Lambert, float3(0.8f, 0.8f, 0.8f), float3(0,0,0), 0, 0, },
52
+ { Material::Lambert, float3(0.8f, 0.4f, 0.4f), float3(0,0,0), 0, 0, },
53
+ { Material::Lambert, float3(0.4f, 0.8f, 0.4f), float3(0,0,0), 0, 0, },
54
+ { Material::Metal, float3(0.4f, 0.4f, 0.8f), float3(0,0,0), 0, 0 },
55
+ { Material::Metal, float3(0.4f, 0.8f, 0.4f), float3(0,0,0), 0, 0 },
56
+ { Material::Metal, float3(0.4f, 0.8f, 0.4f), float3(0,0,0), 0.2f, 0 },
57
+ { Material::Metal, float3(0.4f, 0.8f, 0.4f), float3(0,0,0), 0.6f, 0 },
58
+ { Material::Dielectric, float3(0.4f, 0.4f, 0.4f), float3(0,0,0), 0, 1.5f },
59
+ { Material::Lambert, float3(0.8f, 0.6f, 0.2f), float3(30,25,15), 0, 0 },
60
+ #if DO_BIG_SCENE
61
+ { Material::Lambert, float3(0.1f, 0.1f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.2f, 0.2f, 0.2f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.3f, 0.3f, 0.3f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.4f, 0.4f, 0.4f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.5f, 0.5f, 0.5f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.6f, 0.6f, 0.6f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.7f, 0.7f, 0.7f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.8f, 0.8f, 0.8f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.9f, 0.9f, 0.9f), float3(0,0,0), 0, 0, },
62
+ { Material::Metal, float3(0.1f, 0.1f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.2f, 0.2f, 0.2f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.3f, 0.3f, 0.3f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.4f, 0.4f, 0.4f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.5f, 0.5f, 0.5f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.6f, 0.6f, 0.6f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.7f, 0.7f, 0.7f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.8f, 0.8f, 0.8f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.9f, 0.9f, 0.9f), float3(0,0,0), 0, 0, },
63
+ { Material::Metal, float3(0.8f, 0.1f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.8f, 0.5f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.8f, 0.8f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.4f, 0.8f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.1f, 0.8f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.1f, 0.8f, 0.5f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.1f, 0.8f, 0.8f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.1f, 0.1f, 0.8f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.5f, 0.1f, 0.8f), float3(0,0,0), 0, 0, },
64
+ { Material::Lambert, float3(0.8f, 0.1f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.8f, 0.5f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.8f, 0.8f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.4f, 0.8f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.1f, 0.8f, 0.1f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.1f, 0.8f, 0.5f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.1f, 0.8f, 0.8f), float3(0,0,0), 0, 0, }, { Material::Lambert, float3(0.1f, 0.1f, 0.8f), float3(0,0,0), 0, 0, }, { Material::Metal, float3(0.5f, 0.1f, 0.8f), float3(0,0,0), 0, 0, },
65
+ { Material::Lambert, float3(0.1f, 0.2f, 0.5f), float3(3,10,20), 0, 0 },
66
+ #endif
67
+ };
68
+
69
+ static int s_EmissiveSpheres[kSphereCount];
70
+ static int s_EmissiveSphereCount;
71
+
72
+ static Camera s_Cam;
73
+
74
+ const float kMinT = 0.001f;
75
+ const float kMaxT = 1.0e7f;
76
+ const int kMaxDepth = 10;
77
+
78
+
79
+ bool HitWorld(const Ray& r, float tMin, float tMax, Hit& outHit, int& outID)
80
+ {
81
+ outID = HitSpheres(r, s_SpheresSoA, tMin, tMax, outHit);
82
+ return outID != -1;
83
+ }
84
+
85
+
86
+ static bool Scatter(const Material& mat, const Ray& r_in, const Hit& rec, float3& attenuation, Ray& scattered, float3& outLightE, int& inoutRayCount, uint32_t& state)
87
+ {
88
+ ZoneScoped;
89
+ outLightE = float3(0,0,0);
90
+ if (mat.type == Material::Lambert)
91
+ {
92
+ // random point on unit sphere that is tangent to the hit point
93
+ float3 target = rec.pos + rec.normal + RandomUnitVector(state);
94
+ scattered = Ray(rec.pos, normalize(target - rec.pos));
95
+ attenuation = mat.albedo;
96
+
97
+ // sample lights
98
+ #if DO_LIGHT_SAMPLING
99
+ for (int j = 0; j < s_EmissiveSphereCount; ++j)
100
+ {
101
+ int i = s_EmissiveSpheres[j];
102
+ const Material& smat = s_SphereMats[i];
103
+ if (&mat == &smat)
104
+ continue; // skip self
105
+ const Sphere& s = s_Spheres[i];
106
+
107
+ // create a random direction towards sphere
108
+ // coord system for sampling: sw, su, sv
109
+ float3 sw = normalize(s.center - rec.pos);
110
+ float3 su = normalize(cross(fabs(sw.getX())>0.01f ? float3(0,1,0):float3(1,0,0), sw));
111
+ float3 sv = cross(sw, su);
112
+ // sample sphere by solid angle
113
+ float cosAMax = sqrtf(1.0f - s.radius*s.radius / sqLength(rec.pos-s.center));
114
+ float eps1 = RandomFloat01(state), eps2 = RandomFloat01(state);
115
+ float cosA = 1.0f - eps1 + eps1 * cosAMax;
116
+ float sinA = sqrtf(1.0f - cosA*cosA);
117
+ float phi = 2 * kPI * eps2;
118
+ float3 l = su * (cosf(phi) * sinA) + sv * (sinf(phi) * sinA) + sw * cosA;
119
+ //l = normalize(l); // NOTE(fg): This is already normalized, by construction.
120
+
121
+ // shoot shadow ray
122
+ Hit lightHit;
123
+ int hitID;
124
+ ++inoutRayCount;
125
+ if (HitWorld(Ray(rec.pos, l), kMinT, kMaxT, lightHit, hitID) && hitID == i)
126
+ {
127
+ float omega = 2 * kPI * (1-cosAMax);
128
+
129
+ float3 rdir = r_in.dir;
130
+ AssertUnit(rdir);
131
+ float3 nl = dot(rec.normal, rdir) < 0 ? rec.normal : -rec.normal;
132
+ outLightE += (mat.albedo * smat.emissive) * (std::max(0.0f, dot(l, nl)) * omega / kPI);
133
+ }
134
+ }
135
+ #endif
136
+ return true;
137
+ }
138
+ else if (mat.type == Material::Metal)
139
+ {
140
+ AssertUnit(r_in.dir); AssertUnit(rec.normal);
141
+ float3 refl = reflect(r_in.dir, rec.normal);
142
+ // reflected ray, and random inside of sphere based on roughness
143
+ float roughness = mat.roughness;
144
+ #if DO_MITSUBA_COMPARE
145
+ roughness = 0; // until we get better BRDF for metals
146
+ #endif
147
+ scattered = Ray(rec.pos, normalize(refl + roughness*RandomInUnitSphere(state)));
148
+ attenuation = mat.albedo;
149
+ return dot(scattered.dir, rec.normal) > 0;
150
+ }
151
+ else if (mat.type == Material::Dielectric)
152
+ {
153
+ AssertUnit(r_in.dir); AssertUnit(rec.normal);
154
+ float3 outwardN;
155
+ float3 rdir = r_in.dir;
156
+ float3 refl = reflect(rdir, rec.normal);
157
+ float nint;
158
+ attenuation = float3(1,1,1);
159
+ float3 refr;
160
+ float reflProb;
161
+ float cosine;
162
+ if (dot(rdir, rec.normal) > 0)
163
+ {
164
+ outwardN = -rec.normal;
165
+ nint = mat.ri;
166
+ cosine = mat.ri * dot(rdir, rec.normal);
167
+ }
168
+ else
169
+ {
170
+ outwardN = rec.normal;
171
+ nint = 1.0f / mat.ri;
172
+ cosine = -dot(rdir, rec.normal);
173
+ }
174
+ if (refract(rdir, outwardN, nint, refr))
175
+ {
176
+ reflProb = schlick(cosine, mat.ri);
177
+ }
178
+ else
179
+ {
180
+ reflProb = 1;
181
+ }
182
+ if (RandomFloat01(state) < reflProb)
183
+ scattered = Ray(rec.pos, normalize(refl));
184
+ else
185
+ scattered = Ray(rec.pos, normalize(refr));
186
+ }
187
+ else
188
+ {
189
+ attenuation = float3(1,0,1);
190
+ return false;
191
+ }
192
+ return true;
193
+ }
194
+
195
+ static float3 Trace(const Ray& r, int depth, int& inoutRayCount, uint32_t& state, bool doMaterialE = true)
196
+ {
197
+ ZoneScoped;
198
+ Hit rec;
199
+ int id = 0;
200
+ ++inoutRayCount;
201
+ if (HitWorld(r, kMinT, kMaxT, rec, id))
202
+ {
203
+ Ray scattered;
204
+ float3 attenuation;
205
+ float3 lightE;
206
+ const Material& mat = s_SphereMats[id];
207
+ float3 matE = mat.emissive;
208
+ if (depth < kMaxDepth && Scatter(mat, r, rec, attenuation, scattered, lightE, inoutRayCount, state))
209
+ {
210
+ #if DO_LIGHT_SAMPLING
211
+ if (!doMaterialE) matE = float3(0,0,0); // don't add material emission if told so
212
+ // dor Lambert materials, we just did explicit light (emissive) sampling and already
213
+ // for their contribution, so if next ray bounce hits the light again, don't add
214
+ // emission
215
+ doMaterialE = (mat.type != Material::Lambert);
216
+ #endif
217
+ return matE + lightE + attenuation * Trace(scattered, depth+1, inoutRayCount, state, doMaterialE);
218
+ }
219
+ else
220
+ {
221
+ return matE;
222
+ }
223
+ }
224
+ else
225
+ {
226
+ // sky
227
+ #if DO_MITSUBA_COMPARE
228
+ return float3(0.15f,0.21f,0.3f); // easier compare with Mitsuba's constant environment light
229
+ #else
230
+ float3 unitDir = r.dir;
231
+ float t = 0.5f*(unitDir.getY() + 1.0f);
232
+ return ((1.0f-t)*float3(1.0f, 1.0f, 1.0f) + t*float3(0.5f, 0.7f, 1.0f)) * 0.3f;
233
+ #endif
234
+ }
235
+ }
236
+
237
+ #if CPU_CAN_DO_THREADS
238
+ static enkiTaskScheduler* g_TS;
239
+ #endif
240
+
241
+ void InitializeTest()
242
+ {
243
+ ZoneScoped;
244
+ #if CPU_CAN_DO_THREADS
245
+ g_TS = enkiNewTaskScheduler();
246
+ enkiInitTaskSchedulerNumThreads(g_TS, std::max<int>( 2, std::thread::hardware_concurrency() - 2));
247
+ #endif
248
+ }
249
+
250
+ void ShutdownTest()
251
+ {
252
+ ZoneScoped;
253
+ #if CPU_CAN_DO_THREADS
254
+ enkiDeleteTaskScheduler(g_TS);
255
+ #endif
256
+ }
257
+
258
+ struct JobData
259
+ {
260
+ float time;
261
+ int frameCount;
262
+ int screenWidth, screenHeight;
263
+ float* backbuffer;
264
+ Camera* cam;
265
+ std::atomic<int> rayCount;
266
+ unsigned testFlags;
267
+ };
268
+
269
+ static void TraceRowJob(uint32_t start, uint32_t end, uint32_t threadnum, void* data_)
270
+ {
271
+ ZoneScoped;
272
+ JobData& data = *(JobData*)data_;
273
+ float* backbuffer = data.backbuffer + start * data.screenWidth * 4;
274
+ float invWidth = 1.0f / data.screenWidth;
275
+ float invHeight = 1.0f / data.screenHeight;
276
+ float lerpFac = float(data.frameCount) / float(data.frameCount+1);
277
+ if (data.testFlags & kFlagAnimate)
278
+ lerpFac *= DO_ANIMATE_SMOOTHING;
279
+ if (!(data.testFlags & kFlagProgressive))
280
+ lerpFac = 0;
281
+ int rayCount = 0;
282
+ for (uint32_t y = start; y < end; ++y)
283
+ {
284
+ uint32_t state = (y * 9781 + data.frameCount * 6271) | 1;
285
+ for (int x = 0; x < data.screenWidth; ++x)
286
+ {
287
+ float3 col(0, 0, 0);
288
+ for (int s = 0; s < DO_SAMPLES_PER_PIXEL; s++)
289
+ {
290
+ float u = float(x + RandomFloat01(state)) * invWidth;
291
+ float v = float(y + RandomFloat01(state)) * invHeight;
292
+ Ray r = data.cam->GetRay(u, v, state);
293
+ col += Trace(r, 0, rayCount, state);
294
+ }
295
+ col *= 1.0f / float(DO_SAMPLES_PER_PIXEL);
296
+
297
+ float3 prev(backbuffer[0], backbuffer[1], backbuffer[2]);
298
+ col = prev * lerpFac + col * (1-lerpFac);
299
+ col.store(backbuffer);
300
+ backbuffer += 4;
301
+ }
302
+ }
303
+ data.rayCount += rayCount;
304
+ }
305
+
306
+ void UpdateTest(float time, int frameCount, int screenWidth, int screenHeight, unsigned testFlags)
307
+ {
308
+ ZoneScoped;
309
+ if (testFlags & kFlagAnimate)
310
+ {
311
+ s_Spheres[1].center.setY(cosf(time) + 1.0f);
312
+ s_Spheres[8].center.setZ(sinf(time)*0.3f);
313
+ }
314
+ float3 lookfrom(0, 2, 3);
315
+ float3 lookat(0, 0, 0);
316
+ float distToFocus = 3;
317
+ #if DO_MITSUBA_COMPARE
318
+ float aperture = 0.0f;
319
+ #else
320
+ float aperture = 0.1f;
321
+ #endif
322
+ #if DO_BIG_SCENE
323
+ aperture *= 0.2f;
324
+ #endif
325
+
326
+ s_EmissiveSphereCount = 0;
327
+ for (int i = 0; i < kSphereCount; ++i)
328
+ {
329
+ Sphere& s = s_Spheres[i];
330
+ s.UpdateDerivedData();
331
+ s_SpheresSoA.centerX[i] = s.center.getX();
332
+ s_SpheresSoA.centerY[i] = s.center.getY();
333
+ s_SpheresSoA.centerZ[i] = s.center.getZ();
334
+ s_SpheresSoA.sqRadius[i] = s.radius * s.radius;
335
+ s_SpheresSoA.invRadius[i] = s.invRadius;
336
+
337
+ // Remember IDs of emissive spheres (light sources)
338
+ const Material& smat = s_SphereMats[i];
339
+ if (smat.emissive.getX() > 0 || smat.emissive.getY() > 0 || smat.emissive.getZ() > 0)
340
+ {
341
+ s_EmissiveSpheres[s_EmissiveSphereCount] = i;
342
+ s_EmissiveSphereCount++;
343
+ }
344
+ }
345
+
346
+ s_Cam = Camera(lookfrom, lookat, float3(0, 1, 0), 60, float(screenWidth) / float(screenHeight), aperture, distToFocus);
347
+ }
348
+
349
+ void DrawTest(float time, int frameCount, int screenWidth, int screenHeight, float* backbuffer, int& outRayCount, unsigned testFlags)
350
+ {
351
+ ZoneScoped;
352
+ JobData args;
353
+ args.time = time;
354
+ args.frameCount = frameCount;
355
+ args.screenWidth = screenWidth;
356
+ args.screenHeight = screenHeight;
357
+ args.backbuffer = backbuffer;
358
+ args.cam = &s_Cam;
359
+ args.testFlags = testFlags;
360
+ args.rayCount = 0;
361
+
362
+ #if CPU_CAN_DO_THREADS
363
+ enkiTaskSet* task = enkiCreateTaskSet(g_TS, TraceRowJob);
364
+ bool threaded = true;
365
+ enkiAddTaskSetToPipeMinRange(g_TS, task, &args, screenHeight, threaded ? 4 : screenHeight);
366
+ enkiWaitForTaskSet(g_TS, task);
367
+ enkiDeleteTaskSet(task);
368
+ #else
369
+ TraceRowJob(0, screenHeight, 0, &args);
370
+ #endif
371
+
372
+ outRayCount = args.rayCount;
373
+ }
374
+
375
+ void GetObjectCount(int& outCount, int& outObjectSize, int& outMaterialSize, int& outCamSize)
376
+ {
377
+ ZoneScoped;
378
+ outCount = kSphereCount;
379
+ outObjectSize = sizeof(Sphere);
380
+ outMaterialSize = sizeof(Material);
381
+ outCamSize = sizeof(Camera);
382
+ }
383
+
384
+ void GetSceneDesc(void* outObjects, void* outMaterials, void* outCam, void* outEmissives, int* outEmissiveCount)
385
+ {
386
+ ZoneScoped;
387
+ memcpy(outObjects, s_Spheres, kSphereCount * sizeof(s_Spheres[0]));
388
+ memcpy(outMaterials, s_SphereMats, kSphereCount * sizeof(s_SphereMats[0]));
389
+ memcpy(outCam, &s_Cam, sizeof(s_Cam));
390
+ memcpy(outEmissives, s_EmissiveSpheres, s_EmissiveSphereCount * sizeof(s_EmissiveSpheres[0]));
391
+ *outEmissiveCount = s_EmissiveSphereCount;
392
+ }
third_party/tracy/examples/ToyPathTracer/Source/Test.h ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+ #include <stdint.h>
3
+
4
+ enum TestFlags
5
+ {
6
+ kFlagAnimate = (1 << 0),
7
+ kFlagProgressive = (1 << 1),
8
+ };
9
+
10
+ void InitializeTest();
11
+ void ShutdownTest();
12
+
13
+ void UpdateTest(float time, int frameCount, int screenWidth, int screenHeight, unsigned testFlags);
14
+ void DrawTest(float time, int frameCount, int screenWidth, int screenHeight, float* backbuffer, int& outRayCount, unsigned testFlags);
15
+
16
+ void GetObjectCount(int& outCount, int& outObjectSize, int& outMaterialSize, int& outCamSize);
17
+ void GetSceneDesc(void* outObjects, void* outMaterials, void* outCam, void* outEmissives, int* outEmissiveCount);
third_party/tracy/examples/ToyPathTracer/Source/enkiTS/Atomics.h ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) 2013 Doug Binks
2
+ //
3
+ // This software is provided 'as-is', without any express or implied
4
+ // warranty. In no event will the authors be held liable for any damages
5
+ // arising from the use of this software.
6
+ //
7
+ // Permission is granted to anyone to use this software for any purpose,
8
+ // including commercial applications, and to alter it and redistribute it
9
+ // freely, subject to the following restrictions:
10
+ //
11
+ // 1. The origin of this software must not be misrepresented; you must not
12
+ // claim that you wrote the original software. If you use this software
13
+ // in a product, an acknowledgement in the product documentation would be
14
+ // appreciated but is not required.
15
+ // 2. Altered source versions must be plainly marked as such, and must not be
16
+ // misrepresented as being the original software.
17
+ // 3. This notice may not be removed or altered from any source distribution.
18
+
19
+ #pragma once
20
+
21
+ #include <stdint.h>
22
+
23
+ #ifdef _WIN32
24
+ #define WIN32_LEAN_AND_MEAN
25
+ #include <Windows.h>
26
+ #undef GetObject
27
+ #include <intrin.h>
28
+
29
+ extern "C" void _ReadWriteBarrier();
30
+ #pragma intrinsic(_ReadWriteBarrier)
31
+ #pragma intrinsic(_InterlockedCompareExchange)
32
+ #pragma intrinsic(_InterlockedExchangeAdd)
33
+
34
+ // Memory Barriers to prevent CPU and Compiler re-ordering
35
+ #define BASE_MEMORYBARRIER_ACQUIRE() _ReadWriteBarrier()
36
+ #define BASE_MEMORYBARRIER_RELEASE() _ReadWriteBarrier()
37
+ #define BASE_ALIGN(x) __declspec( align( x ) )
38
+
39
+ #else
40
+ #define BASE_MEMORYBARRIER_ACQUIRE() __asm__ __volatile__("": : :"memory")
41
+ #define BASE_MEMORYBARRIER_RELEASE() __asm__ __volatile__("": : :"memory")
42
+ #define BASE_ALIGN(x) __attribute__ ((aligned( x )))
43
+ #endif
44
+
45
+ namespace enki
46
+ {
47
+ // Atomically performs: if( *pDest == compareWith ) { *pDest = swapTo; }
48
+ // returns old *pDest (so if successfull, returns compareWith)
49
+ inline uint32_t AtomicCompareAndSwap( volatile uint32_t* pDest, uint32_t swapTo, uint32_t compareWith )
50
+ {
51
+ #ifdef _WIN32
52
+ // assumes two's complement - unsigned / signed conversion leads to same bit pattern
53
+ return _InterlockedCompareExchange( (volatile long*)pDest,swapTo, compareWith );
54
+ #else
55
+ return __sync_val_compare_and_swap( pDest, compareWith, swapTo );
56
+ #endif
57
+ }
58
+
59
+ inline uint64_t AtomicCompareAndSwap( volatile uint64_t* pDest, uint64_t swapTo, uint64_t compareWith )
60
+ {
61
+ #ifdef _WIN32
62
+ // assumes two's complement - unsigned / signed conversion leads to same bit pattern
63
+ return _InterlockedCompareExchange64( (__int64 volatile*)pDest, swapTo, compareWith );
64
+ #else
65
+ return __sync_val_compare_and_swap( pDest, compareWith, swapTo );
66
+ #endif
67
+ }
68
+
69
+ // Atomically performs: tmp = *pDest; *pDest += value; return tmp;
70
+ inline int32_t AtomicAdd( volatile int32_t* pDest, int32_t value )
71
+ {
72
+ #ifdef _WIN32
73
+ return _InterlockedExchangeAdd( (long*)pDest, value );
74
+ #else
75
+ return __sync_fetch_and_add( pDest, value );
76
+ #endif
77
+ }
78
+
79
+ }
third_party/tracy/examples/ToyPathTracer/Source/enkiTS/LockLessMultiReadPipe.h ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) 2013 Doug Binks
2
+ //
3
+ // This software is provided 'as-is', without any express or implied
4
+ // warranty. In no event will the authors be held liable for any damages
5
+ // arising from the use of this software.
6
+ //
7
+ // Permission is granted to anyone to use this software for any purpose,
8
+ // including commercial applications, and to alter it and redistribute it
9
+ // freely, subject to the following restrictions:
10
+ //
11
+ // 1. The origin of this software must not be misrepresented; you must not
12
+ // claim that you wrote the original software. If you use this software
13
+ // in a product, an acknowledgement in the product documentation would be
14
+ // appreciated but is not required.
15
+ // 2. Altered source versions must be plainly marked as such, and must not be
16
+ // misrepresented as being the original software.
17
+ // 3. This notice may not be removed or altered from any source distribution.
18
+
19
+ #pragma once
20
+
21
+ #include <stdint.h>
22
+ #include <assert.h>
23
+
24
+ #include "Atomics.h"
25
+ #include <string.h>
26
+
27
+
28
+ namespace enki
29
+ {
30
+ // LockLessMultiReadPipe - Single writer, multiple reader thread safe pipe using (semi) lockless programming
31
+ // Readers can only read from the back of the pipe
32
+ // The single writer can write to the front of the pipe, and read from both ends (a writer can be a reader)
33
+ // for many of the principles used here, see http://msdn.microsoft.com/en-us/library/windows/desktop/ee418650(v=vs.85).aspx
34
+ // Note: using log2 sizes so we do not need to clamp (multi-operation)
35
+ // T is the contained type
36
+ // Note this is not true lockless as the use of flags as a form of lock state.
37
+ template<uint8_t cSizeLog2, typename T> class LockLessMultiReadPipe
38
+ {
39
+ public:
40
+ LockLessMultiReadPipe();
41
+ ~LockLessMultiReadPipe() {}
42
+
43
+ // ReaderTryReadBack returns false if we were unable to read
44
+ // This is thread safe for both multiple readers and the writer
45
+ bool ReaderTryReadBack( T* pOut );
46
+
47
+ // WriterTryReadFront returns false if we were unable to read
48
+ // This is thread safe for the single writer, but should not be called by readers
49
+ bool WriterTryReadFront( T* pOut );
50
+
51
+ // WriterTryWriteFront returns false if we were unable to write
52
+ // This is thread safe for the single writer, but should not be called by readers
53
+ bool WriterTryWriteFront( const T& in );
54
+
55
+ // IsPipeEmpty() is a utility function, not intended for general use
56
+ // Should only be used very prudently.
57
+ bool IsPipeEmpty() const
58
+ {
59
+ return 0 == m_WriteIndex - m_ReadCount;
60
+ }
61
+
62
+ void Clear()
63
+ {
64
+ m_WriteIndex = 0;
65
+ m_ReadIndex = 0;
66
+ m_ReadCount = 0;
67
+ memset( (void*)m_Flags, 0, sizeof( m_Flags ) );
68
+ }
69
+
70
+ private:
71
+ const static uint32_t ms_cSize = ( 1 << cSizeLog2 );
72
+ const static uint32_t ms_cIndexMask = ms_cSize - 1;
73
+ const static uint32_t FLAG_INVALID = 0xFFFFFFFF; // 32bit for CAS
74
+ const static uint32_t FLAG_CAN_WRITE = 0x00000000; // 32bit for CAS
75
+ const static uint32_t FLAG_CAN_READ = 0x11111111; // 32bit for CAS
76
+
77
+ T m_Buffer[ ms_cSize ];
78
+
79
+ // read and write indexes allow fast access to the pipe, but actual access
80
+ // controlled by the access flags.
81
+ volatile uint32_t BASE_ALIGN(4) m_WriteIndex;
82
+ volatile uint32_t BASE_ALIGN(4) m_ReadCount;
83
+ volatile uint32_t m_Flags[ ms_cSize ];
84
+ volatile uint32_t BASE_ALIGN(4) m_ReadIndex;
85
+ };
86
+
87
+ template<uint8_t cSizeLog2, typename T> inline
88
+ LockLessMultiReadPipe<cSizeLog2,T>::LockLessMultiReadPipe()
89
+ : m_WriteIndex(0)
90
+ , m_ReadIndex(0)
91
+ , m_ReadCount(0)
92
+ {
93
+ assert( cSizeLog2 < 32 );
94
+ memset( (void*)m_Flags, 0, sizeof( m_Flags ) );
95
+ }
96
+
97
+ template<uint8_t cSizeLog2, typename T> inline
98
+ bool LockLessMultiReadPipe<cSizeLog2,T>::ReaderTryReadBack( T* pOut )
99
+ {
100
+
101
+ uint32_t actualReadIndex;
102
+
103
+ uint32_t readCount = m_ReadCount;
104
+
105
+ // We get hold of read index for consistency,
106
+ // and do first pass starting at read count
107
+ uint32_t readIndexToUse = readCount;
108
+
109
+
110
+ while(true)
111
+ {
112
+
113
+ uint32_t writeIndex = m_WriteIndex;
114
+ // power of two sizes ensures we can use a simple calc without modulus
115
+ uint32_t numInPipe = writeIndex - readCount;
116
+ if( 0 == numInPipe )
117
+ {
118
+ return false;
119
+ }
120
+ if( readIndexToUse >= writeIndex )
121
+ {
122
+ // move back to start
123
+ readIndexToUse = m_ReadIndex;
124
+ }
125
+
126
+
127
+ // power of two sizes ensures we can perform AND for a modulus
128
+ actualReadIndex = readIndexToUse & ms_cIndexMask;
129
+
130
+ // Multiple potential readers mean we should check if the data is valid,
131
+ // using an atomic compare exchange
132
+ uint32_t previous = AtomicCompareAndSwap( &m_Flags[ actualReadIndex ], FLAG_INVALID, FLAG_CAN_READ );
133
+ if( FLAG_CAN_READ == previous )
134
+ {
135
+ break;
136
+ }
137
+ ++readIndexToUse;
138
+
139
+ //update known readcount
140
+ readCount = m_ReadCount;
141
+ }
142
+
143
+ // we update the read index using an atomic add, as we've only read one piece of data.
144
+ // this ensure consistency of the read index, and the above loop ensures readers
145
+ // only read from unread data
146
+ AtomicAdd( (volatile int32_t*)&m_ReadCount, 1 );
147
+
148
+ BASE_MEMORYBARRIER_ACQUIRE();
149
+ // now read data, ensuring we do so after above reads & CAS
150
+ *pOut = m_Buffer[ actualReadIndex ];
151
+
152
+ m_Flags[ actualReadIndex ] = FLAG_CAN_WRITE;
153
+
154
+ return true;
155
+ }
156
+
157
+ template<uint8_t cSizeLog2, typename T> inline
158
+ bool LockLessMultiReadPipe<cSizeLog2,T>::WriterTryReadFront( T* pOut )
159
+ {
160
+ uint32_t writeIndex = m_WriteIndex;
161
+ uint32_t frontReadIndex = writeIndex;
162
+
163
+ // Multiple potential readers mean we should check if the data is valid,
164
+ // using an atomic compare exchange - which acts as a form of lock (so not quite lockless really).
165
+ uint32_t previous = FLAG_INVALID;
166
+ uint32_t actualReadIndex = 0;
167
+ while( true )
168
+ {
169
+ // power of two sizes ensures we can use a simple calc without modulus
170
+ uint32_t readCount = m_ReadCount;
171
+ uint32_t numInPipe = writeIndex - readCount;
172
+ if( 0 == numInPipe || 0 == frontReadIndex )
173
+ {
174
+ // frontReadIndex can get to 0 here if that item was just being read by another thread.
175
+ m_ReadIndex = readCount;
176
+ return false;
177
+ }
178
+ --frontReadIndex;
179
+ actualReadIndex = frontReadIndex & ms_cIndexMask;
180
+ previous = AtomicCompareAndSwap( &m_Flags[ actualReadIndex ], FLAG_INVALID, FLAG_CAN_READ );
181
+ if( FLAG_CAN_READ == previous )
182
+ {
183
+ break;
184
+ }
185
+ else if( m_ReadIndex >= frontReadIndex )
186
+ {
187
+ return false;
188
+ }
189
+ }
190
+
191
+ // now read data, ensuring we do so after above reads & CAS
192
+ *pOut = m_Buffer[ actualReadIndex ];
193
+
194
+ m_Flags[ actualReadIndex ] = FLAG_CAN_WRITE;
195
+
196
+ BASE_MEMORYBARRIER_RELEASE();
197
+
198
+ // 32-bit aligned stores are atomic, and writer owns the write index
199
+ // we only move one back as this is as many as we have read, not where we have read from.
200
+ --m_WriteIndex;
201
+ return true;
202
+ }
203
+
204
+
205
+ template<uint8_t cSizeLog2, typename T> inline
206
+ bool LockLessMultiReadPipe<cSizeLog2,T>::WriterTryWriteFront( const T& in )
207
+ {
208
+ // The writer 'owns' the write index, and readers can only reduce
209
+ // the amount of data in the pipe.
210
+ // We get hold of both values for consistency and to reduce false sharing
211
+ // impacting more than one access
212
+ uint32_t writeIndex = m_WriteIndex;
213
+
214
+
215
+ // power of two sizes ensures we can perform AND for a modulus
216
+ uint32_t actualWriteIndex = writeIndex & ms_cIndexMask;
217
+
218
+ // a reader may still be reading this item, as there are multiple readers
219
+ if( m_Flags[ actualWriteIndex ] != FLAG_CAN_WRITE )
220
+ {
221
+ return false; // still being read, so have caught up with tail.
222
+ }
223
+
224
+
225
+ // as we are the only writer we can update the data without atomics
226
+ // whilst the write index has not been updated
227
+ m_Buffer[ actualWriteIndex ] = in;
228
+ m_Flags[ actualWriteIndex ] = FLAG_CAN_READ;
229
+
230
+ // We need to ensure the above writes occur prior to updating the write index,
231
+ // otherwise another thread might read before it's finished
232
+ BASE_MEMORYBARRIER_RELEASE();
233
+
234
+ // 32-bit aligned stores are atomic, and the writer controls the write index
235
+ ++writeIndex;
236
+ m_WriteIndex = writeIndex;
237
+ return true;
238
+ }
239
+
240
+ }
third_party/tracy/examples/ToyPathTracer/Source/enkiTS/TaskScheduler.cpp ADDED
@@ -0,0 +1,437 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) 2013 Doug Binks
2
+ //
3
+ // This software is provided 'as-is', without any express or implied
4
+ // warranty. In no event will the authors be held liable for any damages
5
+ // arising from the use of this software.
6
+ //
7
+ // Permission is granted to anyone to use this software for any purpose,
8
+ // including commercial applications, and to alter it and redistribute it
9
+ // freely, subject to the following restrictions:
10
+ //
11
+ // 1. The origin of this software must not be misrepresented; you must not
12
+ // claim that you wrote the original software. If you use this software
13
+ // in a product, an acknowledgement in the product documentation would be
14
+ // appreciated but is not required.
15
+ // 2. Altered source versions must be plainly marked as such, and must not be
16
+ // misrepresented as being the original software.
17
+ // 3. This notice may not be removed or altered from any source distribution.
18
+
19
+ #include <assert.h>
20
+
21
+ #include "TaskScheduler.h"
22
+ #include "LockLessMultiReadPipe.h"
23
+
24
+
25
+
26
+ using namespace enki;
27
+
28
+
29
+ static const uint32_t PIPESIZE_LOG2 = 8;
30
+ static const uint32_t SPIN_COUNT = 100;
31
+ static const uint32_t SPIN_BACKOFF_MULTIPLIER = 10;
32
+ static const uint32_t MAX_NUM_INITIAL_PARTITIONS = 8;
33
+
34
+ // each software thread gets it's own copy of gtl_threadNum, so this is safe to use as a static variable
35
+ static THREAD_LOCAL uint32_t gtl_threadNum = 0;
36
+
37
+ namespace enki
38
+ {
39
+ struct SubTaskSet
40
+ {
41
+ ITaskSet* pTask;
42
+ TaskSetPartition partition;
43
+ };
44
+
45
+ // we derive class TaskPipe rather than typedef to get forward declaration working easily
46
+ class TaskPipe : public LockLessMultiReadPipe<PIPESIZE_LOG2,enki::SubTaskSet> {};
47
+
48
+ struct ThreadArgs
49
+ {
50
+ uint32_t threadNum;
51
+ TaskScheduler* pTaskScheduler;
52
+ };
53
+ }
54
+
55
+ namespace
56
+ {
57
+ SubTaskSet SplitTask( SubTaskSet& subTask_, uint32_t rangeToSplit_ )
58
+ {
59
+ SubTaskSet splitTask = subTask_;
60
+ uint32_t rangeLeft = subTask_.partition.end - subTask_.partition.start;
61
+
62
+ if( rangeToSplit_ > rangeLeft )
63
+ {
64
+ rangeToSplit_ = rangeLeft;
65
+ }
66
+ splitTask.partition.end = subTask_.partition.start + rangeToSplit_;
67
+ subTask_.partition.start = splitTask.partition.end;
68
+ return splitTask;
69
+ }
70
+
71
+ #if defined _WIN32
72
+ #if defined _M_IX86 || defined _M_X64
73
+ #pragma intrinsic(_mm_pause)
74
+ inline void Pause() { _mm_pause(); }
75
+ #endif
76
+ #elif defined __i386__ || defined __x86_64__
77
+ inline void Pause() { __asm__ __volatile__("pause;"); }
78
+ #else
79
+ inline void Pause() { ;} // may have NOP or yield equiv
80
+ #endif
81
+ }
82
+
83
+
84
+ static void SafeCallback(ProfilerCallbackFunc func_, uint32_t threadnum_)
85
+ {
86
+ if( func_ )
87
+ {
88
+ func_(threadnum_);
89
+ }
90
+ }
91
+
92
+ ProfilerCallbacks* TaskScheduler::GetProfilerCallbacks()
93
+ {
94
+ return &m_ProfilerCallbacks;
95
+ }
96
+
97
+ THREADFUNC_DECL TaskScheduler::TaskingThreadFunction( void* pArgs )
98
+ {
99
+ ThreadArgs args = *(ThreadArgs*)pArgs;
100
+ uint32_t threadNum = args.threadNum;
101
+ TaskScheduler* pTS = args.pTaskScheduler;
102
+ gtl_threadNum = threadNum;
103
+
104
+ SafeCallback( pTS->m_ProfilerCallbacks.threadStart, threadNum );
105
+
106
+ uint32_t spinCount = 0;
107
+ uint32_t hintPipeToCheck_io = threadNum + 1; // does not need to be clamped.
108
+ while( pTS->m_bRunning )
109
+ {
110
+ if(!pTS->TryRunTask( threadNum, hintPipeToCheck_io ) )
111
+ {
112
+ // no tasks, will spin then wait
113
+ ++spinCount;
114
+ if( spinCount > SPIN_COUNT )
115
+ {
116
+ pTS->WaitForTasks( threadNum );
117
+ spinCount = 0;
118
+ }
119
+ else
120
+ {
121
+ uint32_t spinBackoffCount = spinCount * SPIN_BACKOFF_MULTIPLIER;
122
+ while( spinBackoffCount )
123
+ {
124
+ Pause();
125
+ --spinBackoffCount;
126
+ }
127
+ }
128
+ }
129
+ else
130
+ {
131
+ spinCount = 0;
132
+ }
133
+ }
134
+
135
+ AtomicAdd( &pTS->m_NumThreadsRunning, -1 );
136
+ SafeCallback( pTS->m_ProfilerCallbacks.threadStop, threadNum );
137
+
138
+ return 0;
139
+ }
140
+
141
+
142
+ void TaskScheduler::StartThreads()
143
+ {
144
+ if( m_bHaveThreads )
145
+ {
146
+ return;
147
+ }
148
+ m_bRunning = true;
149
+
150
+ SemaphoreCreate( m_NewTaskSemaphore );
151
+
152
+ // we create one less thread than m_NumThreads as the main thread counts as one
153
+ m_pThreadNumStore = new ThreadArgs[m_NumThreads];
154
+ m_pThreadIDs = new threadid_t[m_NumThreads];
155
+ m_pThreadNumStore[0].threadNum = 0;
156
+ m_pThreadNumStore[0].pTaskScheduler = this;
157
+ m_pThreadIDs[0] = 0;
158
+ m_NumThreadsWaiting = 0;
159
+ m_NumThreadsRunning = 1;// acount for main thread
160
+ for( uint32_t thread = 1; thread < m_NumThreads; ++thread )
161
+ {
162
+ m_pThreadNumStore[thread].threadNum = thread;
163
+ m_pThreadNumStore[thread].pTaskScheduler = this;
164
+ ThreadCreate( &m_pThreadIDs[thread], TaskingThreadFunction, &m_pThreadNumStore[thread] );
165
+ ++m_NumThreadsRunning;
166
+ }
167
+
168
+ // ensure we have sufficient tasks to equally fill either all threads including main
169
+ // or just the threads we've launched, this is outside the firstinit as we want to be able
170
+ // to runtime change it
171
+ if( 1 == m_NumThreads )
172
+ {
173
+ m_NumPartitions = 1;
174
+ m_NumInitialPartitions = 1;
175
+ }
176
+ else
177
+ {
178
+ m_NumPartitions = m_NumThreads * (m_NumThreads - 1);
179
+ m_NumInitialPartitions = m_NumThreads - 1;
180
+ if( m_NumInitialPartitions > MAX_NUM_INITIAL_PARTITIONS )
181
+ {
182
+ m_NumInitialPartitions = MAX_NUM_INITIAL_PARTITIONS;
183
+ }
184
+ }
185
+
186
+ m_bHaveThreads = true;
187
+ }
188
+
189
+ void TaskScheduler::StopThreads( bool bWait_ )
190
+ {
191
+ if( m_bHaveThreads )
192
+ {
193
+ // wait for them threads quit before deleting data
194
+ m_bRunning = false;
195
+ while( bWait_ && m_NumThreadsRunning > 1 )
196
+ {
197
+ // keep firing event to ensure all threads pick up state of m_bRunning
198
+ SemaphoreSignal( m_NewTaskSemaphore, m_NumThreadsRunning );
199
+ }
200
+
201
+ for( uint32_t thread = 1; thread < m_NumThreads; ++thread )
202
+ {
203
+ ThreadTerminate( m_pThreadIDs[thread] );
204
+ }
205
+
206
+ m_NumThreads = 0;
207
+ delete[] m_pThreadNumStore;
208
+ delete[] m_pThreadIDs;
209
+ m_pThreadNumStore = 0;
210
+ m_pThreadIDs = 0;
211
+ SemaphoreClose( m_NewTaskSemaphore );
212
+
213
+ m_bHaveThreads = false;
214
+ m_NumThreadsWaiting = 0;
215
+ m_NumThreadsRunning = 0;
216
+ }
217
+ }
218
+
219
+ bool TaskScheduler::TryRunTask( uint32_t threadNum, uint32_t& hintPipeToCheck_io_ )
220
+ {
221
+ // check for tasks
222
+ SubTaskSet subTask;
223
+ bool bHaveTask = m_pPipesPerThread[ threadNum ].WriterTryReadFront( &subTask );
224
+
225
+ uint32_t threadToCheck = hintPipeToCheck_io_;
226
+ uint32_t checkCount = 0;
227
+ while( !bHaveTask && checkCount < m_NumThreads )
228
+ {
229
+ threadToCheck = ( hintPipeToCheck_io_ + checkCount ) % m_NumThreads;
230
+ if( threadToCheck != threadNum )
231
+ {
232
+ bHaveTask = m_pPipesPerThread[ threadToCheck ].ReaderTryReadBack( &subTask );
233
+ }
234
+ ++checkCount;
235
+ }
236
+
237
+ if( bHaveTask )
238
+ {
239
+ // update hint, will preserve value unless actually got task from another thread.
240
+ hintPipeToCheck_io_ = threadToCheck;
241
+
242
+ uint32_t partitionSize = subTask.partition.end - subTask.partition.start;
243
+ if( subTask.pTask->m_RangeToRun < partitionSize )
244
+ {
245
+ SubTaskSet taskToRun = SplitTask( subTask, subTask.pTask->m_RangeToRun );
246
+ SplitAndAddTask( gtl_threadNum, subTask, subTask.pTask->m_RangeToRun, 0 );
247
+ taskToRun.pTask->ExecuteRange( taskToRun.partition, threadNum );
248
+ AtomicAdd( &taskToRun.pTask->m_RunningCount, -1 );
249
+ }
250
+ else
251
+ {
252
+
253
+ // the task has already been divided up by AddTaskSetToPipe, so just run it
254
+ subTask.pTask->ExecuteRange( subTask.partition, threadNum );
255
+ AtomicAdd( &subTask.pTask->m_RunningCount, -1 );
256
+ }
257
+ }
258
+
259
+ return bHaveTask;
260
+
261
+ }
262
+
263
+ void TaskScheduler::WaitForTasks( uint32_t threadNum )
264
+ {
265
+ // We incrememt the number of threads waiting here in order
266
+ // to ensure that the check for tasks occurs after the increment
267
+ // to prevent a task being added after a check, then the thread waiting.
268
+ // This will occasionally result in threads being mistakenly awoken,
269
+ // but they will then go back to sleep.
270
+ AtomicAdd( &m_NumThreadsWaiting, 1 );
271
+
272
+ bool bHaveTasks = false;
273
+ for( uint32_t thread = 0; thread < m_NumThreads; ++thread )
274
+ {
275
+ if( !m_pPipesPerThread[ thread ].IsPipeEmpty() )
276
+ {
277
+ bHaveTasks = true;
278
+ break;
279
+ }
280
+ }
281
+ if( !bHaveTasks )
282
+ {
283
+ SafeCallback( m_ProfilerCallbacks.waitStart, threadNum );
284
+ SemaphoreWait( m_NewTaskSemaphore );
285
+ SafeCallback( m_ProfilerCallbacks.waitStop, threadNum );
286
+ }
287
+
288
+ int32_t prev = AtomicAdd( &m_NumThreadsWaiting, -1 );
289
+ assert( prev != 0 );
290
+ }
291
+
292
+ void TaskScheduler::WakeThreads()
293
+ {
294
+ SemaphoreSignal( m_NewTaskSemaphore, m_NumThreadsWaiting );
295
+ }
296
+
297
+ void TaskScheduler::SplitAndAddTask( uint32_t threadNum_, SubTaskSet subTask_,
298
+ uint32_t rangeToSplit_, int32_t runningCountOffset_ )
299
+ {
300
+ int32_t numAdded = 0;
301
+ while( subTask_.partition.start != subTask_.partition.end )
302
+ {
303
+ SubTaskSet taskToAdd = SplitTask( subTask_, rangeToSplit_ );
304
+
305
+ // add the partition to the pipe
306
+ ++numAdded;
307
+ if( !m_pPipesPerThread[ gtl_threadNum ].WriterTryWriteFront( taskToAdd ) )
308
+ {
309
+ if( numAdded > 1 )
310
+ {
311
+ WakeThreads();
312
+ }
313
+ // alter range to run the appropriate fraction
314
+ if( taskToAdd.pTask->m_RangeToRun < rangeToSplit_ )
315
+ {
316
+ taskToAdd.partition.end = taskToAdd.partition.start + taskToAdd.pTask->m_RangeToRun;
317
+ subTask_.partition.start = taskToAdd.partition.end;
318
+ }
319
+ taskToAdd.pTask->ExecuteRange( taskToAdd.partition, threadNum_ );
320
+ --numAdded;
321
+ }
322
+ }
323
+
324
+ // increment running count by number added
325
+ AtomicAdd( &subTask_.pTask->m_RunningCount, numAdded + runningCountOffset_ );
326
+
327
+ WakeThreads();
328
+ }
329
+
330
+ void TaskScheduler::AddTaskSetToPipe( ITaskSet* pTaskSet )
331
+ {
332
+ // set running count to -1 to guarantee it won't be found complete until all subtasks added
333
+ pTaskSet->m_RunningCount = -1;
334
+
335
+ // divide task up and add to pipe
336
+ pTaskSet->m_RangeToRun = pTaskSet->m_SetSize / m_NumPartitions;
337
+ if( pTaskSet->m_RangeToRun < pTaskSet->m_MinRange ) { pTaskSet->m_RangeToRun = pTaskSet->m_MinRange; }
338
+
339
+ uint32_t rangeToSplit = pTaskSet->m_SetSize / m_NumInitialPartitions;
340
+ if( rangeToSplit < pTaskSet->m_MinRange ) { rangeToSplit = pTaskSet->m_MinRange; }
341
+
342
+ SubTaskSet subTask;
343
+ subTask.pTask = pTaskSet;
344
+ subTask.partition.start = 0;
345
+ subTask.partition.end = pTaskSet->m_SetSize;
346
+ SplitAndAddTask( gtl_threadNum, subTask, rangeToSplit, 1 );
347
+ }
348
+
349
+ void TaskScheduler::WaitforTaskSet( const ITaskSet* pTaskSet )
350
+ {
351
+ uint32_t hintPipeToCheck_io = gtl_threadNum + 1; // does not need to be clamped.
352
+ if( pTaskSet )
353
+ {
354
+ while( pTaskSet->m_RunningCount )
355
+ {
356
+ TryRunTask( gtl_threadNum, hintPipeToCheck_io );
357
+ // should add a spin then wait for task completion event.
358
+ }
359
+ }
360
+ else
361
+ {
362
+ TryRunTask( gtl_threadNum, hintPipeToCheck_io );
363
+ }
364
+ }
365
+
366
+ void TaskScheduler::WaitforAll()
367
+ {
368
+ bool bHaveTasks = true;
369
+ uint32_t hintPipeToCheck_io = gtl_threadNum + 1; // does not need to be clamped.
370
+ int32_t threadsRunning = m_NumThreadsRunning - 1;
371
+ while( bHaveTasks || m_NumThreadsWaiting < threadsRunning )
372
+ {
373
+ TryRunTask( gtl_threadNum, hintPipeToCheck_io );
374
+ bHaveTasks = false;
375
+ for( uint32_t thread = 0; thread < m_NumThreads; ++thread )
376
+ {
377
+ if( !m_pPipesPerThread[ thread ].IsPipeEmpty() )
378
+ {
379
+ bHaveTasks = true;
380
+ break;
381
+ }
382
+ }
383
+ }
384
+ }
385
+
386
+ void TaskScheduler::WaitforAllAndShutdown()
387
+ {
388
+ WaitforAll();
389
+ StopThreads(true);
390
+ delete[] m_pPipesPerThread;
391
+ m_pPipesPerThread = 0;
392
+ }
393
+
394
+ uint32_t TaskScheduler::GetNumTaskThreads() const
395
+ {
396
+ return m_NumThreads;
397
+ }
398
+
399
+ TaskScheduler::TaskScheduler()
400
+ : m_pPipesPerThread(NULL)
401
+ , m_NumThreads(0)
402
+ , m_pThreadNumStore(NULL)
403
+ , m_pThreadIDs(NULL)
404
+ , m_bRunning(false)
405
+ , m_NumThreadsRunning(0)
406
+ , m_NumThreadsWaiting(0)
407
+ , m_NumPartitions(0)
408
+ , m_bHaveThreads(false)
409
+ {
410
+ memset(&m_ProfilerCallbacks, 0, sizeof(m_ProfilerCallbacks));
411
+ }
412
+
413
+ TaskScheduler::~TaskScheduler()
414
+ {
415
+ StopThreads( true ); // Stops threads, waiting for them.
416
+
417
+ delete[] m_pPipesPerThread;
418
+ m_pPipesPerThread = 0;
419
+ }
420
+
421
+ void TaskScheduler::Initialize( uint32_t numThreads_ )
422
+ {
423
+ assert( numThreads_ );
424
+ StopThreads( true ); // Stops threads, waiting for them.
425
+ delete[] m_pPipesPerThread;
426
+
427
+ m_NumThreads = numThreads_;
428
+
429
+ m_pPipesPerThread = new TaskPipe[ m_NumThreads ];
430
+
431
+ StartThreads();
432
+ }
433
+
434
+ void TaskScheduler::Initialize()
435
+ {
436
+ Initialize( GetNumHardwareThreads() );
437
+ }
third_party/tracy/examples/ToyPathTracer/Source/enkiTS/TaskScheduler.h ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) 2013 Doug Binks
2
+ //
3
+ // This software is provided 'as-is', without any express or implied
4
+ // warranty. In no event will the authors be held liable for any damages
5
+ // arising from the use of this software.
6
+ //
7
+ // Permission is granted to anyone to use this software for any purpose,
8
+ // including commercial applications, and to alter it and redistribute it
9
+ // freely, subject to the following restrictions:
10
+ //
11
+ // 1. The origin of this software must not be misrepresented; you must not
12
+ // claim that you wrote the original software. If you use this software
13
+ // in a product, an acknowledgement in the product documentation would be
14
+ // appreciated but is not required.
15
+ // 2. Altered source versions must be plainly marked as such, and must not be
16
+ // misrepresented as being the original software.
17
+ // 3. This notice may not be removed or altered from any source distribution.
18
+
19
+ #pragma once
20
+
21
+ #include <stdint.h>
22
+ #include "Threads.h"
23
+
24
+ namespace enki
25
+ {
26
+
27
+ struct TaskSetPartition
28
+ {
29
+ uint32_t start;
30
+ uint32_t end;
31
+ };
32
+
33
+ class TaskScheduler;
34
+ class TaskPipe;
35
+ struct ThreadArgs;
36
+ struct SubTaskSet;
37
+
38
+ // Subclass ITaskSet to create tasks.
39
+ // TaskSets can be re-used, but check
40
+ class ITaskSet
41
+ {
42
+ public:
43
+ ITaskSet()
44
+ : m_SetSize(1)
45
+ , m_MinRange(1)
46
+ , m_RunningCount(0)
47
+ , m_RangeToRun(1)
48
+ {}
49
+
50
+ ITaskSet( uint32_t setSize_ )
51
+ : m_SetSize( setSize_ )
52
+ , m_MinRange(1)
53
+ , m_RunningCount(0)
54
+ , m_RangeToRun(1)
55
+ {}
56
+
57
+ ITaskSet( uint32_t setSize_, uint32_t minRange_ )
58
+ : m_SetSize( setSize_ )
59
+ , m_MinRange( minRange_ )
60
+ , m_RunningCount(0)
61
+ , m_RangeToRun(minRange_)
62
+ {}
63
+
64
+ // Execute range should be overloaded to process tasks. It will be called with a
65
+ // range_ where range.start >= 0; range.start < range.end; and range.end < m_SetSize;
66
+ // The range values should be mapped so that linearly processing them in order is cache friendly
67
+ // i.e. neighbouring values should be close together.
68
+ // threadnum should not be used for changing processing of data, it's intended purpose
69
+ // is to allow per-thread data buckets for output.
70
+ virtual void ExecuteRange( TaskSetPartition range, uint32_t threadnum ) = 0;
71
+
72
+ // Size of set - usually the number of data items to be processed, see ExecuteRange. Defaults to 1
73
+ uint32_t m_SetSize;
74
+
75
+ // Minimum size of of TaskSetPartition range when splitting a task set into partitions.
76
+ // This should be set to a value which results in computation effort of at least 10k
77
+ // clock cycles to minimize tast scheduler overhead.
78
+ // NOTE: The last partition will be smaller than m_MinRange if m_SetSize is not a multiple
79
+ // of m_MinRange.
80
+ // Also known as grain size in literature.
81
+ uint32_t m_MinRange;
82
+
83
+ bool GetIsComplete()
84
+ {
85
+ return 0 == m_RunningCount;
86
+ }
87
+ private:
88
+ friend class TaskScheduler;
89
+ volatile int32_t m_RunningCount;
90
+ uint32_t m_RangeToRun;
91
+ };
92
+
93
+ // TaskScheduler implements several callbacks intended for profilers
94
+ typedef void (*ProfilerCallbackFunc)( uint32_t threadnum_ );
95
+ struct ProfilerCallbacks
96
+ {
97
+ ProfilerCallbackFunc threadStart;
98
+ ProfilerCallbackFunc threadStop;
99
+ ProfilerCallbackFunc waitStart;
100
+ ProfilerCallbackFunc waitStop;
101
+ };
102
+
103
+ class TaskScheduler
104
+ {
105
+ public:
106
+ TaskScheduler();
107
+ ~TaskScheduler();
108
+
109
+ // Call either Initialize() or Initialize( numThreads_ ) before adding tasks.
110
+
111
+ // Initialize() will create GetNumHardwareThreads()-1 threads, which is
112
+ // sufficient to fill the system when including the main thread.
113
+ // Initialize can be called multiple times - it will wait for completion
114
+ // before re-initializing.
115
+ void Initialize();
116
+
117
+ // Initialize( numThreads_ ) - numThreads_ (must be > 0)
118
+ // will create numThreads_-1 threads, as thread 0 is
119
+ // the thread on which the initialize was called.
120
+ void Initialize( uint32_t numThreads_ );
121
+
122
+
123
+ // Adds the TaskSet to pipe and returns if the pipe is not full.
124
+ // If the pipe is full, pTaskSet is run.
125
+ // should only be called from main thread, or within a task
126
+ void AddTaskSetToPipe( ITaskSet* pTaskSet );
127
+
128
+ // Runs the TaskSets in pipe until true == pTaskSet->GetIsComplete();
129
+ // should only be called from thread which created the taskscheduler , or within a task
130
+ // if called with 0 it will try to run tasks, and return if none available.
131
+ void WaitforTaskSet( const ITaskSet* pTaskSet );
132
+
133
+ // Waits for all task sets to complete - not guaranteed to work unless we know we
134
+ // are in a situation where tasks aren't being continuosly added.
135
+ void WaitforAll();
136
+
137
+ // Waits for all task sets to complete and shutdown threads - not guaranteed to work unless we know we
138
+ // are in a situation where tasks aren't being continuosly added.
139
+ void WaitforAllAndShutdown();
140
+
141
+ // Returns the number of threads created for running tasks + 1
142
+ // to account for the main thread.
143
+ uint32_t GetNumTaskThreads() const;
144
+
145
+ // Returns the ProfilerCallbacks structure so that it can be modified to
146
+ // set the callbacks.
147
+ ProfilerCallbacks* GetProfilerCallbacks();
148
+
149
+ private:
150
+ static THREADFUNC_DECL TaskingThreadFunction( void* pArgs );
151
+ void WaitForTasks( uint32_t threadNum );
152
+ bool TryRunTask( uint32_t threadNum, uint32_t& hintPipeToCheck_io_ );
153
+ void StartThreads();
154
+ void StopThreads( bool bWait_ );
155
+ void SplitAndAddTask( uint32_t threadNum_, SubTaskSet subTask_,
156
+ uint32_t rangeToSplit_, int32_t runningCountOffset_ );
157
+ void WakeThreads();
158
+
159
+ TaskPipe* m_pPipesPerThread;
160
+
161
+ uint32_t m_NumThreads;
162
+ ThreadArgs* m_pThreadNumStore;
163
+ threadid_t* m_pThreadIDs;
164
+ volatile bool m_bRunning;
165
+ volatile int32_t m_NumThreadsRunning;
166
+ volatile int32_t m_NumThreadsWaiting;
167
+ uint32_t m_NumPartitions;
168
+ uint32_t m_NumInitialPartitions;
169
+ semaphoreid_t m_NewTaskSemaphore;
170
+ bool m_bHaveThreads;
171
+ ProfilerCallbacks m_ProfilerCallbacks;
172
+
173
+ TaskScheduler( const TaskScheduler& nocopy );
174
+ TaskScheduler& operator=( const TaskScheduler& nocopy );
175
+ };
176
+
177
+ }
third_party/tracy/examples/ToyPathTracer/Source/enkiTS/TaskScheduler_c.cpp ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) 2013 Doug Binks
2
+ //
3
+ // This software is provided 'as-is', without any express or implied
4
+ // warranty. In no event will the authors be held liable for any damages
5
+ // arising from the use of this software.
6
+ //
7
+ // Permission is granted to anyone to use this software for any purpose,
8
+ // including commercial applications, and to alter it and redistribute it
9
+ // freely, subject to the following restrictions:
10
+ //
11
+ // 1. The origin of this software must not be misrepresented; you must not
12
+ // claim that you wrote the original software. If you use this software
13
+ // in a product, an acknowledgement in the product documentation would be
14
+ // appreciated but is not required.
15
+ // 2. Altered source versions must be plainly marked as such, and must not be
16
+ // misrepresented as being the original software.
17
+ // 3. This notice may not be removed or altered from any source distribution.
18
+
19
+ #include "TaskScheduler_c.h"
20
+ #include "TaskScheduler.h"
21
+
22
+ #include <assert.h>
23
+
24
+ using namespace enki;
25
+
26
+ struct enkiTaskScheduler : TaskScheduler
27
+ {
28
+ };
29
+
30
+ struct enkiTaskSet : ITaskSet
31
+ {
32
+ enkiTaskSet( enkiTaskExecuteRange taskFun_ ) : taskFun(taskFun_), pArgs(NULL) {}
33
+
34
+ virtual void ExecuteRange( TaskSetPartition range, uint32_t threadnum )
35
+ {
36
+ taskFun( range.start, range.end, threadnum, pArgs );
37
+ }
38
+
39
+ enkiTaskExecuteRange taskFun;
40
+ void* pArgs;
41
+ };
42
+
43
+ enkiTaskScheduler* enkiNewTaskScheduler()
44
+ {
45
+ enkiTaskScheduler* pETS = new enkiTaskScheduler();
46
+ return pETS;
47
+ }
48
+
49
+ void enkiInitTaskScheduler( enkiTaskScheduler* pETS_ )
50
+ {
51
+ pETS_->Initialize();
52
+ }
53
+
54
+ void enkiInitTaskSchedulerNumThreads( enkiTaskScheduler* pETS_, uint32_t numThreads_ )
55
+ {
56
+ pETS_->Initialize( numThreads_ );
57
+ }
58
+
59
+ void enkiDeleteTaskScheduler( enkiTaskScheduler* pETS_ )
60
+ {
61
+ delete pETS_;
62
+ }
63
+
64
+ enkiTaskSet* enkiCreateTaskSet( enkiTaskScheduler* pETS_, enkiTaskExecuteRange taskFunc_ )
65
+ {
66
+ return new enkiTaskSet( taskFunc_ );
67
+ }
68
+
69
+ void enkiDeleteTaskSet( enkiTaskSet* pTaskSet_ )
70
+ {
71
+ delete pTaskSet_;
72
+ }
73
+
74
+ void enkiAddTaskSetToPipe( enkiTaskScheduler* pETS_, enkiTaskSet* pTaskSet_, void* pArgs_, uint32_t setSize_ )
75
+ {
76
+ assert( pTaskSet_ );
77
+ assert( pTaskSet_->taskFun );
78
+
79
+ pTaskSet_->m_SetSize = setSize_;
80
+ pTaskSet_->pArgs = pArgs_;
81
+ pETS_->AddTaskSetToPipe( pTaskSet_ );
82
+ }
83
+
84
+ void enkiAddTaskSetToPipeMinRange(enkiTaskScheduler * pETS_, enkiTaskSet * pTaskSet_, void * pArgs_, uint32_t setSize_, uint32_t minRange_)
85
+ {
86
+ assert( pTaskSet_ );
87
+ assert( pTaskSet_->taskFun );
88
+
89
+ pTaskSet_->m_SetSize = setSize_;
90
+ pTaskSet_->m_MinRange = minRange_;
91
+ pTaskSet_->pArgs = pArgs_;
92
+ pETS_->AddTaskSetToPipe( pTaskSet_ );
93
+ }
94
+
95
+ int enkiIsTaskSetComplete( enkiTaskScheduler* pETS_, enkiTaskSet* pTaskSet_ )
96
+ {
97
+ assert( pTaskSet_ );
98
+ return ( pTaskSet_->GetIsComplete() ) ? 1 : 0;
99
+ }
100
+
101
+ void enkiWaitForTaskSet( enkiTaskScheduler* pETS_, enkiTaskSet* pTaskSet_ )
102
+ {
103
+ pETS_->WaitforTaskSet( pTaskSet_ );
104
+ }
105
+
106
+ void enkiWaitForAll( enkiTaskScheduler* pETS_ )
107
+ {
108
+ pETS_->WaitforAll();
109
+ }
110
+
111
+
112
+ uint32_t enkiGetNumTaskThreads( enkiTaskScheduler* pETS_ )
113
+ {
114
+ return pETS_->GetNumTaskThreads();
115
+ }
116
+
117
+ enkiProfilerCallbacks* enkiGetProfilerCallbacks( enkiTaskScheduler* pETS_ )
118
+ {
119
+ assert( sizeof(enkiProfilerCallbacks) == sizeof(enki::ProfilerCallbacks) );
120
+ return (enkiProfilerCallbacks*)pETS_->GetProfilerCallbacks();
121
+ }
122
+
third_party/tracy/examples/ToyPathTracer/Source/enkiTS/TaskScheduler_c.h ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) 2013 Doug Binks
2
+ //
3
+ // This software is provided 'as-is', without any express or implied
4
+ // warranty. In no event will the authors be held liable for any damages
5
+ // arising from the use of this software.
6
+ //
7
+ // Permission is granted to anyone to use this software for any purpose,
8
+ // including commercial applications, and to alter it and redistribute it
9
+ // freely, subject to the following restrictions:
10
+ //
11
+ // 1. The origin of this software must not be misrepresented; you must not
12
+ // claim that you wrote the original software. If you use this software
13
+ // in a product, an acknowledgement in the product documentation would be
14
+ // appreciated but is not required.
15
+ // 2. Altered source versions must be plainly marked as such, and must not be
16
+ // misrepresented as being the original software.
17
+ // 3. This notice may not be removed or altered from any source distribution.
18
+
19
+ #pragma once
20
+
21
+ #ifdef __cplusplus
22
+ extern "C" {
23
+ #endif
24
+
25
+ #include <stdint.h>
26
+
27
+ typedef struct enkiTaskScheduler enkiTaskScheduler;
28
+ typedef struct enkiTaskSet enkiTaskSet;
29
+
30
+ typedef void (* enkiTaskExecuteRange)( uint32_t start_, uint32_t end, uint32_t threadnum_, void* pArgs_ );
31
+
32
+
33
+ // Create a new task scheduler
34
+ enkiTaskScheduler* enkiNewTaskScheduler();
35
+
36
+ // Initialize task scheduler - will create GetNumHardwareThreads()-1 threads, which is
37
+ // sufficient to fill the system when including the main thread.
38
+ // Initialize can be called multiple times - it will wait for completion
39
+ // before re-initializing.
40
+ void enkiInitTaskScheduler( enkiTaskScheduler* pETS_ );
41
+
42
+ // Initialize a task scheduler with numThreads_ (must be > 0)
43
+ // will create numThreads_-1 threads, as thread 0 is
44
+ // the thread on which the initialize was called.
45
+ void enkiInitTaskSchedulerNumThreads( enkiTaskScheduler* pETS_, uint32_t numThreads_ );
46
+
47
+
48
+ // Delete a task scheduler
49
+ void enkiDeleteTaskScheduler( enkiTaskScheduler* pETS_ );
50
+
51
+ // Create a task set.
52
+ enkiTaskSet* enkiCreateTaskSet( enkiTaskScheduler* pETS_, enkiTaskExecuteRange taskFunc_ );
53
+
54
+ // Delete a task set.
55
+ void enkiDeleteTaskSet( enkiTaskSet* pTaskSet_ );
56
+
57
+ // Schedule the task
58
+ void enkiAddTaskSetToPipe( enkiTaskScheduler* pETS_, enkiTaskSet* pTaskSet_,
59
+ void* pArgs_, uint32_t setSize_ );
60
+
61
+ // Schedule the task with a minimum range.
62
+ // This should be set to a value which results in computation effort of at least 10k
63
+ // clock cycles to minimize tast scheduler overhead.
64
+ // NOTE: The last partition will be smaller than m_MinRange if m_SetSize is not a multiple
65
+ // of m_MinRange.
66
+ // Also known as grain size in literature.
67
+ void enkiAddTaskSetToPipeMinRange( enkiTaskScheduler* pETS_, enkiTaskSet* pTaskSet_,
68
+ void* pArgs_, uint32_t setSize_, uint32_t minRange_ );
69
+
70
+
71
+ // Check if TaskSet is complete. Doesn't wait. Returns 1 if complete, 0 if not.
72
+ int enkiIsTaskSetComplete( enkiTaskScheduler* pETS_, enkiTaskSet* pTaskSet_ );
73
+
74
+
75
+ // Wait for a given task.
76
+ // should only be called from thread which created the taskscheduler , or within a task
77
+ // if called with 0 it will try to run tasks, and return if none available.
78
+ void enkiWaitForTaskSet( enkiTaskScheduler* pETS_, enkiTaskSet* pTaskSet_ );
79
+
80
+
81
+ // Waits for all task sets to complete - not guaranteed to work unless we know we
82
+ // are in a situation where tasks aren't being continuosly added.
83
+ void enkiWaitForAll( enkiTaskScheduler* pETS_ );
84
+
85
+
86
+ // get number of threads
87
+ uint32_t enkiGetNumTaskThreads( enkiTaskScheduler* pETS_ );
88
+
89
+ // TaskScheduler implements several callbacks intended for profilers
90
+ typedef void (*enkiProfilerCallbackFunc)( uint32_t threadnum_ );
91
+ struct enkiProfilerCallbacks
92
+ {
93
+ enkiProfilerCallbackFunc threadStart;
94
+ enkiProfilerCallbackFunc threadStop;
95
+ enkiProfilerCallbackFunc waitStart;
96
+ enkiProfilerCallbackFunc waitStop;
97
+ };
98
+
99
+ // Get the callback structure so it can be set
100
+ struct enkiProfilerCallbacks* enkiGetProfilerCallbacks( enkiTaskScheduler* pETS_ );
101
+
102
+ #ifdef __cplusplus
103
+ }
104
+ #endif
third_party/tracy/examples/ToyPathTracer/Source/enkiTS/Threads.h ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Copyright (c) 2013 Doug Binks
2
+ //
3
+ // This software is provided 'as-is', without any express or implied
4
+ // warranty. In no event will the authors be held liable for any damages
5
+ // arising from the use of this software.
6
+ //
7
+ // Permission is granted to anyone to use this software for any purpose,
8
+ // including commercial applications, and to alter it and redistribute it
9
+ // freely, subject to the following restrictions:
10
+ //
11
+ // 1. The origin of this software must not be misrepresented; you must not
12
+ // claim that you wrote the original software. If you use this software
13
+ // in a product, an acknowledgement in the product documentation would be
14
+ // appreciated but is not required.
15
+ // 2. Altered source versions must be plainly marked as such, and must not be
16
+ // misrepresented as being the original software.
17
+ // 3. This notice may not be removed or altered from any source distribution.
18
+
19
+ #pragma once
20
+
21
+ #include <stdint.h>
22
+ #include <assert.h>
23
+
24
+ #ifdef _WIN32
25
+
26
+ #include "Atomics.h"
27
+
28
+ #define WIN32_LEAN_AND_MEAN
29
+ #include <Windows.h>
30
+
31
+ #define THREADFUNC_DECL DWORD WINAPI
32
+ #define THREAD_LOCAL __declspec( thread )
33
+
34
+ namespace enki
35
+ {
36
+ typedef HANDLE threadid_t;
37
+
38
+ // declare the thread start function as:
39
+ // THREADFUNC_DECL MyThreadStart( void* pArg );
40
+ inline bool ThreadCreate( threadid_t* returnid, DWORD ( WINAPI *StartFunc) (void* ), void* pArg )
41
+ {
42
+ // posix equiv pthread_create
43
+ DWORD threadid;
44
+ *returnid = CreateThread( 0, 0, StartFunc, pArg, 0, &threadid );
45
+ return *returnid != NULL;
46
+ }
47
+
48
+ inline bool ThreadTerminate( threadid_t threadid )
49
+ {
50
+ // posix equiv pthread_cancel
51
+ return CloseHandle( threadid ) == 0;
52
+ }
53
+
54
+ inline uint32_t GetNumHardwareThreads()
55
+ {
56
+ SYSTEM_INFO sysInfo;
57
+ GetSystemInfo(&sysInfo);
58
+ return sysInfo.dwNumberOfProcessors;
59
+ }
60
+ }
61
+
62
+ #else // posix
63
+
64
+ #include <pthread.h>
65
+ #include <unistd.h>
66
+ #define THREADFUNC_DECL void*
67
+ #define THREAD_LOCAL __thread
68
+
69
+ namespace enki
70
+ {
71
+ typedef pthread_t threadid_t;
72
+
73
+ // declare the thread start function as:
74
+ // THREADFUNC_DECL MyThreadStart( void* pArg );
75
+ inline bool ThreadCreate( threadid_t* returnid, void* ( *StartFunc) (void* ), void* pArg )
76
+ {
77
+ // posix equiv pthread_create
78
+ int32_t retval = pthread_create( returnid, NULL, StartFunc, pArg );
79
+
80
+ return retval == 0;
81
+ }
82
+
83
+ inline bool ThreadTerminate( threadid_t threadid )
84
+ {
85
+ // posix equiv pthread_cancel
86
+ return pthread_cancel( threadid ) == 0;
87
+ }
88
+
89
+ inline uint32_t GetNumHardwareThreads()
90
+ {
91
+ return (uint32_t)sysconf( _SC_NPROCESSORS_ONLN );
92
+ }
93
+ }
94
+
95
+ #endif // posix
96
+
97
+
98
+ // Semaphore implementation
99
+ #ifdef _WIN32
100
+
101
+ namespace enki
102
+ {
103
+ struct semaphoreid_t
104
+ {
105
+ HANDLE sem;
106
+ };
107
+
108
+ inline void SemaphoreCreate( semaphoreid_t& semaphoreid )
109
+ {
110
+ semaphoreid.sem = CreateSemaphore(NULL, 0, MAXLONG, NULL );
111
+ }
112
+
113
+ inline void SemaphoreClose( semaphoreid_t& semaphoreid )
114
+ {
115
+ CloseHandle( semaphoreid.sem );
116
+ }
117
+
118
+ inline void SemaphoreWait( semaphoreid_t& semaphoreid )
119
+ {
120
+ DWORD retval = WaitForSingleObject( semaphoreid.sem, INFINITE );
121
+
122
+ assert( retval != WAIT_FAILED );
123
+ }
124
+
125
+ inline void SemaphoreSignal( semaphoreid_t& semaphoreid, int32_t countWaiting )
126
+ {
127
+ if( countWaiting )
128
+ {
129
+ ReleaseSemaphore( semaphoreid.sem, countWaiting, NULL );
130
+ }
131
+ }
132
+ }
133
+ #elif defined(__MACH__)
134
+
135
+ // OS X does not have POSIX semaphores
136
+ // see https://developer.apple.com/library/content/documentation/Darwin/Conceptual/KernelProgramming/synchronization/synchronization.html
137
+ #include <mach/mach.h>
138
+
139
+ namespace enki
140
+ {
141
+
142
+ struct semaphoreid_t
143
+ {
144
+ semaphore_t sem;
145
+ };
146
+
147
+ inline void SemaphoreCreate( semaphoreid_t& semaphoreid )
148
+ {
149
+ semaphore_create( mach_task_self(), &semaphoreid.sem, SYNC_POLICY_FIFO, 0 );
150
+ }
151
+
152
+ inline void SemaphoreClose( semaphoreid_t& semaphoreid )
153
+ {
154
+ semaphore_destroy( mach_task_self(), semaphoreid.sem );
155
+ }
156
+
157
+ inline void SemaphoreWait( semaphoreid_t& semaphoreid )
158
+ {
159
+ semaphore_wait( semaphoreid.sem );
160
+ }
161
+
162
+ inline void SemaphoreSignal( semaphoreid_t& semaphoreid, int32_t countWaiting )
163
+ {
164
+ while( countWaiting-- > 0 )
165
+ {
166
+ semaphore_signal( semaphoreid.sem );
167
+ }
168
+ }
169
+ }
170
+
171
+ #else // POSIX
172
+
173
+ #include <semaphore.h>
174
+
175
+ namespace enki
176
+ {
177
+
178
+ struct semaphoreid_t
179
+ {
180
+ sem_t sem;
181
+ };
182
+
183
+ inline void SemaphoreCreate( semaphoreid_t& semaphoreid )
184
+ {
185
+ int err = sem_init( &semaphoreid.sem, 0, 0 );
186
+ assert( err == 0 );
187
+ }
188
+
189
+ inline void SemaphoreClose( semaphoreid_t& semaphoreid )
190
+ {
191
+ sem_destroy( &semaphoreid.sem );
192
+ }
193
+
194
+ inline void SemaphoreWait( semaphoreid_t& semaphoreid )
195
+ {
196
+ int err = sem_wait( &semaphoreid.sem );
197
+ assert( err == 0 );
198
+ }
199
+
200
+ inline void SemaphoreSignal( semaphoreid_t& semaphoreid, int32_t countWaiting )
201
+ {
202
+ while( countWaiting-- > 0 )
203
+ {
204
+ sem_post( &semaphoreid.sem );
205
+ }
206
+ }
207
+ }
208
+ #endif
209
+
210
+
third_party/tracy/examples/ToyPathTracer/Windows/ComputeShader.hlsl ADDED
@@ -0,0 +1,395 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "../Source/Config.h"
2
+
3
+ inline uint RNG(inout uint state)
4
+ {
5
+ uint x = state;
6
+ x ^= x << 13;
7
+ x ^= x >> 17;
8
+ x ^= x << 15;
9
+ state = x;
10
+ return x;
11
+ }
12
+
13
+ float RandomFloat01(inout uint state)
14
+ {
15
+ return (RNG(state) & 0xFFFFFF) / 16777216.0f;
16
+ }
17
+
18
+ float3 RandomInUnitDisk(inout uint state)
19
+ {
20
+ float a = RandomFloat01(state) * 2.0f * 3.1415926f;
21
+ float2 xy = float2(cos(a), sin(a));
22
+ xy *= sqrt(RandomFloat01(state));
23
+ return float3(xy, 0);
24
+ }
25
+ float3 RandomInUnitSphere(inout uint state)
26
+ {
27
+ float z = RandomFloat01(state) * 2.0f - 1.0f;
28
+ float t = RandomFloat01(state) * 2.0f * 3.1415926f;
29
+ float r = sqrt(max(0.0, 1.0f - z * z));
30
+ float x = r * cos(t);
31
+ float y = r * sin(t);
32
+ float3 res = float3(x, y, z);
33
+ res *= pow(RandomFloat01(state), 1.0 / 3.0);
34
+ return res;
35
+ }
36
+ float3 RandomUnitVector(inout uint state)
37
+ {
38
+ float z = RandomFloat01(state) * 2.0f - 1.0f;
39
+ float a = RandomFloat01(state) * 2.0f * 3.1415926f;
40
+ float r = sqrt(1.0f - z * z);
41
+ float x = r * cos(a);
42
+ float y = r * sin(a);
43
+ return float3(x, y, z);
44
+ }
45
+
46
+
47
+
48
+ struct Ray
49
+ {
50
+ float3 orig;
51
+ float3 dir;
52
+ };
53
+ Ray MakeRay(float3 orig_, float3 dir_) { Ray r; r.orig = orig_; r.dir = dir_; return r; }
54
+ float3 RayPointAt(Ray r, float t) { return r.orig + r.dir * t; }
55
+
56
+
57
+ inline bool refract(float3 v, float3 n, float nint, out float3 outRefracted)
58
+ {
59
+ float dt = dot(v, n);
60
+ float discr = 1.0f - nint * nint*(1 - dt * dt);
61
+ if (discr > 0)
62
+ {
63
+ outRefracted = nint * (v - n * dt) - n * sqrt(discr);
64
+ return true;
65
+ }
66
+ return false;
67
+ }
68
+ inline float schlick(float cosine, float ri)
69
+ {
70
+ float r0 = (1 - ri) / (1 + ri);
71
+ r0 = r0 * r0;
72
+ // note: saturate to guard against possible tiny negative numbers
73
+ return r0 + (1 - r0)*pow(saturate(1 - cosine), 5);
74
+ }
75
+
76
+ struct Hit
77
+ {
78
+ float3 pos;
79
+ float3 normal;
80
+ float t;
81
+ };
82
+
83
+ struct Sphere
84
+ {
85
+ float3 center;
86
+ float radius;
87
+ float invRadius;
88
+ };
89
+
90
+ #define MatLambert 0
91
+ #define MatMetal 1
92
+ #define MatDielectric 2
93
+
94
+ struct Material
95
+ {
96
+ int type;
97
+ float3 albedo;
98
+ float3 emissive;
99
+ float roughness;
100
+ float ri;
101
+ };
102
+
103
+ groupshared Sphere s_GroupSpheres[kCSMaxObjects];
104
+ groupshared Material s_GroupMaterials[kCSMaxObjects];
105
+ groupshared int s_GroupEmissives[kCSMaxObjects];
106
+
107
+
108
+ struct Camera
109
+ {
110
+ float3 origin;
111
+ float3 lowerLeftCorner;
112
+ float3 horizontal;
113
+ float3 vertical;
114
+ float3 u, v, w;
115
+ float lensRadius;
116
+ };
117
+
118
+ Ray CameraGetRay(Camera cam, float s, float t, inout uint state)
119
+ {
120
+ float3 rd = cam.lensRadius * RandomInUnitDisk(state);
121
+ float3 offset = cam.u * rd.x + cam.v * rd.y;
122
+ return MakeRay(cam.origin + offset, normalize(cam.lowerLeftCorner + s * cam.horizontal + t * cam.vertical - cam.origin - offset));
123
+ }
124
+
125
+
126
+ int HitSpheres(Ray r, int sphereCount, float tMin, float tMax, inout Hit outHit)
127
+ {
128
+ float hitT = tMax;
129
+ int id = -1;
130
+ for (int i = 0; i < sphereCount; ++i)
131
+ {
132
+ Sphere s = s_GroupSpheres[i];
133
+ float3 co = s.center - r.orig;
134
+ float nb = dot(co, r.dir);
135
+ float c = dot(co, co) - s.radius*s.radius;
136
+ float discr = nb * nb - c;
137
+ if (discr > 0)
138
+ {
139
+ float discrSq = sqrt(discr);
140
+
141
+ // Try earlier t
142
+ float t = nb - discrSq;
143
+ if (t <= tMin) // before min, try later t!
144
+ t = nb + discrSq;
145
+
146
+ if (t > tMin && t < hitT)
147
+ {
148
+ id = i;
149
+ hitT = t;
150
+ }
151
+ }
152
+ }
153
+
154
+ if (id != -1)
155
+ {
156
+ outHit.pos = RayPointAt(r, hitT);
157
+ outHit.normal = (outHit.pos - s_GroupSpheres[id].center) * s_GroupSpheres[id].invRadius;
158
+ outHit.t = hitT;
159
+ }
160
+ return id;
161
+ }
162
+
163
+ struct Params
164
+ {
165
+ Camera cam;
166
+ int sphereCount;
167
+ int screenWidth;
168
+ int screenHeight;
169
+ int frames;
170
+ float invWidth;
171
+ float invHeight;
172
+ float lerpFac;
173
+ int emissiveCount;
174
+ };
175
+
176
+
177
+ #define kMinT 0.001f
178
+ #define kMaxT 1.0e7f
179
+ #define kMaxDepth 10
180
+
181
+
182
+ static int HitWorld(int sphereCount, Ray r, float tMin, float tMax, inout Hit outHit)
183
+ {
184
+ return HitSpheres(r, sphereCount, tMin, tMax, outHit);
185
+ }
186
+
187
+
188
+ static bool Scatter(int sphereCount, int emissiveCount, int matID, Ray r_in, Hit rec, out float3 attenuation, out Ray scattered, out float3 outLightE, inout int inoutRayCount, inout uint state)
189
+ {
190
+ outLightE = float3(0, 0, 0);
191
+ Material mat = s_GroupMaterials[matID];
192
+ if (mat.type == MatLambert)
193
+ {
194
+ // random point on unit sphere that is tangent to the hit point
195
+ float3 target = rec.pos + rec.normal + RandomUnitVector(state);
196
+ scattered = MakeRay(rec.pos, normalize(target - rec.pos));
197
+ attenuation = mat.albedo;
198
+
199
+ // sample lights
200
+ #if DO_LIGHT_SAMPLING
201
+ for (int j = 0; j < emissiveCount; ++j)
202
+ {
203
+ int i = s_GroupEmissives[j];
204
+ if (matID == i)
205
+ continue; // skip self
206
+ Material smat = s_GroupMaterials[i];
207
+ Sphere s = s_GroupSpheres[i];
208
+
209
+ // create a random direction towards sphere
210
+ // coord system for sampling: sw, su, sv
211
+ float3 sw = normalize(s.center - rec.pos);
212
+ float3 su = normalize(cross(abs(sw.x)>0.01f ? float3(0, 1, 0) : float3(1, 0, 0), sw));
213
+ float3 sv = cross(sw, su);
214
+ // sample sphere by solid angle
215
+ float cosAMax = sqrt(1.0f - s.radius*s.radius / dot(rec.pos - s.center, rec.pos - s.center));
216
+ float eps1 = RandomFloat01(state), eps2 = RandomFloat01(state);
217
+ float cosA = 1.0f - eps1 + eps1 * cosAMax;
218
+ float sinA = sqrt(1.0f - cosA * cosA);
219
+ float phi = 2 * 3.1415926 * eps2;
220
+ float3 l = su * cos(phi) * sinA + sv * sin(phi) * sinA + sw * cosA;
221
+
222
+ // shoot shadow ray
223
+ Hit lightHit;
224
+ ++inoutRayCount;
225
+ int hitID = HitWorld(sphereCount, MakeRay(rec.pos, l), kMinT, kMaxT, lightHit);
226
+ if (hitID == i)
227
+ {
228
+ float omega = 2 * 3.1415926 * (1 - cosAMax);
229
+
230
+ float3 rdir = r_in.dir;
231
+ float3 nl = dot(rec.normal, rdir) < 0 ? rec.normal : -rec.normal;
232
+ outLightE += (mat.albedo * smat.emissive) * (max(0.0f, dot(l, nl)) * omega / 3.1415926);
233
+ }
234
+ }
235
+ #endif
236
+ return true;
237
+ }
238
+ else if (mat.type == MatMetal)
239
+ {
240
+ float3 refl = reflect(r_in.dir, rec.normal);
241
+ // reflected ray, and random inside of sphere based on roughness
242
+ float roughness = mat.roughness;
243
+ #if DO_MITSUBA_COMPARE
244
+ roughness = 0; // until we get better BRDF for metals
245
+ #endif
246
+ scattered = MakeRay(rec.pos, normalize(refl + roughness*RandomInUnitSphere(state)));
247
+ attenuation = mat.albedo;
248
+ return dot(scattered.dir, rec.normal) > 0;
249
+ }
250
+ else if (mat.type == MatDielectric)
251
+ {
252
+ float3 outwardN;
253
+ float3 rdir = r_in.dir;
254
+ float3 refl = reflect(rdir, rec.normal);
255
+ float nint;
256
+ attenuation = float3(1, 1, 1);
257
+ float3 refr;
258
+ float reflProb;
259
+ float cosine;
260
+ if (dot(rdir, rec.normal) > 0)
261
+ {
262
+ outwardN = -rec.normal;
263
+ nint = mat.ri;
264
+ cosine = mat.ri * dot(rdir, rec.normal);
265
+ }
266
+ else
267
+ {
268
+ outwardN = rec.normal;
269
+ nint = 1.0f / mat.ri;
270
+ cosine = -dot(rdir, rec.normal);
271
+ }
272
+ if (refract(rdir, outwardN, nint, refr))
273
+ {
274
+ reflProb = schlick(cosine, mat.ri);
275
+ }
276
+ else
277
+ {
278
+ reflProb = 1;
279
+ }
280
+ if (RandomFloat01(state) < reflProb)
281
+ scattered = MakeRay(rec.pos, normalize(refl));
282
+ else
283
+ scattered = MakeRay(rec.pos, normalize(refr));
284
+ }
285
+ else
286
+ {
287
+ attenuation = float3(1, 0, 1);
288
+ scattered = MakeRay(float3(0,0,0), float3(0, 0, 1));
289
+ return false;
290
+ }
291
+ return true;
292
+ }
293
+
294
+ static float3 Trace(int sphereCount, int emissiveCount, Ray r, inout int inoutRayCount, inout uint state)
295
+ {
296
+ float3 col = 0;
297
+ float3 curAtten = 1;
298
+ bool doMaterialE = true;
299
+ // GPUs don't support recursion, so do tracing iterations in a loop up to max depth
300
+ for (int depth = 0; depth < kMaxDepth; ++depth)
301
+ {
302
+ Hit rec;
303
+ ++inoutRayCount;
304
+ int id = HitWorld(sphereCount, r, kMinT, kMaxT, rec);
305
+ if (id >= 0)
306
+ {
307
+ Ray scattered;
308
+ float3 attenuation;
309
+ float3 lightE;
310
+ Material mat = s_GroupMaterials[id];
311
+ float3 matE = mat.emissive;
312
+ if (Scatter(sphereCount, emissiveCount, id, r, rec, attenuation, scattered, lightE, inoutRayCount, state))
313
+ {
314
+ #if DO_LIGHT_SAMPLING
315
+ if (!doMaterialE) matE = 0;
316
+ doMaterialE = (mat.type != MatLambert);
317
+ #endif
318
+ col += curAtten * (matE + lightE);
319
+ curAtten *= attenuation;
320
+ r = scattered;
321
+ }
322
+ else
323
+ {
324
+ col += curAtten * matE;
325
+ break;
326
+ }
327
+ }
328
+ else
329
+ {
330
+ // sky
331
+ #if DO_MITSUBA_COMPARE
332
+ col += curAtten * float3(0.15f, 0.21f, 0.3f); // easier compare with Mitsuba's constant environment light
333
+ #else
334
+ float3 unitDir = r.dir;
335
+ float t = 0.5f*(unitDir.y + 1.0f);
336
+ float3 skyCol = ((1.0f - t)*float3(1.0f, 1.0f, 1.0f) + t * float3(0.5f, 0.7f, 1.0f)) * 0.3f;
337
+ col += curAtten * skyCol;
338
+ #endif
339
+ break;
340
+ }
341
+ }
342
+ return col;
343
+ }
344
+
345
+ Texture2D srcImage : register(t0);
346
+ RWTexture2D<float4> dstImage : register(u0);
347
+ StructuredBuffer<Sphere> g_Spheres : register(t1);
348
+ StructuredBuffer<Material> g_Materials : register(t2);
349
+ StructuredBuffer<Params> g_Params : register(t3);
350
+ StructuredBuffer<int> g_Emissives : register(t4);
351
+ RWByteAddressBuffer g_OutRayCount : register(u1);
352
+
353
+ [numthreads(kCSGroupSizeX, kCSGroupSizeY, 1)]
354
+ void main(uint3 gid : SV_DispatchThreadID, uint3 tid : SV_GroupThreadID)
355
+ {
356
+ // First, move scene data (spheres, materials, emissive indices) into group shared
357
+ // memory. Do this in parallel; each thread in group copies its own chunk of data.
358
+ uint threadID = tid.y * kCSGroupSizeX + tid.x;
359
+ uint groupSize = kCSGroupSizeX * kCSGroupSizeY;
360
+ uint objCount = g_Params[0].sphereCount;
361
+ uint myObjCount = (objCount + groupSize - 1) / groupSize;
362
+ uint myObjStart = threadID * myObjCount;
363
+ for (uint io = myObjStart; io < myObjStart + myObjCount; ++io)
364
+ {
365
+ if (io < objCount)
366
+ {
367
+ s_GroupSpheres[io] = g_Spheres[io];
368
+ s_GroupMaterials[io] = g_Materials[io];
369
+ }
370
+ if (io < g_Params[0].emissiveCount)
371
+ {
372
+ s_GroupEmissives[io] = g_Emissives[io];
373
+ }
374
+ }
375
+ GroupMemoryBarrierWithGroupSync();
376
+
377
+ int rayCount = 0;
378
+ float3 col = 0;
379
+ Params params = g_Params[0];
380
+ uint rngState = (gid.x * 1973 + gid.y * 9277 + params.frames * 26699) | 1;
381
+ for (int s = 0; s < DO_SAMPLES_PER_PIXEL; s++)
382
+ {
383
+ float u = float(gid.x + RandomFloat01(rngState)) * params.invWidth;
384
+ float v = float(gid.y + RandomFloat01(rngState)) * params.invHeight;
385
+ Ray r = CameraGetRay(params.cam, u, v, rngState);
386
+ col += Trace(params.sphereCount, params.emissiveCount, r, rayCount, rngState);
387
+ }
388
+ col *= 1.0f / float(DO_SAMPLES_PER_PIXEL);
389
+
390
+ float3 prev = srcImage.Load(int3(gid.xy,0)).rgb;
391
+ col = lerp(col, prev, params.lerpFac);
392
+ dstImage[gid.xy] = float4(col, 1);
393
+
394
+ g_OutRayCount.InterlockedAdd(0, rayCount);
395
+ }
third_party/tracy/examples/ToyPathTracer/Windows/PixelShader.hlsl ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ float3 LinearToSRGB(float3 rgb)
2
+ {
3
+ rgb = max(rgb, float3(0, 0, 0));
4
+ return max(1.055 * pow(rgb, 0.416666667) - 0.055, 0.0);
5
+ }
6
+
7
+ Texture2D tex : register(t0);
8
+ SamplerState smp : register(s0);
9
+
10
+ float4 main(float2 uv : TEXCOORD0) : SV_Target
11
+ {
12
+ float3 col = tex.Sample(smp, uv).rgb;
13
+ col = LinearToSRGB(col);
14
+ return float4(col, 1.0f);
15
+ }
third_party/tracy/examples/ToyPathTracer/Windows/TestCpu.sln ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 
2
+ Microsoft Visual Studio Solution File, Format Version 12.00
3
+ # Visual Studio Version 16
4
+ VisualStudioVersion = 16.0.30907.101
5
+ MinimumVisualStudioVersion = 10.0.40219.1
6
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestCpu", "TestCpu.vcxproj", "{4F84B756-87F5-4B92-827B-DA087DAE1900}"
7
+ EndProject
8
+ Global
9
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
10
+ Debug|x64 = Debug|x64
11
+ Debug|x86 = Debug|x86
12
+ Release|x64 = Release|x64
13
+ Release|x86 = Release|x86
14
+ EndGlobalSection
15
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
16
+ {4F84B756-87F5-4B92-827B-DA087DAE1900}.Debug|x64.ActiveCfg = Debug|x64
17
+ {4F84B756-87F5-4B92-827B-DA087DAE1900}.Debug|x64.Build.0 = Debug|x64
18
+ {4F84B756-87F5-4B92-827B-DA087DAE1900}.Debug|x86.ActiveCfg = Debug|Win32
19
+ {4F84B756-87F5-4B92-827B-DA087DAE1900}.Debug|x86.Build.0 = Debug|Win32
20
+ {4F84B756-87F5-4B92-827B-DA087DAE1900}.Release|x64.ActiveCfg = Release|x64
21
+ {4F84B756-87F5-4B92-827B-DA087DAE1900}.Release|x64.Build.0 = Release|x64
22
+ {4F84B756-87F5-4B92-827B-DA087DAE1900}.Release|x86.ActiveCfg = Release|Win32
23
+ {4F84B756-87F5-4B92-827B-DA087DAE1900}.Release|x86.Build.0 = Release|Win32
24
+ EndGlobalSection
25
+ GlobalSection(SolutionProperties) = preSolution
26
+ HideSolutionNode = FALSE
27
+ EndGlobalSection
28
+ GlobalSection(ExtensibilityGlobals) = postSolution
29
+ SolutionGuid = {067FB780-37B8-465E-AD7E-E7B238B9C04F}
30
+ EndGlobalSection
31
+ EndGlobal
third_party/tracy/examples/ToyPathTracer/Windows/TestCpu.vcxproj ADDED
@@ -0,0 +1,245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+ <ItemGroup Label="ProjectConfigurations">
4
+ <ProjectConfiguration Include="Debug|Win32">
5
+ <Configuration>Debug</Configuration>
6
+ <Platform>Win32</Platform>
7
+ </ProjectConfiguration>
8
+ <ProjectConfiguration Include="Release|Win32">
9
+ <Configuration>Release</Configuration>
10
+ <Platform>Win32</Platform>
11
+ </ProjectConfiguration>
12
+ <ProjectConfiguration Include="Debug|x64">
13
+ <Configuration>Debug</Configuration>
14
+ <Platform>x64</Platform>
15
+ </ProjectConfiguration>
16
+ <ProjectConfiguration Include="Release|x64">
17
+ <Configuration>Release</Configuration>
18
+ <Platform>x64</Platform>
19
+ </ProjectConfiguration>
20
+ </ItemGroup>
21
+ <PropertyGroup Label="Globals">
22
+ <VCProjectVersion>15.0</VCProjectVersion>
23
+ <ProjectGuid>{4F84B756-87F5-4B92-827B-DA087DAE1900}</ProjectGuid>
24
+ <Keyword>Win32Proj</Keyword>
25
+ <RootNamespace>TestCpu</RootNamespace>
26
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
27
+ </PropertyGroup>
28
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
29
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
30
+ <ConfigurationType>Application</ConfigurationType>
31
+ <UseDebugLibraries>true</UseDebugLibraries>
32
+ <PlatformToolset>v143</PlatformToolset>
33
+ <CharacterSet>Unicode</CharacterSet>
34
+ </PropertyGroup>
35
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
36
+ <ConfigurationType>Application</ConfigurationType>
37
+ <UseDebugLibraries>false</UseDebugLibraries>
38
+ <PlatformToolset>v143</PlatformToolset>
39
+ <WholeProgramOptimization>true</WholeProgramOptimization>
40
+ <CharacterSet>Unicode</CharacterSet>
41
+ </PropertyGroup>
42
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
43
+ <ConfigurationType>Application</ConfigurationType>
44
+ <UseDebugLibraries>true</UseDebugLibraries>
45
+ <PlatformToolset>v143</PlatformToolset>
46
+ <CharacterSet>Unicode</CharacterSet>
47
+ </PropertyGroup>
48
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
49
+ <ConfigurationType>Application</ConfigurationType>
50
+ <UseDebugLibraries>false</UseDebugLibraries>
51
+ <PlatformToolset>v143</PlatformToolset>
52
+ <WholeProgramOptimization>true</WholeProgramOptimization>
53
+ <CharacterSet>Unicode</CharacterSet>
54
+ </PropertyGroup>
55
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
56
+ <ImportGroup Label="ExtensionSettings">
57
+ </ImportGroup>
58
+ <ImportGroup Label="Shared">
59
+ </ImportGroup>
60
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
61
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
62
+ </ImportGroup>
63
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
64
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
65
+ </ImportGroup>
66
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
67
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
68
+ </ImportGroup>
69
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
70
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
71
+ </ImportGroup>
72
+ <PropertyGroup Label="UserMacros" />
73
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
74
+ <LinkIncremental>true</LinkIncremental>
75
+ </PropertyGroup>
76
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
77
+ <LinkIncremental>true</LinkIncremental>
78
+ </PropertyGroup>
79
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
80
+ <LinkIncremental>false</LinkIncremental>
81
+ </PropertyGroup>
82
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
83
+ <LinkIncremental>false</LinkIncremental>
84
+ </PropertyGroup>
85
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
86
+ <ClCompile>
87
+ <WarningLevel>Level3</WarningLevel>
88
+ <Optimization>Disabled</Optimization>
89
+ <SDLCheck>true</SDLCheck>
90
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
91
+ <ConformanceMode>true</ConformanceMode>
92
+ <CallingConvention>VectorCall</CallingConvention>
93
+ <FloatingPointModel>Fast</FloatingPointModel>
94
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
95
+ </ClCompile>
96
+ <Link>
97
+ <SubSystem>Windows</SubSystem>
98
+ <GenerateDebugInformation>true</GenerateDebugInformation>
99
+ <AdditionalDependencies>d3d11.lib;kernel32.lib;user32.lib;gdi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
100
+ </Link>
101
+ </ItemDefinitionGroup>
102
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
103
+ <ClCompile>
104
+ <WarningLevel>Level3</WarningLevel>
105
+ <Optimization>Disabled</Optimization>
106
+ <SDLCheck>true</SDLCheck>
107
+ <PreprocessorDefinitions>TRACY_ENABLE;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
108
+ <ConformanceMode>true</ConformanceMode>
109
+ <CallingConvention>VectorCall</CallingConvention>
110
+ <FloatingPointModel>Fast</FloatingPointModel>
111
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
112
+ </ClCompile>
113
+ <Link>
114
+ <SubSystem>Windows</SubSystem>
115
+ <GenerateDebugInformation>true</GenerateDebugInformation>
116
+ <AdditionalDependencies>d3d11.lib;kernel32.lib;user32.lib;gdi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
117
+ </Link>
118
+ </ItemDefinitionGroup>
119
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
120
+ <ClCompile>
121
+ <WarningLevel>Level3</WarningLevel>
122
+ <Optimization>MaxSpeed</Optimization>
123
+ <FunctionLevelLinking>true</FunctionLevelLinking>
124
+ <IntrinsicFunctions>true</IntrinsicFunctions>
125
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
126
+ <ConformanceMode>true</ConformanceMode>
127
+ <ExceptionHandling>false</ExceptionHandling>
128
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
129
+ <BufferSecurityCheck>false</BufferSecurityCheck>
130
+ <CallingConvention>VectorCall</CallingConvention>
131
+ <FloatingPointModel>Fast</FloatingPointModel>
132
+ </ClCompile>
133
+ <Link>
134
+ <SubSystem>Windows</SubSystem>
135
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
136
+ <OptimizeReferences>true</OptimizeReferences>
137
+ <GenerateDebugInformation>true</GenerateDebugInformation>
138
+ <AdditionalDependencies>d3d11.lib;kernel32.lib;user32.lib;gdi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
139
+ </Link>
140
+ </ItemDefinitionGroup>
141
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
142
+ <ClCompile>
143
+ <WarningLevel>Level3</WarningLevel>
144
+ <Optimization>MaxSpeed</Optimization>
145
+ <FunctionLevelLinking>true</FunctionLevelLinking>
146
+ <IntrinsicFunctions>true</IntrinsicFunctions>
147
+ <PreprocessorDefinitions>TRACY_ENABLE;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
148
+ <ConformanceMode>true</ConformanceMode>
149
+ <ExceptionHandling>false</ExceptionHandling>
150
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
151
+ <BufferSecurityCheck>false</BufferSecurityCheck>
152
+ <CallingConvention>VectorCall</CallingConvention>
153
+ <FloatingPointModel>Fast</FloatingPointModel>
154
+ </ClCompile>
155
+ <Link>
156
+ <SubSystem>Windows</SubSystem>
157
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
158
+ <OptimizeReferences>true</OptimizeReferences>
159
+ <GenerateDebugInformation>true</GenerateDebugInformation>
160
+ <AdditionalDependencies>d3d11.lib;kernel32.lib;user32.lib;gdi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
161
+ </Link>
162
+ </ItemDefinitionGroup>
163
+ <ItemGroup>
164
+ <ClCompile Include="..\..\..\public\TracyClient.cpp" />
165
+ <ClCompile Include="..\Source\enkiTS\TaskScheduler.cpp" />
166
+ <ClCompile Include="..\Source\enkiTS\TaskScheduler_c.cpp" />
167
+ <ClCompile Include="..\Source\Maths.cpp" />
168
+ <ClCompile Include="..\Source\Test.cpp" />
169
+ <ClCompile Include="TestWin.cpp" />
170
+ </ItemGroup>
171
+ <ItemGroup>
172
+ <ClInclude Include="..\Source\Config.h" />
173
+ <ClInclude Include="..\Source\enkiTS\Atomics.h" />
174
+ <ClInclude Include="..\Source\enkiTS\LockLessMultiReadPipe.h" />
175
+ <ClInclude Include="..\Source\enkiTS\TaskScheduler.h" />
176
+ <ClInclude Include="..\Source\enkiTS\TaskScheduler_c.h" />
177
+ <ClInclude Include="..\Source\enkiTS\Threads.h" />
178
+ <ClInclude Include="..\Source\Maths.h" />
179
+ <ClInclude Include="..\Source\MathSimd.h" />
180
+ <ClInclude Include="..\Source\Test.h" />
181
+ <ClInclude Include="..\Source\stb_image.h" />
182
+ </ItemGroup>
183
+ <ItemGroup>
184
+ <None Include="..\.editorconfig" />
185
+ </ItemGroup>
186
+ <ItemGroup>
187
+ <FxCompile Include="ComputeShader.hlsl">
188
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compute</ShaderType>
189
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">5.0</ShaderModel>
190
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
191
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">5.0</ShaderModel>
192
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compute</ShaderType>
193
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">5.0</ShaderModel>
194
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compute</ShaderType>
195
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">5.0</ShaderModel>
196
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">g_CSBytecode</VariableName>
197
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">CompiledComputeShader.h</HeaderFileOutput>
198
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">g_CSBytecode</VariableName>
199
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">CompiledComputeShader.h</HeaderFileOutput>
200
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">g_CSBytecode</VariableName>
201
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompiledComputeShader.h</HeaderFileOutput>
202
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">g_CSBytecode</VariableName>
203
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompiledComputeShader.h</HeaderFileOutput>
204
+ </FxCompile>
205
+ <FxCompile Include="PixelShader.hlsl">
206
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
207
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
208
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
209
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Pixel</ShaderType>
210
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">5.0</ShaderModel>
211
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">5.0</ShaderModel>
212
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">5.0</ShaderModel>
213
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">5.0</ShaderModel>
214
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">CompiledPixelShader.h</HeaderFileOutput>
215
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">CompiledPixelShader.h</HeaderFileOutput>
216
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompiledPixelShader.h</HeaderFileOutput>
217
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompiledPixelShader.h</HeaderFileOutput>
218
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">g_PSBytecode</VariableName>
219
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">g_PSBytecode</VariableName>
220
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">g_PSBytecode</VariableName>
221
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">g_PSBytecode</VariableName>
222
+ </FxCompile>
223
+ <FxCompile Include="VertexShader.hlsl">
224
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Vertex</ShaderType>
225
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Vertex</ShaderType>
226
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Vertex</ShaderType>
227
+ <ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Vertex</ShaderType>
228
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">5.0</ShaderModel>
229
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">5.0</ShaderModel>
230
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">5.0</ShaderModel>
231
+ <ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|x64'">5.0</ShaderModel>
232
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">CompiledVertexShader.h</HeaderFileOutput>
233
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">CompiledVertexShader.h</HeaderFileOutput>
234
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">CompiledVertexShader.h</HeaderFileOutput>
235
+ <HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CompiledVertexShader.h</HeaderFileOutput>
236
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">g_VSBytecode</VariableName>
237
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">g_VSBytecode</VariableName>
238
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">g_VSBytecode</VariableName>
239
+ <VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">g_VSBytecode</VariableName>
240
+ </FxCompile>
241
+ </ItemGroup>
242
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
243
+ <ImportGroup Label="ExtensionTargets">
244
+ </ImportGroup>
245
+ </Project>
third_party/tracy/examples/ToyPathTracer/Windows/TestCpu.vcxproj.filters ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+ <ItemGroup>
4
+ <ClCompile Include="TestWin.cpp" />
5
+ <ClCompile Include="..\Source\Test.cpp">
6
+ <Filter>Source</Filter>
7
+ </ClCompile>
8
+ <ClCompile Include="..\Source\enkiTS\TaskScheduler.cpp">
9
+ <Filter>Source\enkiTS</Filter>
10
+ </ClCompile>
11
+ <ClCompile Include="..\Source\enkiTS\TaskScheduler_c.cpp">
12
+ <Filter>Source\enkiTS</Filter>
13
+ </ClCompile>
14
+ <ClCompile Include="..\Source\Maths.cpp">
15
+ <Filter>Source</Filter>
16
+ </ClCompile>
17
+ <ClCompile Include="..\..\..\public\TracyClient.cpp" />
18
+ </ItemGroup>
19
+ <ItemGroup>
20
+ <Filter Include="Source">
21
+ <UniqueIdentifier>{5f19f217-c1c7-4eeb-be61-8b986fee9375}</UniqueIdentifier>
22
+ </Filter>
23
+ <Filter Include="Source\enkiTS">
24
+ <UniqueIdentifier>{38c448a8-1dcc-4116-9410-a9f8d068caff}</UniqueIdentifier>
25
+ </Filter>
26
+ </ItemGroup>
27
+ <ItemGroup>
28
+ <ClInclude Include="..\Source\Test.h">
29
+ <Filter>Source</Filter>
30
+ </ClInclude>
31
+ <ClInclude Include="..\Source\stb_image.h">
32
+ <Filter>Source</Filter>
33
+ </ClInclude>
34
+ <ClInclude Include="..\Source\enkiTS\Atomics.h">
35
+ <Filter>Source\enkiTS</Filter>
36
+ </ClInclude>
37
+ <ClInclude Include="..\Source\enkiTS\LockLessMultiReadPipe.h">
38
+ <Filter>Source\enkiTS</Filter>
39
+ </ClInclude>
40
+ <ClInclude Include="..\Source\enkiTS\TaskScheduler.h">
41
+ <Filter>Source\enkiTS</Filter>
42
+ </ClInclude>
43
+ <ClInclude Include="..\Source\enkiTS\TaskScheduler_c.h">
44
+ <Filter>Source\enkiTS</Filter>
45
+ </ClInclude>
46
+ <ClInclude Include="..\Source\enkiTS\Threads.h">
47
+ <Filter>Source\enkiTS</Filter>
48
+ </ClInclude>
49
+ <ClInclude Include="..\Source\Maths.h">
50
+ <Filter>Source</Filter>
51
+ </ClInclude>
52
+ <ClInclude Include="..\Source\Config.h">
53
+ <Filter>Source</Filter>
54
+ </ClInclude>
55
+ <ClInclude Include="..\Source\MathSimd.h">
56
+ <Filter>Source</Filter>
57
+ </ClInclude>
58
+ </ItemGroup>
59
+ <ItemGroup>
60
+ <None Include="..\.editorconfig" />
61
+ </ItemGroup>
62
+ <ItemGroup>
63
+ <FxCompile Include="VertexShader.hlsl" />
64
+ <FxCompile Include="PixelShader.hlsl" />
65
+ <FxCompile Include="ComputeShader.hlsl" />
66
+ </ItemGroup>
67
+ </Project>
third_party/tracy/examples/ToyPathTracer/Windows/TestWin.cpp ADDED
@@ -0,0 +1,567 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include <stdint.h>
2
+ #define WIN32_LEAN_AND_MEAN
3
+ #define NOMINMAX
4
+ #include <windows.h>
5
+ #include <d3d11_1.h>
6
+
7
+ #include <stdio.h>
8
+ #include <stdlib.h>
9
+ #include <time.h>
10
+ #include <algorithm>
11
+
12
+ #include "../Source/Config.h"
13
+ #include "../Source/Maths.h"
14
+ #include "../Source/Test.h"
15
+ #include "CompiledVertexShader.h"
16
+ #include "CompiledPixelShader.h"
17
+
18
+ #include "../../../public/tracy/Tracy.hpp"
19
+ #include "../../../public/tracy/TracyD3D11.hpp"
20
+
21
+ static HINSTANCE g_HInstance;
22
+ static HWND g_Wnd;
23
+
24
+ ATOM MyRegisterClass(HINSTANCE hInstance);
25
+ BOOL InitInstance(HINSTANCE, int);
26
+ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
27
+ INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
28
+
29
+ static HRESULT InitD3DDevice();
30
+ static void ShutdownD3DDevice();
31
+ static void RenderFrame();
32
+
33
+ static float* g_Backbuffer;
34
+
35
+ static D3D_FEATURE_LEVEL g_D3D11FeatureLevel = D3D_FEATURE_LEVEL_11_0;
36
+ static ID3D11Device* g_D3D11Device = nullptr;
37
+ static ID3D11DeviceContext* g_D3D11Ctx = nullptr;
38
+ static IDXGISwapChain* g_D3D11SwapChain = nullptr;
39
+ static ID3D11RenderTargetView* g_D3D11RenderTarget = nullptr;
40
+ static ID3D11VertexShader* g_VertexShader;
41
+ static ID3D11PixelShader* g_PixelShader;
42
+ static ID3D11Texture2D *g_BackbufferTexture, *g_BackbufferTexture2;
43
+ static ID3D11ShaderResourceView *g_BackbufferSRV, *g_BackbufferSRV2;
44
+ static ID3D11UnorderedAccessView *g_BackbufferUAV, *g_BackbufferUAV2;
45
+ static ID3D11SamplerState* g_SamplerLinear;
46
+ static ID3D11RasterizerState* g_RasterState;
47
+ static int g_BackbufferIndex;
48
+ static tracy::D3D11Ctx *g_tracyCtx;
49
+
50
+
51
+ #if DO_COMPUTE_GPU
52
+ #include "CompiledComputeShader.h"
53
+ struct ComputeParams
54
+ {
55
+ Camera cam;
56
+ int sphereCount;
57
+ int screenWidth;
58
+ int screenHeight;
59
+ int frames;
60
+ float invWidth;
61
+ float invHeight;
62
+ float lerpFac;
63
+ int emissiveCount;
64
+ };
65
+ static ID3D11ComputeShader* g_ComputeShader;
66
+ static ID3D11Buffer* g_DataSpheres; static ID3D11ShaderResourceView* g_SRVSpheres;
67
+ static ID3D11Buffer* g_DataMaterials; static ID3D11ShaderResourceView* g_SRVMaterials;
68
+ static ID3D11Buffer* g_DataParams; static ID3D11ShaderResourceView* g_SRVParams;
69
+ static ID3D11Buffer* g_DataEmissives; static ID3D11ShaderResourceView* g_SRVEmissives;
70
+ static ID3D11Buffer* g_DataCounter; static ID3D11UnorderedAccessView* g_UAVCounter;
71
+ static int g_SphereCount, g_ObjSize, g_MatSize;
72
+ static ID3D11Query *g_QueryBegin, *g_QueryEnd, *g_QueryDisjoint;
73
+ #endif // #if DO_COMPUTE_GPU
74
+
75
+ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int nCmdShow)
76
+ {
77
+ g_Backbuffer = new float[kBackbufferWidth * kBackbufferHeight * 4];
78
+ memset(g_Backbuffer, 0, kBackbufferWidth * kBackbufferHeight * 4 * sizeof(g_Backbuffer[0]));
79
+
80
+ InitializeTest();
81
+
82
+ MyRegisterClass(hInstance);
83
+ if (!InitInstance (hInstance, nCmdShow))
84
+ {
85
+ return FALSE;
86
+ }
87
+
88
+ if (FAILED(InitD3DDevice()))
89
+ {
90
+ ShutdownD3DDevice();
91
+ return 0;
92
+ }
93
+
94
+ g_D3D11Device->CreateVertexShader(g_VSBytecode, ARRAYSIZE(g_VSBytecode), NULL, &g_VertexShader);
95
+ g_D3D11Device->CreatePixelShader(g_PSBytecode, ARRAYSIZE(g_PSBytecode), NULL, &g_PixelShader);
96
+ #if DO_COMPUTE_GPU
97
+ g_D3D11Device->CreateComputeShader(g_CSBytecode, ARRAYSIZE(g_CSBytecode), NULL, &g_ComputeShader);
98
+ #endif
99
+
100
+ D3D11_TEXTURE2D_DESC texDesc = {};
101
+ texDesc.Width = kBackbufferWidth;
102
+ texDesc.Height = kBackbufferHeight;
103
+ texDesc.MipLevels = 1;
104
+ texDesc.ArraySize = 1;
105
+ texDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
106
+ texDesc.SampleDesc.Count = 1;
107
+ texDesc.SampleDesc.Quality = 0;
108
+ #if DO_COMPUTE_GPU
109
+ texDesc.Usage = D3D11_USAGE_DEFAULT;
110
+ texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
111
+ texDesc.CPUAccessFlags = 0;
112
+ #else
113
+ texDesc.Usage = D3D11_USAGE_DYNAMIC;
114
+ texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
115
+ texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
116
+ #endif
117
+ texDesc.MiscFlags = 0;
118
+ g_D3D11Device->CreateTexture2D(&texDesc, NULL, &g_BackbufferTexture);
119
+ g_D3D11Device->CreateTexture2D(&texDesc, NULL, &g_BackbufferTexture2);
120
+
121
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
122
+ srvDesc.Format = texDesc.Format;
123
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
124
+ srvDesc.Texture2D.MipLevels = 1;
125
+ srvDesc.Texture2D.MostDetailedMip = 0;
126
+ g_D3D11Device->CreateShaderResourceView(g_BackbufferTexture, &srvDesc, &g_BackbufferSRV);
127
+ g_D3D11Device->CreateShaderResourceView(g_BackbufferTexture2, &srvDesc, &g_BackbufferSRV2);
128
+
129
+ D3D11_SAMPLER_DESC smpDesc = {};
130
+ smpDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
131
+ smpDesc.AddressU = smpDesc.AddressV = smpDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
132
+ g_D3D11Device->CreateSamplerState(&smpDesc, &g_SamplerLinear);
133
+
134
+ D3D11_RASTERIZER_DESC rasterDesc = {};
135
+ rasterDesc.FillMode = D3D11_FILL_SOLID;
136
+ rasterDesc.CullMode = D3D11_CULL_NONE;
137
+ g_D3D11Device->CreateRasterizerState(&rasterDesc, &g_RasterState);
138
+
139
+ #if DO_COMPUTE_GPU
140
+ D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
141
+
142
+ int camSize;
143
+ GetObjectCount(g_SphereCount, g_ObjSize, g_MatSize, camSize);
144
+ assert(g_ObjSize == 20);
145
+ assert(g_MatSize == 36);
146
+ assert(camSize == 88);
147
+ D3D11_BUFFER_DESC bdesc = {};
148
+ bdesc.ByteWidth = g_SphereCount * g_ObjSize;
149
+ bdesc.Usage = D3D11_USAGE_DEFAULT;
150
+ bdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
151
+ bdesc.CPUAccessFlags = 0;
152
+ bdesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
153
+ bdesc.StructureByteStride = g_ObjSize;
154
+ g_D3D11Device->CreateBuffer(&bdesc, NULL, &g_DataSpheres);
155
+ srvDesc.Format = DXGI_FORMAT_UNKNOWN;
156
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
157
+ srvDesc.Buffer.FirstElement = 0;
158
+ srvDesc.Buffer.NumElements = g_SphereCount;
159
+ g_D3D11Device->CreateShaderResourceView(g_DataSpheres, &srvDesc, &g_SRVSpheres);
160
+
161
+ bdesc.ByteWidth = g_SphereCount * g_MatSize;
162
+ bdesc.StructureByteStride = g_MatSize;
163
+ g_D3D11Device->CreateBuffer(&bdesc, NULL, &g_DataMaterials);
164
+ srvDesc.Buffer.NumElements = g_SphereCount;
165
+ g_D3D11Device->CreateShaderResourceView(g_DataMaterials, &srvDesc, &g_SRVMaterials);
166
+
167
+ bdesc.ByteWidth = sizeof(ComputeParams);
168
+ bdesc.StructureByteStride = sizeof(ComputeParams);
169
+ g_D3D11Device->CreateBuffer(&bdesc, NULL, &g_DataParams);
170
+ srvDesc.Buffer.NumElements = 1;
171
+ g_D3D11Device->CreateShaderResourceView(g_DataParams, &srvDesc, &g_SRVParams);
172
+
173
+ bdesc.ByteWidth = g_SphereCount * 4;
174
+ bdesc.StructureByteStride = 4;
175
+ g_D3D11Device->CreateBuffer(&bdesc, NULL, &g_DataEmissives);
176
+ srvDesc.Buffer.NumElements = g_SphereCount;
177
+ g_D3D11Device->CreateShaderResourceView(g_DataEmissives, &srvDesc, &g_SRVEmissives);
178
+
179
+ bdesc.ByteWidth = 4;
180
+ bdesc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
181
+ bdesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
182
+ bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
183
+ g_D3D11Device->CreateBuffer(&bdesc, NULL, &g_DataCounter);
184
+ uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
185
+ uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
186
+ uavDesc.Buffer.FirstElement = 0;
187
+ uavDesc.Buffer.NumElements = 1;
188
+ uavDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
189
+ g_D3D11Device->CreateUnorderedAccessView(g_DataCounter, &uavDesc, &g_UAVCounter);
190
+
191
+ uavDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
192
+ uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
193
+ uavDesc.Texture2D.MipSlice = 0;
194
+ g_D3D11Device->CreateUnorderedAccessView(g_BackbufferTexture, &uavDesc, &g_BackbufferUAV);
195
+ g_D3D11Device->CreateUnorderedAccessView(g_BackbufferTexture2, &uavDesc, &g_BackbufferUAV2);
196
+
197
+ D3D11_QUERY_DESC qDesc = {};
198
+ qDesc.Query = D3D11_QUERY_TIMESTAMP;
199
+ g_D3D11Device->CreateQuery(&qDesc, &g_QueryBegin);
200
+ g_D3D11Device->CreateQuery(&qDesc, &g_QueryEnd);
201
+ qDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
202
+ g_D3D11Device->CreateQuery(&qDesc, &g_QueryDisjoint);
203
+ #endif // #if DO_COMPUTE_GPU
204
+
205
+
206
+ static int framesLeft = 10;
207
+
208
+ // Main message loop
209
+ MSG msg = { 0 };
210
+ while (msg.message != WM_QUIT)
211
+ {
212
+ if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
213
+ {
214
+ TranslateMessage(&msg);
215
+ DispatchMessage(&msg);
216
+ }
217
+ else
218
+ {
219
+ RenderFrame();
220
+ TracyD3D11Collect(g_tracyCtx);
221
+ if( --framesLeft == 0 ) break;
222
+ }
223
+ }
224
+
225
+ ShutdownTest();
226
+ ShutdownD3DDevice();
227
+
228
+ return (int) msg.wParam;
229
+ }
230
+
231
+
232
+ ATOM MyRegisterClass(HINSTANCE hInstance)
233
+ {
234
+ ZoneScoped;
235
+
236
+ WNDCLASSEXW wcex;
237
+ memset(&wcex, 0, sizeof(wcex));
238
+ wcex.cbSize = sizeof(WNDCLASSEX);
239
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
240
+ wcex.lpfnWndProc = WndProc;
241
+ wcex.cbClsExtra = 0;
242
+ wcex.cbWndExtra = 0;
243
+ wcex.hInstance = hInstance;
244
+ wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
245
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
246
+ wcex.lpszClassName = L"TestClass";
247
+ return RegisterClassExW(&wcex);
248
+ }
249
+
250
+ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
251
+ {
252
+ ZoneScoped;
253
+
254
+ g_HInstance = hInstance;
255
+ RECT rc = { 0, 0, kBackbufferWidth, kBackbufferHeight };
256
+ DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
257
+ AdjustWindowRect(&rc, style, FALSE);
258
+ HWND hWnd = CreateWindowW(L"TestClass", L"Test", style, CW_USEDEFAULT, CW_USEDEFAULT, rc.right-rc.left, rc.bottom-rc.top, nullptr, nullptr, hInstance, nullptr);
259
+ if (!hWnd)
260
+ return FALSE;
261
+ g_Wnd = hWnd;
262
+ ShowWindow(hWnd, nCmdShow);
263
+ UpdateWindow(hWnd);
264
+ return TRUE;
265
+ }
266
+
267
+ static uint64_t s_Time;
268
+ static int s_Count;
269
+ static char s_Buffer[200];
270
+ static unsigned s_Flags = kFlagProgressive;
271
+ static int s_FrameCount = 0;
272
+
273
+
274
+ static void RenderFrame()
275
+ {
276
+ ZoneScoped;
277
+ TracyD3D11Zone(g_tracyCtx, "RenderFrame");
278
+
279
+ LARGE_INTEGER time1;
280
+
281
+ #if DO_COMPUTE_GPU
282
+ QueryPerformanceCounter(&time1);
283
+ float t = float(clock()) / CLOCKS_PER_SEC;
284
+ UpdateTest(t, s_FrameCount, kBackbufferWidth, kBackbufferHeight, s_Flags);
285
+
286
+ g_BackbufferIndex = 1 - g_BackbufferIndex;
287
+ void* dataSpheres = alloca(g_SphereCount * g_ObjSize);
288
+ void* dataMaterials = alloca(g_SphereCount * g_MatSize);
289
+ void* dataEmissives = alloca(g_SphereCount * 4);
290
+ ComputeParams dataParams;
291
+ GetSceneDesc(dataSpheres, dataMaterials, &dataParams.cam, dataEmissives, &dataParams.emissiveCount);
292
+
293
+ dataParams.sphereCount = g_SphereCount;
294
+ dataParams.screenWidth = kBackbufferWidth;
295
+ dataParams.screenHeight = kBackbufferHeight;
296
+ dataParams.frames = s_FrameCount;
297
+ dataParams.invWidth = 1.0f / kBackbufferWidth;
298
+ dataParams.invHeight = 1.0f / kBackbufferHeight;
299
+ float lerpFac = float(s_FrameCount) / float(s_FrameCount + 1);
300
+ if (s_Flags & kFlagAnimate)
301
+ lerpFac *= DO_ANIMATE_SMOOTHING;
302
+ if (!(s_Flags & kFlagProgressive))
303
+ lerpFac = 0;
304
+ dataParams.lerpFac = lerpFac;
305
+
306
+ g_D3D11Ctx->UpdateSubresource(g_DataSpheres, 0, NULL, dataSpheres, 0, 0);
307
+ g_D3D11Ctx->UpdateSubresource(g_DataMaterials, 0, NULL, dataMaterials, 0, 0);
308
+ g_D3D11Ctx->UpdateSubresource(g_DataParams, 0, NULL, &dataParams, 0, 0);
309
+ g_D3D11Ctx->UpdateSubresource(g_DataEmissives, 0, NULL, dataEmissives, 0, 0);
310
+
311
+ ID3D11ShaderResourceView* srvs[] = {
312
+ g_BackbufferIndex == 0 ? g_BackbufferSRV2 : g_BackbufferSRV,
313
+ g_SRVSpheres,
314
+ g_SRVMaterials,
315
+ g_SRVParams,
316
+ g_SRVEmissives
317
+ };
318
+ g_D3D11Ctx->CSSetShaderResources(0, ARRAYSIZE(srvs), srvs);
319
+ ID3D11UnorderedAccessView* uavs[] = {
320
+ g_BackbufferIndex == 0 ? g_BackbufferUAV : g_BackbufferUAV2,
321
+ g_UAVCounter
322
+ };
323
+ g_D3D11Ctx->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, NULL);
324
+ g_D3D11Ctx->CSSetShader(g_ComputeShader, NULL, 0);
325
+ g_D3D11Ctx->Begin(g_QueryDisjoint);
326
+ g_D3D11Ctx->End(g_QueryBegin);
327
+ g_D3D11Ctx->Dispatch(kBackbufferWidth/kCSGroupSizeX, kBackbufferHeight/kCSGroupSizeY, 1);
328
+ g_D3D11Ctx->End(g_QueryEnd);
329
+ uavs[0] = NULL;
330
+ g_D3D11Ctx->CSSetUnorderedAccessViews(0, ARRAYSIZE(uavs), uavs, NULL);
331
+ ++s_FrameCount;
332
+
333
+ #else
334
+ QueryPerformanceCounter(&time1);
335
+ float t = float(clock()) / CLOCKS_PER_SEC;
336
+ static size_t s_RayCounter = 0;
337
+ int rayCount;
338
+ UpdateTest(t, s_FrameCount, kBackbufferWidth, kBackbufferHeight, s_Flags);
339
+ DrawTest(t, s_FrameCount, kBackbufferWidth, kBackbufferHeight, g_Backbuffer, rayCount, s_Flags);
340
+ s_FrameCount++;
341
+ s_RayCounter += rayCount;
342
+ LARGE_INTEGER time2;
343
+ QueryPerformanceCounter(&time2);
344
+ uint64_t dt = time2.QuadPart - time1.QuadPart;
345
+ ++s_Count;
346
+ s_Time += dt;
347
+ if (s_Count > 10)
348
+ {
349
+ LARGE_INTEGER frequency;
350
+ QueryPerformanceFrequency(&frequency);
351
+
352
+ double s = double(s_Time) / double(frequency.QuadPart) / s_Count;
353
+ sprintf_s(s_Buffer, sizeof(s_Buffer), "%.2fms (%.1f FPS) %.1fMrays/s %.2fMrays/frame frames %i\n", s * 1000.0f, 1.f / s, s_RayCounter / s_Count / s * 1.0e-6f, s_RayCounter / s_Count * 1.0e-6f, s_FrameCount);
354
+ SetWindowTextA(g_Wnd, s_Buffer);
355
+ OutputDebugStringA(s_Buffer);
356
+ s_Count = 0;
357
+ s_Time = 0;
358
+ s_RayCounter = 0;
359
+ }
360
+
361
+ D3D11_MAPPED_SUBRESOURCE mapped;
362
+ g_D3D11Ctx->Map(g_BackbufferTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
363
+ const uint8_t* src = (const uint8_t*)g_Backbuffer;
364
+ uint8_t* dst = (uint8_t*)mapped.pData;
365
+ for (int y = 0; y < kBackbufferHeight; ++y)
366
+ {
367
+ memcpy(dst, src, kBackbufferWidth * 16);
368
+ src += kBackbufferWidth * 16;
369
+ dst += mapped.RowPitch;
370
+ }
371
+ g_D3D11Ctx->Unmap(g_BackbufferTexture, 0);
372
+ #endif
373
+
374
+ g_D3D11Ctx->VSSetShader(g_VertexShader, NULL, 0);
375
+ g_D3D11Ctx->PSSetShader(g_PixelShader, NULL, 0);
376
+ g_D3D11Ctx->PSSetShaderResources(0, 1, g_BackbufferIndex == 0 ? &g_BackbufferSRV : &g_BackbufferSRV2);
377
+ g_D3D11Ctx->PSSetSamplers(0, 1, &g_SamplerLinear);
378
+ g_D3D11Ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
379
+ g_D3D11Ctx->RSSetState(g_RasterState);
380
+ g_D3D11Ctx->Draw(3, 0);
381
+ g_D3D11SwapChain->Present(0, 0);
382
+
383
+ FrameMark;
384
+
385
+ #if DO_COMPUTE_GPU
386
+ g_D3D11Ctx->End(g_QueryDisjoint);
387
+
388
+ // get GPU times
389
+ while (g_D3D11Ctx->GetData(g_QueryDisjoint, NULL, 0, 0) == S_FALSE) { Sleep(0); }
390
+ D3D10_QUERY_DATA_TIMESTAMP_DISJOINT tsDisjoint;
391
+ g_D3D11Ctx->GetData(g_QueryDisjoint, &tsDisjoint, sizeof(tsDisjoint), 0);
392
+ if (!tsDisjoint.Disjoint)
393
+ {
394
+ UINT64 tsBegin, tsEnd;
395
+ // Note: on some GPUs/drivers, even when the disjoint query above already said "yeah I have data",
396
+ // might still not return "I have data" for timestamp queries before it.
397
+ while (g_D3D11Ctx->GetData(g_QueryBegin, &tsBegin, sizeof(tsBegin), 0) == S_FALSE) { Sleep(0); }
398
+ while (g_D3D11Ctx->GetData(g_QueryEnd, &tsEnd, sizeof(tsEnd), 0) == S_FALSE) { Sleep(0); }
399
+
400
+ float s = float(tsEnd - tsBegin) / float(tsDisjoint.Frequency);
401
+
402
+ static uint64_t s_RayCounter;
403
+ D3D11_MAPPED_SUBRESOURCE mapped;
404
+ g_D3D11Ctx->Map(g_DataCounter, 0, D3D11_MAP_READ, 0, &mapped);
405
+ s_RayCounter += *(const int*)mapped.pData;
406
+ g_D3D11Ctx->Unmap(g_DataCounter, 0);
407
+ int zeroCount = 0;
408
+ g_D3D11Ctx->UpdateSubresource(g_DataCounter, 0, NULL, &zeroCount, 0, 0);
409
+
410
+ static float s_Time;
411
+ ++s_Count;
412
+ s_Time += s;
413
+ if (s_Count > 150)
414
+ {
415
+ s = s_Time / s_Count;
416
+ sprintf_s(s_Buffer, sizeof(s_Buffer), "%.2fms (%.1f FPS) %.1fMrays/s %.2fMrays/frame frames %i\n", s * 1000.0f, 1.f / s, s_RayCounter / s_Count / s * 1.0e-6f, s_RayCounter / s_Count * 1.0e-6f, s_FrameCount);
417
+ SetWindowTextA(g_Wnd, s_Buffer);
418
+ s_Count = 0;
419
+ s_Time = 0;
420
+ s_RayCounter = 0;
421
+ }
422
+
423
+ }
424
+ #endif // #if DO_COMPUTE_GPU
425
+ }
426
+
427
+
428
+ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
429
+ {
430
+ switch (message)
431
+ {
432
+ case WM_PAINT:
433
+ {
434
+ PAINTSTRUCT ps;
435
+ HDC hdc = BeginPaint(hWnd, &ps);
436
+ EndPaint(hWnd, &ps);
437
+ }
438
+ break;
439
+ case WM_DESTROY:
440
+ PostQuitMessage(0);
441
+ break;
442
+ case WM_CHAR:
443
+ if (wParam == 'a')
444
+ s_Flags = s_Flags ^ kFlagAnimate;
445
+ if (wParam == 'p')
446
+ {
447
+ s_Flags = s_Flags ^ kFlagProgressive;
448
+ s_FrameCount = 0;
449
+ }
450
+ break;
451
+ default:
452
+ return DefWindowProc(hWnd, message, wParam, lParam);
453
+ }
454
+ return 0;
455
+ }
456
+
457
+
458
+ static HRESULT InitD3DDevice()
459
+ {
460
+ ZoneScoped;
461
+
462
+ HRESULT hr = S_OK;
463
+
464
+ RECT rc;
465
+ GetClientRect(g_Wnd, &rc);
466
+ UINT width = rc.right - rc.left;
467
+ UINT height = rc.bottom - rc.top;
468
+
469
+ UINT createDeviceFlags = 0;
470
+ #ifdef _DEBUG
471
+ createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
472
+ #endif
473
+
474
+ D3D_FEATURE_LEVEL featureLevels[] =
475
+ {
476
+ D3D_FEATURE_LEVEL_11_0,
477
+ };
478
+ UINT numFeatureLevels = ARRAYSIZE(featureLevels);
479
+ hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, D3D11_SDK_VERSION, &g_D3D11Device, &g_D3D11FeatureLevel, &g_D3D11Ctx);
480
+ if (FAILED(hr))
481
+ return hr;
482
+
483
+ // Get DXGI factory
484
+ IDXGIFactory1* dxgiFactory = nullptr;
485
+ {
486
+ IDXGIDevice* dxgiDevice = nullptr;
487
+ hr = g_D3D11Device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));
488
+ if (SUCCEEDED(hr))
489
+ {
490
+ IDXGIAdapter* adapter = nullptr;
491
+ hr = dxgiDevice->GetAdapter(&adapter);
492
+ if (SUCCEEDED(hr))
493
+ {
494
+ hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory));
495
+ adapter->Release();
496
+ }
497
+ dxgiDevice->Release();
498
+ }
499
+ }
500
+ if (FAILED(hr))
501
+ return hr;
502
+
503
+ // Create swap chain
504
+ DXGI_SWAP_CHAIN_DESC sd;
505
+ ZeroMemory(&sd, sizeof(sd));
506
+ sd.BufferCount = 1;
507
+ sd.BufferDesc.Width = width;
508
+ sd.BufferDesc.Height = height;
509
+ sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
510
+ sd.BufferDesc.RefreshRate.Numerator = 60;
511
+ sd.BufferDesc.RefreshRate.Denominator = 1;
512
+ sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
513
+ sd.OutputWindow = g_Wnd;
514
+ sd.SampleDesc.Count = 1;
515
+ sd.SampleDesc.Quality = 0;
516
+ sd.Windowed = TRUE;
517
+ hr = dxgiFactory->CreateSwapChain(g_D3D11Device, &sd, &g_D3D11SwapChain);
518
+
519
+ // Prevent Alt-Enter
520
+ dxgiFactory->MakeWindowAssociation(g_Wnd, DXGI_MWA_NO_ALT_ENTER);
521
+ dxgiFactory->Release();
522
+
523
+ if (FAILED(hr))
524
+ return hr;
525
+
526
+ // RTV
527
+ ID3D11Texture2D* pBackBuffer = nullptr;
528
+ hr = g_D3D11SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackBuffer));
529
+ if (FAILED(hr))
530
+ return hr;
531
+ hr = g_D3D11Device->CreateRenderTargetView(pBackBuffer, nullptr, &g_D3D11RenderTarget);
532
+ pBackBuffer->Release();
533
+ if (FAILED(hr))
534
+ return hr;
535
+
536
+ g_D3D11Ctx->OMSetRenderTargets(1, &g_D3D11RenderTarget, nullptr);
537
+
538
+ // Viewport
539
+ D3D11_VIEWPORT vp;
540
+ vp.Width = (float)width;
541
+ vp.Height = (float)height;
542
+ vp.MinDepth = 0.0f;
543
+ vp.MaxDepth = 1.0f;
544
+ vp.TopLeftX = 0;
545
+ vp.TopLeftY = 0;
546
+ g_D3D11Ctx->RSSetViewports(1, &vp);
547
+
548
+ g_tracyCtx = TracyD3D11Context(g_D3D11Device, g_D3D11Ctx);
549
+ const char* tracyD3D11CtxName = "D3D11";
550
+ TracyD3D11ContextName(g_tracyCtx, tracyD3D11CtxName, (uint16_t)strlen(tracyD3D11CtxName));
551
+
552
+ return S_OK;
553
+ }
554
+
555
+ static void ShutdownD3DDevice()
556
+ {
557
+ ZoneScoped;
558
+
559
+ if (g_tracyCtx) TracyD3D11Destroy(g_tracyCtx);
560
+
561
+ if (g_D3D11Ctx) g_D3D11Ctx->ClearState();
562
+
563
+ if (g_D3D11RenderTarget) g_D3D11RenderTarget->Release();
564
+ if (g_D3D11SwapChain) g_D3D11SwapChain->Release();
565
+ if (g_D3D11Ctx) g_D3D11Ctx->Release();
566
+ if (g_D3D11Device) g_D3D11Device->Release();
567
+ }
third_party/tracy/examples/ToyPathTracer/Windows/VertexShader.hlsl ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ struct vs2ps
2
+ {
3
+ float2 uv : TEXCOORD0;
4
+ float4 pos : SV_Position;
5
+ };
6
+
7
+ vs2ps main(uint vid : SV_VertexID)
8
+ {
9
+ vs2ps o;
10
+ o.uv = float2((vid << 1) & 2, vid & 2);
11
+ o.pos = float4(o.uv * float2(2, 2) + float2(-1, -1), 0, 1);
12
+ return o;
13
+ }
third_party/tracy/examples/ToyPathTracer/license.md ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org>
third_party/tracy/examples/fibers.cpp ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // g++ fibers.cpp ../public/TracyClient.cpp -I../public/tracy -DTRACY_ENABLE -DTRACY_FIBERS -lpthread -ldl
2
+
3
+ #include <thread>
4
+ #include <unistd.h>
5
+
6
+ #include "Tracy.hpp"
7
+ #include "TracyC.h"
8
+
9
+ const char* fiber = "job1";
10
+ TracyCZoneCtx zone;
11
+
12
+ int main()
13
+ {
14
+ std::thread t1( [] {
15
+ TracyFiberEnter( fiber );
16
+ TracyCZone( ctx, 1 );
17
+ zone = ctx;
18
+ sleep( 1 );
19
+ TracyFiberLeave;
20
+ });
21
+ t1.join();
22
+
23
+ std::thread t2( [] {
24
+ TracyFiberEnter( fiber );
25
+ sleep( 1 );
26
+ TracyCZoneEnd( zone );
27
+ TracyFiberLeave;
28
+ });
29
+ t2.join();
30
+ }
third_party/tracy/public/TracyClient.cpp ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // Tracy profiler
3
+ // ----------------
4
+ //
5
+ // For fast integration, compile and
6
+ // link with this source file (and none
7
+ // other) in your executable (or in the
8
+ // main DLL / shared object on multi-DLL
9
+ // projects).
10
+ //
11
+
12
+ // Define TRACY_ENABLE to enable profiler.
13
+
14
+ #include "common/TracySystem.cpp"
15
+
16
+ #ifdef TRACY_ENABLE
17
+
18
+ #ifdef _MSC_VER
19
+ # pragma warning(push, 0)
20
+ #endif
21
+
22
+ #include "common/tracy_lz4.cpp"
23
+ #include "client/TracyProfiler.cpp"
24
+ #include "client/TracyCallstack.cpp"
25
+ #include "client/TracySysPower.cpp"
26
+ #include "client/TracySysTime.cpp"
27
+ #include "client/TracySysTrace.cpp"
28
+ #include "common/TracySocket.cpp"
29
+ #include "client/tracy_rpmalloc.cpp"
30
+ #include "client/TracyDxt1.cpp"
31
+ #include "client/TracyAlloc.cpp"
32
+ #include "client/TracyOverride.cpp"
33
+ #include "client/TracyKCore.cpp"
34
+
35
+ #if defined(TRACY_HAS_CALLSTACK)
36
+ # if TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6
37
+ # include "libbacktrace/alloc.cpp"
38
+ # include "libbacktrace/dwarf.cpp"
39
+ # include "libbacktrace/fileline.cpp"
40
+ # include "libbacktrace/mmapio.cpp"
41
+ # include "libbacktrace/posix.cpp"
42
+ # include "libbacktrace/sort.cpp"
43
+ # include "libbacktrace/state.cpp"
44
+ # if TRACY_HAS_CALLSTACK == 4
45
+ # include "libbacktrace/macho.cpp"
46
+ # else
47
+ # include "libbacktrace/elf.cpp"
48
+ # endif
49
+ # include "common/TracyStackFrames.cpp"
50
+ # endif
51
+ #endif
52
+
53
+ #ifdef _MSC_VER
54
+ # pragma comment(lib, "ws2_32.lib")
55
+ # pragma comment(lib, "dbghelp.lib")
56
+ # pragma comment(lib, "advapi32.lib")
57
+ # pragma comment(lib, "user32.lib")
58
+ # pragma warning(pop)
59
+ #endif
60
+
61
+ #endif
third_party/tracy/public/libbacktrace/alloc.cpp ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* alloc.c -- Memory allocation without mmap.
2
+ Copyright (C) 2012-2021 Free Software Foundation, Inc.
3
+ Written by Ian Lance Taylor, Google.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are
7
+ met:
8
+
9
+ (1) Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ (2) Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in
14
+ the documentation and/or other materials provided with the
15
+ distribution.
16
+
17
+ (3) The name of the author may not be used to
18
+ endorse or promote products derived from this software without
19
+ specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
+ POSSIBILITY OF SUCH DAMAGE. */
32
+
33
+ #include "config.h"
34
+
35
+ #include <errno.h>
36
+ #include <stdlib.h>
37
+ #include <sys/types.h>
38
+
39
+ #include "backtrace.hpp"
40
+ #include "internal.hpp"
41
+
42
+ #include "../common/TracyAlloc.hpp"
43
+
44
+ namespace tracy
45
+ {
46
+
47
+ /* Allocation routines to use on systems that do not support anonymous
48
+ mmap. This implementation just uses malloc, which means that the
49
+ backtrace functions may not be safely invoked from a signal
50
+ handler. */
51
+
52
+ /* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't
53
+ report an error. */
54
+
55
+ void *
56
+ backtrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED,
57
+ size_t size, backtrace_error_callback error_callback,
58
+ void *data)
59
+ {
60
+ void *ret;
61
+
62
+ ret = tracy_malloc (size);
63
+ if (ret == NULL)
64
+ {
65
+ if (error_callback)
66
+ error_callback (data, "malloc", errno);
67
+ }
68
+ return ret;
69
+ }
70
+
71
+ /* Free memory. */
72
+
73
+ void
74
+ backtrace_free (struct backtrace_state *state ATTRIBUTE_UNUSED,
75
+ void *p, size_t size ATTRIBUTE_UNUSED,
76
+ backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
77
+ void *data ATTRIBUTE_UNUSED)
78
+ {
79
+ tracy_free (p);
80
+ }
81
+
82
+ /* Grow VEC by SIZE bytes. */
83
+
84
+ void *
85
+ backtrace_vector_grow (struct backtrace_state *state ATTRIBUTE_UNUSED,
86
+ size_t size, backtrace_error_callback error_callback,
87
+ void *data, struct backtrace_vector *vec)
88
+ {
89
+ void *ret;
90
+
91
+ if (size > vec->alc)
92
+ {
93
+ size_t alc;
94
+ void *base;
95
+
96
+ if (vec->size == 0)
97
+ alc = 32 * size;
98
+ else if (vec->size >= 4096)
99
+ alc = vec->size + 4096;
100
+ else
101
+ alc = 2 * vec->size;
102
+
103
+ if (alc < vec->size + size)
104
+ alc = vec->size + size;
105
+
106
+ base = tracy_realloc (vec->base, alc);
107
+ if (base == NULL)
108
+ {
109
+ error_callback (data, "realloc", errno);
110
+ return NULL;
111
+ }
112
+
113
+ vec->base = base;
114
+ vec->alc = alc - vec->size;
115
+ }
116
+
117
+ ret = (char *) vec->base + vec->size;
118
+ vec->size += size;
119
+ vec->alc -= size;
120
+ return ret;
121
+ }
122
+
123
+ /* Finish the current allocation on VEC. */
124
+
125
+ void *
126
+ backtrace_vector_finish (struct backtrace_state *state,
127
+ struct backtrace_vector *vec,
128
+ backtrace_error_callback error_callback,
129
+ void *data)
130
+ {
131
+ void *ret;
132
+
133
+ /* With this allocator we call realloc in backtrace_vector_grow,
134
+ which means we can't easily reuse the memory here. So just
135
+ release it. */
136
+ if (!backtrace_vector_release (state, vec, error_callback, data))
137
+ return NULL;
138
+ ret = vec->base;
139
+ vec->base = NULL;
140
+ vec->size = 0;
141
+ vec->alc = 0;
142
+ return ret;
143
+ }
144
+
145
+ /* Release any extra space allocated for VEC. */
146
+
147
+ int
148
+ backtrace_vector_release (struct backtrace_state *state ATTRIBUTE_UNUSED,
149
+ struct backtrace_vector *vec,
150
+ backtrace_error_callback error_callback,
151
+ void *data)
152
+ {
153
+ vec->alc = 0;
154
+
155
+ if (vec->size == 0)
156
+ {
157
+ /* As of C17, realloc with size 0 is marked as an obsolescent feature, use
158
+ free instead. */
159
+ tracy_free (vec->base);
160
+ vec->base = NULL;
161
+ return 1;
162
+ }
163
+
164
+ vec->base = tracy_realloc (vec->base, vec->size);
165
+ if (vec->base == NULL)
166
+ {
167
+ error_callback (data, "realloc", errno);
168
+ return 0;
169
+ }
170
+
171
+ return 1;
172
+ }
173
+
174
+ }
third_party/tracy/public/libbacktrace/dwarf.cpp ADDED
The diff for this file is too large to render. See raw diff
 
third_party/tracy/public/libbacktrace/elf.cpp ADDED
The diff for this file is too large to render. See raw diff
 
third_party/tracy/public/libbacktrace/mmapio.cpp ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* mmapio.c -- File views using mmap.
2
+ Copyright (C) 2012-2021 Free Software Foundation, Inc.
3
+ Written by Ian Lance Taylor, Google.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are
7
+ met:
8
+
9
+ (1) Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ (2) Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in
14
+ the documentation and/or other materials provided with the
15
+ distribution.
16
+
17
+ (3) The name of the author may not be used to
18
+ endorse or promote products derived from this software without
19
+ specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
+ POSSIBILITY OF SUCH DAMAGE. */
32
+
33
+ #include "config.h"
34
+
35
+ #include <errno.h>
36
+ #include <sys/types.h>
37
+ #include <sys/mman.h>
38
+ #include <unistd.h>
39
+
40
+ #include "backtrace.hpp"
41
+ #include "internal.hpp"
42
+
43
+ #ifndef HAVE_DECL_GETPAGESIZE
44
+ extern int getpagesize (void);
45
+ #endif
46
+
47
+ #ifndef MAP_FAILED
48
+ #define MAP_FAILED ((void *)-1)
49
+ #endif
50
+
51
+ namespace tracy
52
+ {
53
+
54
+ /* This file implements file views and memory allocation when mmap is
55
+ available. */
56
+
57
+ /* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */
58
+
59
+ int
60
+ backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
61
+ int descriptor, off_t offset, uint64_t size,
62
+ backtrace_error_callback error_callback,
63
+ void *data, struct backtrace_view *view)
64
+ {
65
+ size_t pagesize;
66
+ unsigned int inpage;
67
+ off_t pageoff;
68
+ void *map;
69
+
70
+ if ((uint64_t) (size_t) size != size)
71
+ {
72
+ error_callback (data, "file size too large", 0);
73
+ return 0;
74
+ }
75
+
76
+ pagesize = getpagesize ();
77
+ inpage = offset % pagesize;
78
+ pageoff = offset - inpage;
79
+
80
+ size += inpage;
81
+ size = (size + (pagesize - 1)) & ~ (pagesize - 1);
82
+
83
+ map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff);
84
+ if (map == MAP_FAILED)
85
+ {
86
+ error_callback (data, "mmap", errno);
87
+ return 0;
88
+ }
89
+
90
+ view->data = (char *) map + inpage;
91
+ view->base = map;
92
+ view->len = size;
93
+
94
+ return 1;
95
+ }
96
+
97
+ /* Release a view read by backtrace_get_view. */
98
+
99
+ void
100
+ backtrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
101
+ struct backtrace_view *view,
102
+ backtrace_error_callback error_callback,
103
+ void *data)
104
+ {
105
+ union {
106
+ const void *cv;
107
+ void *v;
108
+ } cc;
109
+
110
+ cc.cv = view->base;
111
+ if (munmap (cc.v, view->len) < 0)
112
+ error_callback (data, "munmap", errno);
113
+ }
114
+
115
+ }
third_party/tracy/public/libbacktrace/sort.cpp ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* sort.c -- Sort without allocating memory
2
+ Copyright (C) 2012-2021 Free Software Foundation, Inc.
3
+ Written by Ian Lance Taylor, Google.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are
7
+ met:
8
+
9
+ (1) Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ (2) Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in
14
+ the documentation and/or other materials provided with the
15
+ distribution.
16
+
17
+ (3) The name of the author may not be used to
18
+ endorse or promote products derived from this software without
19
+ specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
+ POSSIBILITY OF SUCH DAMAGE. */
32
+
33
+ #include "config.h"
34
+
35
+ #include <stddef.h>
36
+ #include <sys/types.h>
37
+
38
+ #include "backtrace.hpp"
39
+ #include "internal.hpp"
40
+
41
+ namespace tracy
42
+ {
43
+
44
+ /* The GNU glibc version of qsort allocates memory, which we must not
45
+ do if we are invoked by a signal handler. So provide our own
46
+ sort. */
47
+
48
+ static void
49
+ swap (char *a, char *b, size_t size)
50
+ {
51
+ size_t i;
52
+
53
+ for (i = 0; i < size; i++, a++, b++)
54
+ {
55
+ char t;
56
+
57
+ t = *a;
58
+ *a = *b;
59
+ *b = t;
60
+ }
61
+ }
62
+
63
+ void
64
+ backtrace_qsort (void *basearg, size_t count, size_t size,
65
+ int (*compar) (const void *, const void *))
66
+ {
67
+ char *base = (char *) basearg;
68
+ size_t i;
69
+ size_t mid;
70
+
71
+ tail_recurse:
72
+ if (count < 2)
73
+ return;
74
+
75
+ /* The symbol table and DWARF tables, which is all we use this
76
+ routine for, tend to be roughly sorted. Pick the middle element
77
+ in the array as our pivot point, so that we are more likely to
78
+ cut the array in half for each recursion step. */
79
+ swap (base, base + (count / 2) * size, size);
80
+
81
+ mid = 0;
82
+ for (i = 1; i < count; i++)
83
+ {
84
+ if ((*compar) (base, base + i * size) > 0)
85
+ {
86
+ ++mid;
87
+ if (i != mid)
88
+ swap (base + mid * size, base + i * size, size);
89
+ }
90
+ }
91
+
92
+ if (mid > 0)
93
+ swap (base, base + mid * size, size);
94
+
95
+ /* Recurse with the smaller array, loop with the larger one. That
96
+ ensures that our maximum stack depth is log count. */
97
+ if (2 * mid < count)
98
+ {
99
+ backtrace_qsort (base, mid, size, compar);
100
+ base += (mid + 1) * size;
101
+ count -= mid + 1;
102
+ goto tail_recurse;
103
+ }
104
+ else
105
+ {
106
+ backtrace_qsort (base + (mid + 1) * size, count - (mid + 1),
107
+ size, compar);
108
+ count = mid;
109
+ goto tail_recurse;
110
+ }
111
+ }
112
+
113
+ }
third_party/tracy/public/libbacktrace/state.cpp ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* state.c -- Create the backtrace state.
2
+ Copyright (C) 2012-2021 Free Software Foundation, Inc.
3
+ Written by Ian Lance Taylor, Google.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are
7
+ met:
8
+
9
+ (1) Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ (2) Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in
14
+ the documentation and/or other materials provided with the
15
+ distribution.
16
+
17
+ (3) The name of the author may not be used to
18
+ endorse or promote products derived from this software without
19
+ specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
+ POSSIBILITY OF SUCH DAMAGE. */
32
+
33
+ #include "config.h"
34
+
35
+ #include <string.h>
36
+ #include <sys/types.h>
37
+
38
+ #include "backtrace.hpp"
39
+ #include "internal.hpp"
40
+
41
+ namespace tracy
42
+ {
43
+
44
+ /* Create the backtrace state. This will then be passed to all the
45
+ other routines. */
46
+
47
+ struct backtrace_state *
48
+ backtrace_create_state (const char *filename, int threaded,
49
+ backtrace_error_callback error_callback,
50
+ void *data)
51
+ {
52
+ struct backtrace_state init_state;
53
+ struct backtrace_state *state;
54
+
55
+ #ifndef HAVE_SYNC_FUNCTIONS
56
+ if (threaded)
57
+ {
58
+ error_callback (data, "backtrace library does not support threads", 0);
59
+ return NULL;
60
+ }
61
+ #endif
62
+
63
+ memset (&init_state, 0, sizeof init_state);
64
+ init_state.filename = filename;
65
+ init_state.threaded = threaded;
66
+
67
+ state = ((struct backtrace_state *)
68
+ backtrace_alloc (&init_state, sizeof *state, error_callback, data));
69
+ if (state == NULL)
70
+ return NULL;
71
+ *state = init_state;
72
+
73
+ return state;
74
+ }
75
+
76
+ }
third_party/tracy/server/TracyCharUtil.hpp ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ifndef __TRACY__CHARUTIL_HPP__
2
+ #define __TRACY__CHARUTIL_HPP__
3
+
4
+ #include <stddef.h>
5
+ #include <stdint.h>
6
+ #include <string.h>
7
+
8
+ #define XXH_INLINE_ALL
9
+ #include "tracy_xxhash.h"
10
+
11
+ namespace tracy
12
+ {
13
+ namespace charutil
14
+ {
15
+
16
+ static inline size_t hash( const char* str )
17
+ {
18
+ const auto sz = strlen( str );
19
+ return XXH3_64bits( str, sz );
20
+ }
21
+
22
+ static inline size_t hash( const char* str, size_t sz )
23
+ {
24
+ return XXH3_64bits( str, sz );
25
+ }
26
+
27
+ struct Hasher
28
+ {
29
+ size_t operator()( const char* key ) const
30
+ {
31
+ return hash( key );
32
+ }
33
+ };
34
+
35
+ struct Comparator
36
+ {
37
+ bool operator()( const char* lhs, const char* rhs ) const
38
+ {
39
+ return strcmp( lhs, rhs ) == 0;
40
+ }
41
+ };
42
+
43
+ struct LessComparator
44
+ {
45
+ bool operator()( const char* lhs, const char* rhs ) const
46
+ {
47
+ return strcmp( lhs, rhs ) < 0;
48
+ }
49
+ };
50
+
51
+ struct StringKey
52
+ {
53
+ const char* ptr;
54
+ size_t sz;
55
+
56
+ struct Hasher
57
+ {
58
+ size_t operator()( const StringKey& key ) const
59
+ {
60
+ return hash( key.ptr, key.sz );
61
+ }
62
+ };
63
+
64
+ struct Comparator
65
+ {
66
+ bool operator()( const StringKey& lhs, const StringKey& rhs ) const
67
+ {
68
+ return lhs.sz == rhs.sz && memcmp( lhs.ptr, rhs.ptr, lhs.sz ) == 0;
69
+ }
70
+ };
71
+ };
72
+
73
+ }
74
+ }
75
+
76
+ #endif
third_party/tracy/server/TracyEvent.hpp ADDED
@@ -0,0 +1,850 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ifndef __TRACYEVENT_HPP__
2
+ #define __TRACYEVENT_HPP__
3
+
4
+ #include <assert.h>
5
+ #include <limits>
6
+ #include <stdint.h>
7
+ #include <string>
8
+ #include <string.h>
9
+
10
+ #include "TracyCharUtil.hpp"
11
+ #include "TracyShortPtr.hpp"
12
+ #include "TracySortedVector.hpp"
13
+ #include "TracyVector.hpp"
14
+ #include "tracy_robin_hood.h"
15
+ #include "../public/common/TracyForceInline.hpp"
16
+ #include "../public/common/TracyQueue.hpp"
17
+
18
+ namespace tracy
19
+ {
20
+
21
+ #pragma pack( push, 1 )
22
+
23
+ struct StringRef
24
+ {
25
+ enum Type { Ptr, Idx };
26
+
27
+ tracy_force_inline StringRef() : str( 0 ), __data( 0 ) {}
28
+ tracy_force_inline StringRef( Type t, uint64_t data )
29
+ : str( data )
30
+ , __data( 0 )
31
+ {
32
+ isidx = t == Idx;
33
+ active = 1;
34
+ }
35
+
36
+ uint64_t str;
37
+
38
+ union
39
+ {
40
+ struct
41
+ {
42
+ uint8_t isidx : 1;
43
+ uint8_t active : 1;
44
+ };
45
+ uint8_t __data;
46
+ };
47
+ };
48
+
49
+ struct StringRefHasher
50
+ {
51
+ size_t operator()( const StringRef& key ) const
52
+ {
53
+ return charutil::hash( (const char*)&key, sizeof( StringRef ) );
54
+ }
55
+ };
56
+
57
+ struct StringRefComparator
58
+ {
59
+ bool operator()( const StringRef& lhs, const StringRef& rhs ) const
60
+ {
61
+ return memcmp( &lhs, &rhs, sizeof( StringRef ) ) == 0;
62
+ }
63
+ };
64
+
65
+ class StringIdx
66
+ {
67
+ public:
68
+ tracy_force_inline StringIdx() { memset( m_idx, 0, sizeof( m_idx ) ); }
69
+ tracy_force_inline StringIdx( uint32_t idx )
70
+ {
71
+ SetIdx( idx );
72
+ }
73
+
74
+ tracy_force_inline void SetIdx( uint32_t idx )
75
+ {
76
+ idx++;
77
+ memcpy( m_idx, &idx, 3 );
78
+ }
79
+
80
+ tracy_force_inline uint32_t Idx() const
81
+ {
82
+ uint32_t idx = 0;
83
+ memcpy( &idx, m_idx, 3 );
84
+ assert( idx != 0 );
85
+ return idx - 1;
86
+ }
87
+
88
+ tracy_force_inline bool Active() const
89
+ {
90
+ uint32_t zero = 0;
91
+ return memcmp( m_idx, &zero, 3 ) != 0;
92
+ }
93
+
94
+ private:
95
+ uint8_t m_idx[3];
96
+ };
97
+
98
+ struct StringIdxHasher
99
+ {
100
+ size_t operator()( const StringIdx& key ) const
101
+ {
102
+ return charutil::hash( (const char*)&key, sizeof( StringIdx ) );
103
+ }
104
+ };
105
+
106
+ struct StringIdxComparator
107
+ {
108
+ bool operator()( const StringIdx& lhs, const StringIdx& rhs ) const
109
+ {
110
+ return memcmp( &lhs, &rhs, sizeof( StringIdx ) ) == 0;
111
+ }
112
+ };
113
+
114
+ class Int24
115
+ {
116
+ public:
117
+ tracy_force_inline Int24() { memset( m_val, 0, sizeof( m_val ) ); }
118
+ tracy_force_inline Int24( uint32_t val )
119
+ {
120
+ SetVal( val );
121
+ }
122
+
123
+ tracy_force_inline void SetVal( uint32_t val )
124
+ {
125
+ memcpy( m_val, &val, 2 );
126
+ val >>= 16;
127
+ memcpy( m_val+2, &val, 1 );
128
+ }
129
+
130
+ tracy_force_inline uint32_t Val() const
131
+ {
132
+ uint8_t hi;
133
+ memcpy( &hi, m_val+2, 1 );
134
+ uint16_t lo;
135
+ memcpy( &lo, m_val, 2 );
136
+ return ( uint32_t( hi ) << 16 ) | lo;
137
+ }
138
+
139
+ private:
140
+ uint8_t m_val[3];
141
+ };
142
+
143
+ class Int48
144
+ {
145
+ public:
146
+ tracy_force_inline Int48() {}
147
+ tracy_force_inline Int48( int64_t val )
148
+ {
149
+ SetVal( val );
150
+ }
151
+
152
+ tracy_force_inline void Clear()
153
+ {
154
+ memset( m_val, 0, 6 );
155
+ }
156
+
157
+ tracy_force_inline void SetVal( int64_t val )
158
+ {
159
+ memcpy( m_val, &val, 4 );
160
+ val >>= 32;
161
+ memcpy( m_val+4, &val, 2 );
162
+ }
163
+
164
+ tracy_force_inline int64_t Val() const
165
+ {
166
+ int16_t hi;
167
+ memcpy( &hi, m_val+4, 2 );
168
+ uint32_t lo;
169
+ memcpy( &lo, m_val, 4 );
170
+ return ( int64_t( uint64_t( hi ) << 32 ) ) | lo;
171
+ }
172
+
173
+ tracy_force_inline bool IsNonNegative() const
174
+ {
175
+ return ( m_val[5] >> 7 ) == 0;
176
+ }
177
+
178
+ private:
179
+ uint8_t m_val[6];
180
+ };
181
+
182
+ struct Int48Sort { bool operator()( const Int48& lhs, const Int48& rhs ) { return lhs.Val() < rhs.Val(); }; };
183
+
184
+
185
+ struct SourceLocationBase
186
+ {
187
+ StringRef name;
188
+ StringRef function;
189
+ StringRef file;
190
+ uint32_t line;
191
+ uint32_t color;
192
+ };
193
+
194
+ struct SourceLocation : public SourceLocationBase
195
+ {
196
+ mutable uint32_t namehash;
197
+ };
198
+
199
+ enum { SourceLocationSize = sizeof( SourceLocation ) };
200
+
201
+
202
+ struct ZoneEvent
203
+ {
204
+ tracy_force_inline ZoneEvent() {};
205
+
206
+ tracy_force_inline int64_t Start() const { return int64_t( _start_srcloc ) >> 16; }
207
+ tracy_force_inline void SetStart( int64_t start ) { assert( start < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_start_srcloc)+2, &start, 4 ); memcpy( ((char*)&_start_srcloc)+6, ((char*)&start)+4, 2 ); }
208
+ tracy_force_inline int64_t End() const { return int64_t( _end_child1 ) >> 16; }
209
+ tracy_force_inline void SetEnd( int64_t end ) { assert( end < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_end_child1)+2, &end, 4 ); memcpy( ((char*)&_end_child1)+6, ((char*)&end)+4, 2 ); }
210
+ tracy_force_inline bool IsEndValid() const { return ( _end_child1 >> 63 ) == 0; }
211
+ tracy_force_inline int16_t SrcLoc() const { return int16_t( _start_srcloc & 0xFFFF ); }
212
+ tracy_force_inline void SetSrcLoc( int16_t srcloc ) { memcpy( &_start_srcloc, &srcloc, 2 ); }
213
+ tracy_force_inline int32_t Child() const { int32_t child; memcpy( &child, &_child2, 4 ); return child; }
214
+ tracy_force_inline void SetChild( int32_t child ) { memcpy( &_child2, &child, 4 ); }
215
+ tracy_force_inline bool HasChildren() const { uint8_t tmp; memcpy( &tmp, ((char*)&_end_child1)+1, 1 ); return ( tmp >> 7 ) == 0; }
216
+
217
+ tracy_force_inline void SetStartSrcLoc( int64_t start, int16_t srcloc ) { assert( start < (int64_t)( 1ull << 47 ) ); start <<= 16; start |= uint16_t( srcloc ); memcpy( &_start_srcloc, &start, 8 ); }
218
+
219
+ uint64_t _start_srcloc;
220
+ uint16_t _child2;
221
+ uint64_t _end_child1;
222
+ uint32_t extra;
223
+ };
224
+
225
+ enum { ZoneEventSize = sizeof( ZoneEvent ) };
226
+ static_assert( std::is_standard_layout<ZoneEvent>::value, "ZoneEvent is not standard layout" );
227
+
228
+
229
+ struct ZoneExtra
230
+ {
231
+ Int24 callstack;
232
+ StringIdx text;
233
+ StringIdx name;
234
+ Int24 color;
235
+ };
236
+
237
+ enum { ZoneExtraSize = sizeof( ZoneExtra ) };
238
+
239
+
240
+ // This union exploits the fact that the current implementations of x64 and arm64 do not provide
241
+ // full 64 bit address space. The high bits must be bit-extended, so 0x80... is an invalid pointer.
242
+ // This allows using the highest bit as a selector between a native pointer and a table index here.
243
+ union CallstackFrameId
244
+ {
245
+ struct
246
+ {
247
+ uint64_t idx : 62;
248
+ uint64_t sel : 1;
249
+ uint64_t custom : 1;
250
+ };
251
+ uint64_t data;
252
+ };
253
+
254
+ enum { CallstackFrameIdSize = sizeof( CallstackFrameId ) };
255
+
256
+ static tracy_force_inline bool operator==( const CallstackFrameId& lhs, const CallstackFrameId& rhs ) { return lhs.data == rhs.data; }
257
+
258
+
259
+ struct SampleData
260
+ {
261
+ Int48 time;
262
+ Int24 callstack;
263
+ };
264
+
265
+ enum { SampleDataSize = sizeof( SampleData ) };
266
+
267
+ struct SampleDataSort { bool operator()( const SampleData& lhs, const SampleData& rhs ) { return lhs.time.Val() < rhs.time.Val(); }; };
268
+
269
+
270
+ struct SampleDataRange
271
+ {
272
+ Int48 time;
273
+ uint16_t thread;
274
+ CallstackFrameId ip;
275
+ };
276
+
277
+ enum { SampleDataRangeSize = sizeof( SampleDataRange ) };
278
+
279
+
280
+ struct HwSampleData
281
+ {
282
+ SortedVector<Int48, Int48Sort> cycles;
283
+ SortedVector<Int48, Int48Sort> retired;
284
+ SortedVector<Int48, Int48Sort> cacheRef;
285
+ SortedVector<Int48, Int48Sort> cacheMiss;
286
+ SortedVector<Int48, Int48Sort> branchRetired;
287
+ SortedVector<Int48, Int48Sort> branchMiss;
288
+
289
+ bool is_sorted() const
290
+ {
291
+ return
292
+ cycles.is_sorted() &&
293
+ retired.is_sorted() &&
294
+ cacheRef.is_sorted() &&
295
+ cacheMiss.is_sorted() &&
296
+ branchRetired.is_sorted() &&
297
+ branchMiss.is_sorted();
298
+ }
299
+
300
+ void sort()
301
+ {
302
+ if( !cycles.is_sorted() ) cycles.sort();
303
+ if( !retired.is_sorted() ) retired.sort();
304
+ if( !cacheRef.is_sorted() ) cacheRef.sort();
305
+ if( !cacheMiss.is_sorted() ) cacheMiss.sort();
306
+ if( !branchRetired.is_sorted() ) branchRetired.sort();
307
+ if( !branchMiss.is_sorted() ) branchMiss.sort();
308
+ }
309
+ };
310
+
311
+ enum { HwSampleDataSize = sizeof( HwSampleData ) };
312
+
313
+
314
+ struct LockEvent
315
+ {
316
+ enum class Type : uint8_t
317
+ {
318
+ Wait,
319
+ Obtain,
320
+ Release,
321
+ WaitShared,
322
+ ObtainShared,
323
+ ReleaseShared
324
+ };
325
+
326
+ tracy_force_inline int64_t Time() const { return int64_t( _time_srcloc ) >> 16; }
327
+ tracy_force_inline void SetTime( int64_t time ) { assert( time < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_time_srcloc)+2, &time, 4 ); memcpy( ((char*)&_time_srcloc)+6, ((char*)&time)+4, 2 ); }
328
+ tracy_force_inline int16_t SrcLoc() const { return int16_t( _time_srcloc & 0xFFFF ); }
329
+ tracy_force_inline void SetSrcLoc( int16_t srcloc ) { memcpy( &_time_srcloc, &srcloc, 2 ); }
330
+
331
+ uint64_t _time_srcloc;
332
+ uint8_t thread;
333
+ Type type;
334
+ };
335
+
336
+ struct LockEventShared : public LockEvent
337
+ {
338
+ uint64_t waitShared;
339
+ uint64_t sharedList;
340
+ };
341
+
342
+ struct LockEventPtr
343
+ {
344
+ short_ptr<LockEvent> ptr;
345
+ uint8_t lockingThread;
346
+ uint8_t lockCount;
347
+ uint64_t waitList;
348
+ };
349
+
350
+ enum { LockEventSize = sizeof( LockEvent ) };
351
+ enum { LockEventSharedSize = sizeof( LockEventShared ) };
352
+ enum { LockEventPtrSize = sizeof( LockEventPtr ) };
353
+
354
+ enum { MaxLockThreads = sizeof( LockEventPtr::waitList ) * 8 };
355
+ static_assert( std::numeric_limits<decltype(LockEventPtr::lockCount)>::max() >= MaxLockThreads, "Not enough space for lock count." );
356
+
357
+
358
+ enum class LockType : uint8_t;
359
+
360
+ struct LockMap
361
+ {
362
+ struct TimeRange
363
+ {
364
+ int64_t start = std::numeric_limits<int64_t>::max();
365
+ int64_t end = std::numeric_limits<int64_t>::min();
366
+ };
367
+
368
+ StringIdx customName;
369
+ int16_t srcloc;
370
+ Vector<LockEventPtr> timeline;
371
+ unordered_flat_map<uint64_t, uint8_t> threadMap;
372
+ std::vector<uint64_t> threadList;
373
+ LockType type;
374
+ int64_t timeAnnounce;
375
+ int64_t timeTerminate;
376
+ bool valid;
377
+ bool isContended;
378
+ uint64_t lockingThread;
379
+
380
+ TimeRange range[64];
381
+ };
382
+
383
+ struct LockHighlight
384
+ {
385
+ int64_t id;
386
+ int64_t begin;
387
+ int64_t end;
388
+ uint8_t thread;
389
+ bool blocked;
390
+ };
391
+
392
+
393
+ struct GpuEvent
394
+ {
395
+ tracy_force_inline int64_t CpuStart() const { return int64_t( _cpuStart_srcloc ) >> 16; }
396
+ tracy_force_inline void SetCpuStart( int64_t cpuStart ) { assert( cpuStart < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_cpuStart_srcloc)+2, &cpuStart, 4 ); memcpy( ((char*)&_cpuStart_srcloc)+6, ((char*)&cpuStart)+4, 2 ); }
397
+ tracy_force_inline int64_t CpuEnd() const { return int64_t( _cpuEnd_thread ) >> 16; }
398
+ tracy_force_inline void SetCpuEnd( int64_t cpuEnd ) { assert( cpuEnd < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_cpuEnd_thread)+2, &cpuEnd, 4 ); memcpy( ((char*)&_cpuEnd_thread)+6, ((char*)&cpuEnd)+4, 2 ); }
399
+ tracy_force_inline int64_t GpuStart() const { return int64_t( _gpuStart_child1 ) >> 16; }
400
+ tracy_force_inline void SetGpuStart( int64_t gpuStart ) { /*assert( gpuStart < (int64_t)( 1ull << 47 ) );*/ memcpy( ((char*)&_gpuStart_child1)+2, &gpuStart, 4 ); memcpy( ((char*)&_gpuStart_child1)+6, ((char*)&gpuStart)+4, 2 ); }
401
+ tracy_force_inline int64_t GpuEnd() const { return int64_t( _gpuEnd_child2 ) >> 16; }
402
+ tracy_force_inline void SetGpuEnd( int64_t gpuEnd ) { assert( gpuEnd < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_gpuEnd_child2)+2, &gpuEnd, 4 ); memcpy( ((char*)&_gpuEnd_child2)+6, ((char*)&gpuEnd)+4, 2 ); }
403
+ tracy_force_inline int16_t SrcLoc() const { return int16_t( _cpuStart_srcloc & 0xFFFF ); }
404
+ tracy_force_inline void SetSrcLoc( int16_t srcloc ) { memcpy( &_cpuStart_srcloc, &srcloc, 2 ); }
405
+ tracy_force_inline uint16_t Thread() const { return uint16_t( _cpuEnd_thread & 0xFFFF ); }
406
+ tracy_force_inline void SetThread( uint16_t thread ) { memcpy( &_cpuEnd_thread, &thread, 2 ); }
407
+ tracy_force_inline int32_t Child() const { return int32_t( uint32_t( _gpuStart_child1 & 0xFFFF ) | ( uint32_t( _gpuEnd_child2 & 0xFFFF ) << 16 ) ); }
408
+ tracy_force_inline void SetChild( int32_t child ) { memcpy( &_gpuStart_child1, &child, 2 ); memcpy( &_gpuEnd_child2, ((char*)&child)+2, 2 ); }
409
+
410
+ uint64_t _cpuStart_srcloc;
411
+ uint64_t _cpuEnd_thread;
412
+ uint64_t _gpuStart_child1;
413
+ uint64_t _gpuEnd_child2;
414
+ Int24 callstack;
415
+ };
416
+
417
+ enum { GpuEventSize = sizeof( GpuEvent ) };
418
+ static_assert( std::is_standard_layout<GpuEvent>::value, "GpuEvent is not standard layout" );
419
+
420
+
421
+ struct MemEvent
422
+ {
423
+ tracy_force_inline uint64_t Ptr() const { return uint64_t( int64_t( _ptr_csalloc1 ) >> 8 ); }
424
+ tracy_force_inline void SetPtr( uint64_t ptr ) { memcpy( ((char*)&_ptr_csalloc1)+1, &ptr, 4 ); memcpy( ((char*)&_ptr_csalloc1)+5, ((char*)&ptr)+4, 2 ); memcpy( ((char*)&_ptr_csalloc1)+7, ((char*)&ptr)+6, 1 ); }
425
+ tracy_force_inline uint64_t Size() const { return _size_csalloc2 >> 16; }
426
+ tracy_force_inline void SetSize( uint64_t size ) { assert( size < ( 1ull << 47 ) ); memcpy( ((char*)&_size_csalloc2)+2, &size, 4 ); memcpy( ((char*)&_size_csalloc2)+6, ((char*)&size)+4, 2 ); }
427
+ tracy_force_inline uint32_t CsAlloc() const { return uint8_t( _ptr_csalloc1 ) | ( uint16_t( _size_csalloc2 ) << 8 ); }
428
+ tracy_force_inline void SetCsAlloc( uint32_t csAlloc ) { memcpy( &_ptr_csalloc1, &csAlloc, 1 ); memcpy( &_size_csalloc2, ((char*)&csAlloc)+1, 2 ); }
429
+ tracy_force_inline int64_t TimeAlloc() const { return int64_t( _time_thread_alloc ) >> 16; }
430
+ tracy_force_inline void SetTimeAlloc( int64_t time ) { assert( time < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_time_thread_alloc)+2, &time, 4 ); memcpy( ((char*)&_time_thread_alloc)+6, ((char*)&time)+4, 2 ); }
431
+ tracy_force_inline int64_t TimeFree() const { return int64_t( _time_thread_free ) >> 16; }
432
+ tracy_force_inline void SetTimeFree( int64_t time ) { assert( time < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_time_thread_free)+2, &time, 4 ); memcpy( ((char*)&_time_thread_free)+6, ((char*)&time)+4, 2 ); }
433
+ tracy_force_inline uint16_t ThreadAlloc() const { return uint16_t( _time_thread_alloc ); }
434
+ tracy_force_inline void SetThreadAlloc( uint16_t thread ) { memcpy( &_time_thread_alloc, &thread, 2 ); }
435
+ tracy_force_inline uint16_t ThreadFree() const { return uint16_t( _time_thread_free ); }
436
+ tracy_force_inline void SetThreadFree( uint16_t thread ) { memcpy( &_time_thread_free, &thread, 2 ); }
437
+
438
+ tracy_force_inline void SetTimeThreadAlloc( int64_t time, uint16_t thread ) { time <<= 16; time |= thread; memcpy( &_time_thread_alloc, &time, 8 ); }
439
+ tracy_force_inline void SetTimeThreadFree( int64_t time, uint16_t thread ) { uint64_t t; memcpy( &t, &time, 8 ); t <<= 16; t |= thread; memcpy( &_time_thread_free, &t, 8 ); }
440
+
441
+ uint64_t _ptr_csalloc1;
442
+ uint64_t _size_csalloc2;
443
+ Int24 csFree;
444
+ uint64_t _time_thread_alloc;
445
+ uint64_t _time_thread_free;
446
+ };
447
+
448
+ enum { MemEventSize = sizeof( MemEvent ) };
449
+ static_assert( std::is_standard_layout<MemEvent>::value, "MemEvent is not standard layout" );
450
+
451
+
452
+ struct CallstackFrameBasic
453
+ {
454
+ StringIdx name;
455
+ StringIdx file;
456
+ uint32_t line;
457
+ };
458
+
459
+ struct CallstackFrame : public CallstackFrameBasic
460
+ {
461
+ uint64_t symAddr;
462
+ };
463
+
464
+ struct SymbolData : public CallstackFrameBasic
465
+ {
466
+ StringIdx imageName;
467
+ StringIdx callFile;
468
+ uint32_t callLine;
469
+ uint8_t isInline;
470
+ Int24 size;
471
+ };
472
+
473
+ enum { CallstackFrameBasicSize = sizeof( CallstackFrameBasic ) };
474
+ enum { CallstackFrameSize = sizeof( CallstackFrame ) };
475
+ enum { SymbolDataSize = sizeof( SymbolData ) };
476
+
477
+
478
+ struct SymbolLocation
479
+ {
480
+ uint64_t addr;
481
+ uint32_t len;
482
+ };
483
+
484
+ enum { SymbolLocationSize = sizeof( SymbolLocation ) };
485
+
486
+
487
+ struct CallstackFrameData
488
+ {
489
+ short_ptr<CallstackFrame> data;
490
+ uint8_t size;
491
+ StringIdx imageName;
492
+ };
493
+
494
+ enum { CallstackFrameDataSize = sizeof( CallstackFrameData ) };
495
+
496
+
497
+ struct MemCallstackFrameTree
498
+ {
499
+ MemCallstackFrameTree( CallstackFrameId id ) : frame( id ), alloc( 0 ), count( 0 ) {}
500
+
501
+ CallstackFrameId frame;
502
+ uint64_t alloc;
503
+ uint32_t count;
504
+ unordered_flat_map<uint64_t, MemCallstackFrameTree> children;
505
+ unordered_flat_set<uint32_t> callstacks;
506
+ };
507
+
508
+ enum { MemCallstackFrameTreeSize = sizeof( MemCallstackFrameTree ) };
509
+
510
+
511
+ struct CallstackFrameTree
512
+ {
513
+ CallstackFrameTree( CallstackFrameId id ) : frame( id ), count( 0 ) {}
514
+
515
+ CallstackFrameId frame;
516
+ uint32_t count;
517
+ unordered_flat_map<uint64_t, CallstackFrameTree> children;
518
+ };
519
+
520
+ enum { CallstackFrameTreeSize = sizeof( CallstackFrameTree ) };
521
+
522
+
523
+ struct CrashEvent
524
+ {
525
+ uint64_t thread = 0;
526
+ int64_t time = 0;
527
+ uint64_t message = 0;
528
+ uint32_t callstack = 0;
529
+ };
530
+
531
+ enum { CrashEventSize = sizeof( CrashEvent ) };
532
+
533
+
534
+ struct ContextSwitchData
535
+ {
536
+ enum : int8_t { Fiber = 99 };
537
+ enum : int8_t { NoState = 100 };
538
+ enum : int8_t { Wakeup = -2 };
539
+
540
+ tracy_force_inline int64_t Start() const { return int64_t( _start_cpu ) >> 16; }
541
+ tracy_force_inline void SetStart( int64_t start ) { assert( start < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_start_cpu)+2, &start, 4 ); memcpy( ((char*)&_start_cpu)+6, ((char*)&start)+4, 2 ); }
542
+ tracy_force_inline int64_t End() const { return int64_t( _end_reason_state ) >> 16; }
543
+ tracy_force_inline void SetEnd( int64_t end ) { assert( end < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_end_reason_state)+2, &end, 4 ); memcpy( ((char*)&_end_reason_state)+6, ((char*)&end)+4, 2 ); }
544
+ tracy_force_inline bool IsEndValid() const { return ( _end_reason_state >> 63 ) == 0; }
545
+ tracy_force_inline uint8_t Cpu() const { return uint8_t( _start_cpu & 0xFF ); }
546
+ tracy_force_inline void SetCpu( uint8_t cpu ) { memcpy( &_start_cpu, &cpu, 1 ); }
547
+ tracy_force_inline int8_t Reason() const { return int8_t( (_end_reason_state >> 8) & 0xFF ); }
548
+ tracy_force_inline void SetReason( int8_t reason ) { memcpy( ((char*)&_end_reason_state)+1, &reason, 1 ); }
549
+ tracy_force_inline int8_t State() const { return int8_t( _end_reason_state & 0xFF ); }
550
+ tracy_force_inline void SetState( int8_t state ) { memcpy( &_end_reason_state, &state, 1 ); }
551
+ tracy_force_inline int64_t WakeupVal() const { return _wakeup.Val(); }
552
+ tracy_force_inline void SetWakeup( int64_t wakeup ) { assert( wakeup < (int64_t)( 1ull << 47 ) ); _wakeup.SetVal( wakeup ); }
553
+ tracy_force_inline uint16_t Thread() const { return _thread; }
554
+ tracy_force_inline void SetThread( uint16_t thread ) { _thread = thread; }
555
+
556
+ tracy_force_inline void SetStartCpu( int64_t start, uint8_t cpu ) { assert( start < (int64_t)( 1ull << 47 ) ); _start_cpu = ( uint64_t( start ) << 16 ) | cpu; }
557
+ tracy_force_inline void SetEndReasonState( int64_t end, int8_t reason, int8_t state ) { assert( end < (int64_t)( 1ull << 47 ) ); _end_reason_state = ( uint64_t( end ) << 16 ) | ( uint64_t( reason ) << 8 ) | uint8_t( state ); }
558
+
559
+ uint64_t _start_cpu;
560
+ uint64_t _end_reason_state;
561
+ Int48 _wakeup;
562
+ uint16_t _thread;
563
+ };
564
+
565
+ enum { ContextSwitchDataSize = sizeof( ContextSwitchData ) };
566
+
567
+
568
+ struct ContextSwitchCpu
569
+ {
570
+ tracy_force_inline int64_t Start() const { return int64_t( _start_thread ) >> 16; }
571
+ tracy_force_inline void SetStart( int64_t start ) { assert( start < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_start_thread)+2, &start, 4 ); memcpy( ((char*)&_start_thread)+6, ((char*)&start)+4, 2 ); }
572
+ tracy_force_inline int64_t End() const { int64_t v; memcpy( &v, ((char*)&_end)-2, 8 ); return v >> 16; }
573
+ tracy_force_inline void SetEnd( int64_t end ) { assert( end < (int64_t)( 1ull << 47 ) ); _end.SetVal( end ); }
574
+ tracy_force_inline bool IsEndValid() const { return _end.IsNonNegative(); }
575
+ tracy_force_inline uint16_t Thread() const { return uint16_t( _start_thread ); }
576
+ tracy_force_inline void SetThread( uint16_t thread ) { memcpy( &_start_thread, &thread, 2 ); }
577
+
578
+ tracy_force_inline void SetStartThread( int64_t start, uint16_t thread ) { assert( start < (int64_t)( 1ull << 47 ) ); _start_thread = ( uint64_t( start ) << 16 ) | thread; }
579
+
580
+ uint64_t _start_thread;
581
+ Int48 _end;
582
+ };
583
+
584
+ enum { ContextSwitchCpuSize = sizeof( ContextSwitchCpu ) };
585
+
586
+
587
+ struct ContextSwitchUsage
588
+ {
589
+ ContextSwitchUsage() {}
590
+ ContextSwitchUsage( int64_t time, uint8_t other, uint8_t own ) { SetTime( time ); SetOther( other ); SetOwn( own ); }
591
+
592
+ tracy_force_inline int64_t Time() const { return int64_t( _time_other_own ) >> 16; }
593
+ tracy_force_inline void SetTime( int64_t time ) { assert( time < (int64_t)( 1ull << 47 ) ); memcpy( ((char*)&_time_other_own)+2, &time, 4 ); memcpy( ((char*)&_time_other_own)+6, ((char*)&time)+4, 2 ); }
594
+ tracy_force_inline uint8_t Other() const { return uint8_t( _time_other_own ); }
595
+ tracy_force_inline void SetOther( uint8_t other ) { memcpy( &_time_other_own, &other, 1 ); }
596
+ tracy_force_inline uint8_t Own() const { uint8_t v; memcpy( &v, ((char*)&_time_other_own)+1, 1 );return v; }
597
+ tracy_force_inline void SetOwn( uint8_t own ) { memcpy( ((char*)&_time_other_own)+1, &own, 1 ); }
598
+
599
+ uint64_t _time_other_own;
600
+ };
601
+
602
+ enum { ContextSwitchUsageSize = sizeof( ContextSwitchUsage ) };
603
+
604
+
605
+ struct MessageData
606
+ {
607
+ int64_t time;
608
+ StringRef ref;
609
+ uint16_t thread;
610
+ uint32_t color;
611
+ Int24 callstack;
612
+ };
613
+
614
+ enum { MessageDataSize = sizeof( MessageData ) };
615
+
616
+
617
+ struct PlotItem
618
+ {
619
+ Int48 time;
620
+ double val;
621
+ };
622
+
623
+ enum { PlotItemSize = sizeof( PlotItem ) };
624
+
625
+
626
+ struct FrameEvent
627
+ {
628
+ int64_t start;
629
+ int64_t end;
630
+ int32_t frameImage;
631
+ };
632
+
633
+ enum { FrameEventSize = sizeof( FrameEvent ) };
634
+
635
+
636
+ struct FrameImage
637
+ {
638
+ short_ptr<const char> ptr;
639
+ uint32_t csz;
640
+ uint16_t w, h;
641
+ uint32_t frameRef;
642
+ uint8_t flip;
643
+ };
644
+
645
+ enum { FrameImageSize = sizeof( FrameImage ) };
646
+
647
+
648
+ struct GhostZone
649
+ {
650
+ Int48 start, end;
651
+ Int24 frame;
652
+ int32_t child;
653
+ };
654
+
655
+ enum { GhostZoneSize = sizeof( GhostZone ) };
656
+
657
+
658
+ struct ChildSample
659
+ {
660
+ Int48 time;
661
+ uint64_t addr;
662
+ };
663
+
664
+ enum { ChildSampleSize = sizeof( ChildSample ) };
665
+
666
+ #pragma pack( pop )
667
+
668
+
669
+ struct ThreadData
670
+ {
671
+ uint64_t id;
672
+ uint64_t count;
673
+ Vector<short_ptr<ZoneEvent>> timeline;
674
+ Vector<short_ptr<ZoneEvent>> stack;
675
+ Vector<short_ptr<MessageData>> messages;
676
+ uint32_t nextZoneId;
677
+ Vector<uint32_t> zoneIdStack;
678
+ #ifndef TRACY_NO_STATISTICS
679
+ Vector<int64_t> childTimeStack;
680
+ Vector<GhostZone> ghostZones;
681
+ uint64_t ghostIdx;
682
+ SortedVector<SampleData, SampleDataSort> postponedSamples;
683
+ #endif
684
+ Vector<SampleData> samples;
685
+ SampleData pendingSample;
686
+ Vector<SampleData> ctxSwitchSamples;
687
+ uint64_t kernelSampleCnt;
688
+ uint8_t isFiber;
689
+ ThreadData* fiber;
690
+ uint8_t* stackCount;
691
+ int32_t groupHint;
692
+
693
+ tracy_force_inline void IncStackCount( int16_t srcloc ) { stackCount[uint16_t(srcloc)]++; }
694
+ tracy_force_inline bool DecStackCount( int16_t srcloc ) { return --stackCount[uint16_t(srcloc)] != 0; }
695
+ };
696
+
697
+ struct GpuCtxThreadData
698
+ {
699
+ Vector<short_ptr<GpuEvent>> timeline;
700
+ Vector<short_ptr<GpuEvent>> stack;
701
+ };
702
+
703
+ struct GpuCtxData
704
+ {
705
+ int64_t timeDiff;
706
+ uint64_t thread;
707
+ uint64_t count;
708
+ float period;
709
+ GpuContextType type;
710
+ bool hasPeriod;
711
+ bool hasCalibration;
712
+ int64_t calibratedGpuTime;
713
+ int64_t calibratedCpuTime;
714
+ double calibrationMod;
715
+ int64_t lastGpuTime;
716
+ uint64_t overflow;
717
+ uint32_t overflowMul;
718
+ StringIdx name;
719
+ unordered_flat_map<uint64_t, GpuCtxThreadData> threadData;
720
+ short_ptr<GpuEvent> query[64*1024];
721
+ };
722
+
723
+ enum { GpuCtxDataSize = sizeof( GpuCtxData ) };
724
+
725
+
726
+ enum class PlotType : uint8_t
727
+ {
728
+ User,
729
+ Memory,
730
+ SysTime,
731
+ Power
732
+ };
733
+
734
+ // Keep this in sync with enum in TracyC.h
735
+ enum class PlotValueFormatting : uint8_t
736
+ {
737
+ Number,
738
+ Memory,
739
+ Percentage,
740
+ Watt
741
+ };
742
+
743
+ struct PlotData
744
+ {
745
+ struct PlotItemSort { bool operator()( const PlotItem& lhs, const PlotItem& rhs ) { return lhs.time.Val() < rhs.time.Val(); }; };
746
+
747
+ uint64_t name;
748
+ double min;
749
+ double max;
750
+ double sum;
751
+ SortedVector<PlotItem, PlotItemSort> data;
752
+ PlotType type;
753
+ PlotValueFormatting format;
754
+ uint8_t showSteps;
755
+ uint8_t fill;
756
+ uint32_t color;
757
+
758
+ double rMin, rMax, num;
759
+ };
760
+
761
+ struct MemData
762
+ {
763
+ Vector<MemEvent> data;
764
+ Vector<uint32_t> frees;
765
+ unordered_flat_map<uint64_t, size_t> active;
766
+ uint64_t high = std::numeric_limits<uint64_t>::min();
767
+ uint64_t low = std::numeric_limits<uint64_t>::max();
768
+ uint64_t usage = 0;
769
+ PlotData* plot = nullptr;
770
+ bool reconstruct = false;
771
+ uint64_t name = 0;
772
+ };
773
+
774
+ struct FrameData
775
+ {
776
+ uint64_t name;
777
+ Vector<FrameEvent> frames;
778
+ uint8_t continuous;
779
+
780
+ int64_t min = std::numeric_limits<int64_t>::max();
781
+ int64_t max = std::numeric_limits<int64_t>::min();
782
+ int64_t total = 0;
783
+ double sumSq = 0;
784
+ };
785
+
786
+ struct StringLocation
787
+ {
788
+ const char* ptr;
789
+ uint32_t idx;
790
+ };
791
+
792
+ struct SourceLocationHasher
793
+ {
794
+ size_t operator()( const SourceLocation* ptr ) const
795
+ {
796
+ return charutil::hash( (const char*)ptr, sizeof( SourceLocationBase ) );
797
+ }
798
+ };
799
+
800
+ struct SourceLocationComparator
801
+ {
802
+ bool operator()( const SourceLocation* lhs, const SourceLocation* rhs ) const
803
+ {
804
+ return memcmp( lhs, rhs, sizeof( SourceLocationBase ) ) == 0;
805
+ }
806
+ };
807
+
808
+
809
+ struct ContextSwitch
810
+ {
811
+ Vector<ContextSwitchData> v;
812
+ int64_t runningTime = 0;
813
+ };
814
+
815
+ struct CpuData
816
+ {
817
+ Vector<ContextSwitchCpu> cs;
818
+ };
819
+
820
+ struct CpuThreadData
821
+ {
822
+ int64_t runningTime = 0;
823
+ uint32_t runningRegions = 0;
824
+ uint32_t migrations = 0;
825
+ };
826
+
827
+ enum { CpuThreadDataSize = sizeof( CpuThreadData ) };
828
+
829
+
830
+ struct Parameter
831
+ {
832
+ uint32_t idx;
833
+ StringRef name;
834
+ bool isBool;
835
+ int32_t val;
836
+ };
837
+
838
+
839
+ struct SymbolStats
840
+ {
841
+ uint32_t incl, excl;
842
+ unordered_flat_map<uint32_t, uint32_t> parents;
843
+ unordered_flat_map<uint32_t, uint32_t> baseParents;
844
+ };
845
+
846
+ enum { SymbolStatsSize = sizeof( SymbolStats ) };
847
+
848
+ }
849
+
850
+ #endif
third_party/tracy/server/TracyFileHeader.hpp ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ifndef __TRACYFILEHEADER_HPP__
2
+ #define __TRACYFILEHEADER_HPP__
3
+
4
+ #include <stdint.h>
5
+
6
+ #include "../public/common/TracyForceInline.hpp"
7
+
8
+ namespace tracy
9
+ {
10
+
11
+ static const uint8_t TracyHeader[4] = { 't', 'r', 253, 'P' };
12
+ static const uint8_t Lz4Header[4] = { 't', 'l', 'Z', 4 };
13
+ static const uint8_t ZstdHeader[4] = { 't', 'Z', 's', 't' };
14
+
15
+ static constexpr tracy_force_inline int FileVersion( uint8_t h5, uint8_t h6, uint8_t h7 )
16
+ {
17
+ return ( h5 << 16 ) | ( h6 << 8 ) | h7;
18
+ }
19
+
20
+ }
21
+
22
+ #endif