mirror of
https://github.com/wolfpld/tracy
synced 2025-04-29 04:23:51 +00:00
Compare commits
410 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a03c7580b9 | ||
|
132a4ba320 | ||
|
6b03d1dd9e | ||
|
7474127bbb | ||
|
a277453acb | ||
|
cc0c53496d | ||
|
a150fdfc35 | ||
|
753305a797 | ||
|
0039895398 | ||
|
1fc7c9f160 | ||
|
f02c6fe4d5 | ||
|
0d1d28415c | ||
|
54d6dd9662 | ||
|
195d79fc67 | ||
|
f41c4672cb | ||
|
e656d49f53 | ||
|
85a9d5e284 | ||
|
3f9c4736f3 | ||
|
49d8a2c082 | ||
|
2d9169e3d1 | ||
|
bb474a12c7 | ||
|
684400b45c | ||
|
e5482580cd | ||
|
9074461ffb | ||
|
eb47afe1f0 | ||
|
873c6ecac8 | ||
|
ae2e6d0a7b | ||
|
1530884256 | ||
|
7455e5890e | ||
|
2183962ef7 | ||
|
bc7ec5b89b | ||
|
9b3c46dd5e | ||
|
54dcbc87ad | ||
|
b8c2e25c3d | ||
|
b04dfcd43d | ||
|
48efd98df7 | ||
|
c5dc5f4455 | ||
|
8ad05c66ae | ||
|
6566d6a8d8 | ||
|
ad61037925 | ||
|
2d53818e55 | ||
|
d966ecf9f7 | ||
|
d71fc39577 | ||
|
40d12b6a53 | ||
|
4a5a21cdb0 | ||
|
50ff279aad | ||
|
367ed69501 | ||
|
8b3638e8e2 | ||
|
5c069f9d8d | ||
|
9b7d53a979 | ||
|
ad5615cda2 | ||
|
b8a64190dc | ||
|
3b48252bb3 | ||
|
526e41b5dc | ||
|
cfc67727a0 | ||
|
015a27bb4e | ||
|
f1128f825d | ||
|
c38764db3c | ||
|
408939862b | ||
|
3ac95e6902 | ||
|
0c228533f2 | ||
|
55d7df3782 | ||
|
16405715a6 | ||
|
5479a42ef9 | ||
|
4662be3aac | ||
|
e19a823c37 | ||
|
2020ef6c6e | ||
|
f583d1c855 | ||
|
7272f9cac1 | ||
|
da60684b9f | ||
|
be3aa5ac21 | ||
|
b87a935c58 | ||
|
9d03627a17 | ||
|
7c48baf132 | ||
|
2608c6bbc9 | ||
|
e49c25f2f5 | ||
|
b68f63c6d5 | ||
|
27689bcf43 | ||
|
277555af2a | ||
|
802bdbbecc | ||
|
a42ea071a0 | ||
|
fd33d1c839 | ||
|
21c8d7615d | ||
|
092e91d058 | ||
|
f01973a78c | ||
|
4273d34ca4 | ||
|
fb9686fb28 | ||
|
9b14656c8a | ||
|
38e7024277 | ||
|
7730ac595f | ||
|
82460b0316 | ||
|
caabfc6379 | ||
|
49cc094869 | ||
|
fbc40e8b9e | ||
|
4d5cd252a4 | ||
|
59116feb55 | ||
|
4fd6d5317b | ||
|
07cd1d8ee1 | ||
|
ead67c06d9 | ||
|
1d627c86be | ||
|
66a50a8c76 | ||
|
3488e08aa7 | ||
|
d16986dfa7 | ||
|
a30fff8b4c | ||
|
e981a5ba6f | ||
|
3e88544d1f | ||
|
7093eb0b08 | ||
|
7e128f3bce | ||
|
6e220fee91 | ||
|
94403bde4b | ||
|
cd8e2a5d8a | ||
|
a8f844b970 | ||
|
78bca3f0e1 | ||
|
4929ac6487 | ||
|
39d382b033 | ||
|
8baa50b2f5 | ||
|
7f516e2fed | ||
|
8b0b2343e1 | ||
|
b9c7cd1738 | ||
|
31eeb843c7 | ||
|
d30a2d6854 | ||
|
38636648d3 | ||
|
23bfabc6c2 | ||
|
57f1a63b3f | ||
|
3f700c93a6 | ||
|
a2fce55aee | ||
|
9aba23bbb0 | ||
|
96ba28e761 | ||
|
39137d809e | ||
|
117ab107c1 | ||
|
4591dfa208 | ||
|
e9eecbb2c6 | ||
|
cf912bbb19 | ||
|
1c63239a78 | ||
|
e9664a1c87 | ||
|
caf0047367 | ||
|
5051db201e | ||
|
6452690e57 | ||
|
aa28504c60 | ||
|
96e1cb17c6 | ||
|
07d38d608e | ||
|
01a7f62650 | ||
|
7fc3366086 | ||
|
99d39e6eee | ||
|
9d839c52d1 | ||
|
70fc28506f | ||
|
1e796064bc | ||
|
bb02d0b0af | ||
|
87c54f92cf | ||
|
b48ab72cf0 | ||
|
45c4dc5124 | ||
|
f703cc33cf | ||
|
8f25eaf54e | ||
|
c214804aa1 | ||
|
c5797e4e36 | ||
|
a9e8f9a5f8 | ||
|
f0ee324399 | ||
|
759b4c3bfe | ||
|
b9ee0d3b4c | ||
|
e756fa75cf | ||
|
e6ee311392 | ||
|
b9b808ca12 | ||
|
cc0f158c16 | ||
|
5120ad8311 | ||
|
339a92a7b2 | ||
|
0cac843ad7 | ||
|
3c0db7e3c3 | ||
|
7ef690bd5a | ||
|
16ef91c238 | ||
|
ee06542f1f | ||
|
caa61de540 | ||
|
55ea2a20e7 | ||
|
2097e3c836 | ||
|
84718101fe | ||
|
ecf3b30baf | ||
|
ceeea7712d | ||
|
9d2f874b02 | ||
|
92241fc0a4 | ||
|
869d75f53e | ||
|
a916050724 | ||
|
872367f068 | ||
|
cacd71c401 | ||
|
f4df9013bb | ||
|
3dc68bcb76 | ||
|
d0a7ee1692 | ||
|
60f461d94d | ||
|
f7e26acfb9 | ||
|
9baf5f403c | ||
|
44bb5d474b | ||
|
c2b4e81493 | ||
|
27d7939cc1 | ||
|
1ab0b5abd2 | ||
|
8a7f540d7c | ||
|
697ea8b3b3 | ||
|
1bd56a93f0 | ||
|
1bd84419c0 | ||
|
90c072b66c | ||
|
096eec1b84 | ||
|
9839e4aea7 | ||
|
1499da51b8 | ||
|
3e41052853 | ||
|
384646b03b | ||
|
471ed0ef65 | ||
|
8d418760c0 | ||
|
9ab2f35c08 | ||
|
a8c6c5f50e | ||
|
5454b3202d | ||
|
fd5ee53251 | ||
|
b46d8db565 | ||
|
4497201928 | ||
|
e0c3efee6c | ||
|
f45dc88bf8 | ||
|
4490f9cb41 | ||
|
13d9ed7e87 | ||
|
66edfaec42 | ||
|
e1554a13e0 | ||
|
9dfb1e98b9 | ||
|
97a6a3dde7 | ||
|
cc860fe56a | ||
|
201dcb6a8a | ||
|
5213c53bb0 | ||
|
9378718231 | ||
|
fe6b79082f | ||
|
34879d6dd3 | ||
|
defb91abc1 | ||
|
e6eb9899bb | ||
|
28a229c594 | ||
|
9f4d7fa5ad | ||
|
346d8a45c6 | ||
|
02d60a3dde | ||
|
d0b6869e9e | ||
|
20c4822c98 | ||
|
da1e92956f | ||
|
21721dd814 | ||
|
98a064efa9 | ||
|
5caeffa19a | ||
|
e8a9d228c5 | ||
|
2ac51fb597 | ||
|
7465b4ffaf | ||
|
8819ea745d | ||
|
2435a76caa | ||
|
9f682c6015 | ||
|
44ae59f363 | ||
|
04b921e200 | ||
|
290e546f47 | ||
|
0e6ba23800 | ||
|
429de331d6 | ||
|
796f09ef23 | ||
|
219da446f4 | ||
|
7cb82b9894 | ||
|
293c76625c | ||
|
05d00388ed | ||
|
39ee307409 | ||
|
d734aaa357 | ||
|
a34b058701 | ||
|
52e0cf38b7 | ||
|
dfcc5ae37e | ||
|
8740ea710a | ||
|
6721db8600 | ||
|
157bf05c50 | ||
|
2de14f4e38 | ||
|
616e7c2eec | ||
|
1769c2f457 | ||
|
0e47224578 | ||
|
be53a82e78 | ||
|
bc60621d61 | ||
|
8f8871454c | ||
|
1c1faeff2d | ||
|
d400183483 | ||
|
717605065a | ||
|
5b1f3f67c3 | ||
|
721cf57b28 | ||
|
9c5c082d83 | ||
|
684c34dc21 | ||
|
bbbe6ce894 | ||
|
fbd359099b | ||
|
315864e434 | ||
|
b676406878 | ||
|
aca0f3cad7 | ||
|
2d6bcff3a6 | ||
|
ae2a7c60b8 | ||
|
9b9a883d07 | ||
|
f6882e2a5d | ||
|
7792b95443 | ||
|
19960c0287 | ||
|
07a561176c | ||
|
82a0476ad5 | ||
|
86270dac6d | ||
|
8b9da2efba | ||
|
207605f93b | ||
|
650e1b9739 | ||
|
c3cf13fc64 | ||
|
87285cfcaa | ||
|
821f2f907b | ||
|
a68ef3c27b | ||
|
aa451b48bb | ||
|
39497ab77b | ||
|
a47a51453c | ||
|
fc303d9594 | ||
|
0b5b674e1f | ||
|
e793f927fc | ||
|
4795011b12 | ||
|
f971faab58 | ||
|
07995f0222 | ||
|
25899fef73 | ||
|
de2a9fd18f | ||
|
1109e3ce2d | ||
|
0b72fd8a97 | ||
|
00f7beee43 | ||
|
20905406da | ||
|
6ff9869120 | ||
|
0f0f2c6b9b | ||
|
3bb6f1bb68 | ||
|
3bea3b7725 | ||
|
758080e579 | ||
|
0f6002822c | ||
|
44d1502474 | ||
|
5a67246426 | ||
|
0d17d5eaaa | ||
|
f387929653 | ||
|
d8f4c8bc7e | ||
|
8a6e525ea9 | ||
|
b359936c04 | ||
|
8724400884 | ||
|
7bb59b6784 | ||
|
26bf9b60cd | ||
|
55da9d1084 | ||
|
d71754298c | ||
|
8fc0dcfd48 | ||
|
46ec677702 | ||
|
b687831394 | ||
|
5632021003 | ||
|
1478e74963 | ||
|
9a3a6ba3ef | ||
|
e8ff26e173 | ||
|
c168ff6c3c | ||
|
bd061d1d1b | ||
|
19f376a6c9 | ||
|
49f0ca5339 | ||
|
d46eebf794 | ||
|
5795bc5766 | ||
|
323778e96f | ||
|
48763ef836 | ||
|
504b9d215e | ||
|
ce39032bc5 | ||
|
88f0f6680b | ||
|
25ff997548 | ||
|
59092bef72 | ||
|
bec8973265 | ||
|
d4f6537b95 | ||
|
f1bfbb9821 | ||
|
45b9aff761 | ||
|
8b8ff9363d | ||
|
0c0e4f554f | ||
|
d67598f0fe | ||
|
0d8b2b6252 | ||
|
97cf0bd11f | ||
|
c783a48bae | ||
|
1950040461 | ||
|
5934f5da9a | ||
|
959f0de7e5 | ||
|
6080b8742a | ||
|
4afc0960fb | ||
|
d8849af800 | ||
|
e4ec798762 | ||
|
5b75954c5b | ||
|
692fcc225f | ||
|
11777e8136 | ||
|
ea4de3be36 | ||
|
64f2008cc1 | ||
|
e393ade59d | ||
|
0ffa0be4fd | ||
|
8e3d250654 | ||
|
fe51f02a25 | ||
|
aa85824455 | ||
|
799360dfb8 | ||
|
ea65b145c6 | ||
|
06b23cc293 | ||
|
5ec7565852 | ||
|
638fa1f06c | ||
|
cef49c2269 | ||
|
5f09d454be | ||
|
91ca0f2f89 | ||
|
04cf494d9c | ||
|
b11e66594d | ||
|
ad2c2efacd | ||
|
a9538799da | ||
|
c374440379 | ||
|
c6cc424991 | ||
|
6d04913b4a | ||
|
3d69c485be | ||
|
94407dbd1f | ||
|
fd1e60e2fd | ||
|
4b695cc3dd | ||
|
47180dbf7f | ||
|
1dfc926eb8 | ||
|
e26c34346b | ||
|
0d0e56dca3 | ||
|
12c8592325 | ||
|
ef21f5867e | ||
|
ba79deddf6 | ||
|
8f3b312b7c | ||
|
f7b810a3d1 | ||
|
be92ae787c | ||
|
50bb383667 | ||
|
844bc1e416 | ||
|
46e979e185 | ||
|
2716311f51 | ||
|
357b557684 | ||
|
e947aeb72d |
@ -37,7 +37,6 @@ Checks:
|
||||
'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: none
|
||||
CheckOptions:
|
||||
llvm-else-after-return.WarnOnConditionVariables: 'false'
|
||||
|
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@ -6,11 +6,14 @@ on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ windows-latest, macos-latest ]
|
||||
os: [ windows-latest, macos-15 ]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: true
|
||||
@ -27,9 +30,11 @@ jobs:
|
||||
- if: startsWith(matrix.os, 'macos')
|
||||
name: Install macos dependencies
|
||||
run: brew install pkg-config glfw meson
|
||||
- name: Trust git repo
|
||||
run: git config --global --add safe.directory '*'
|
||||
- name: Profiler GUI
|
||||
run: |
|
||||
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release
|
||||
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
|
||||
cmake --build profiler/build --parallel --config Release
|
||||
- name: Update utility
|
||||
run: |
|
||||
|
63
.github/workflows/emscripten.yml
vendored
Normal file
63
.github/workflows/emscripten.yml
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
name: emscripten
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container: archlinux:base-devel
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: pacman -Syu --noconfirm && pacman -S --noconfirm --needed cmake git unzip python ninja zstd
|
||||
- name: Setup emscripten
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: 3.1.67
|
||||
- name: Trust git repo
|
||||
run: git config --global --add safe.directory '*'
|
||||
- uses: actions/checkout@v4
|
||||
- name: Profiler GUI
|
||||
run: |
|
||||
cmake -G Ninja -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=MinSizeRel -DGIT_REV=${{ github.sha }} -DCMAKE_TOOLCHAIN_FILE=${{env.EMSDK}}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
|
||||
cmake --build profiler/build --parallel
|
||||
- name: Compress artifacts
|
||||
run: |
|
||||
zstd -18 profiler/build/tracy-profiler.js profiler/build/tracy-profiler.wasm
|
||||
gzip -9 profiler/build/tracy-profiler.js profiler/build/tracy-profiler.wasm
|
||||
- name: Find Artifacts
|
||||
id: find_artifacts
|
||||
run: |
|
||||
mkdir -p bin
|
||||
cp profiler/build/index.html bin
|
||||
cp profiler/build/favicon.svg bin
|
||||
cp profiler/build/tracy-profiler.data bin
|
||||
cp profiler/build/tracy-profiler.js.gz bin
|
||||
cp profiler/build/tracy-profiler.js.zst bin
|
||||
cp profiler/build/tracy-profiler.wasm.gz bin
|
||||
cp profiler/build/tracy-profiler.wasm.zst bin
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: emscripten
|
||||
path: bin
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: wlixcc/SFTP-Deploy-Action@v1.2.4
|
||||
with:
|
||||
username: ${{ secrets.USERNAME }}
|
||||
server: ${{ secrets.SERVER }}
|
||||
port: ${{ secrets.PORT }}
|
||||
ssh_private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
local_path: './emscripten/*'
|
||||
remote_path: ${{ secrets.REMOTE_PATH }}
|
||||
sftp_only: true
|
9
.github/workflows/linux.yml
vendored
9
.github/workflows/linux.yml
vendored
@ -6,17 +6,22 @@ on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container: archlinux:base-devel
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: pacman -Syu --noconfirm && pacman -S --noconfirm --needed freetype2 tbb debuginfod wayland dbus libxkbcommon libglvnd meson cmake git wayland-protocols nodejs
|
||||
run: pacman -Syu --noconfirm && pacman -S --noconfirm --needed freetype2 debuginfod wayland dbus libxkbcommon libglvnd meson cmake git wayland-protocols nodejs
|
||||
- name: Trust git repo
|
||||
run: git config --global --add safe.directory '*'
|
||||
- uses: actions/checkout@v4
|
||||
- name: Profiler GUI
|
||||
run: |
|
||||
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release
|
||||
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
|
||||
cmake --build profiler/build --parallel
|
||||
- name: Update utility
|
||||
run: |
|
||||
|
2
.mailmap
Normal file
2
.mailmap
Normal file
@ -0,0 +1,2 @@
|
||||
<wolf@nereid.pl> <wolf.pld@gmail.com>
|
||||
<wolf@nereid.pl> <bartosz.taudul@game-lion.com>
|
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@ -7,8 +7,7 @@
|
||||
"request": "launch",
|
||||
"program": "${command:cmake.launchTargetPath}",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"terminal": "console"
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -8,25 +8,45 @@ project(Tracy LANGUAGES CXX VERSION ${TRACY_VERSION_STRING})
|
||||
file(GENERATE OUTPUT .gitignore CONTENT "*")
|
||||
|
||||
if(${BUILD_SHARED_LIBS})
|
||||
set(DEFAULT_STATIC OFF)
|
||||
set(DEFAULT_STATIC OFF)
|
||||
else()
|
||||
set(DEFAULT_STATIC ON)
|
||||
set(DEFAULT_STATIC ON)
|
||||
endif()
|
||||
|
||||
option(TRACY_STATIC "Whether to build Tracy as a static library" ${DEFAULT_STATIC})
|
||||
option(TRACY_Fortran "Build Fortran bindings" OFF)
|
||||
option(TRACY_LTO "Enable Link-Time optimization" OFF)
|
||||
|
||||
if(TRACY_Fortran)
|
||||
enable_language(Fortran)
|
||||
set(CMAKE_Fortran_VERSION 2003)
|
||||
endif()
|
||||
|
||||
if(TRACY_LTO OR CMAKE_INTERPROCEDURAL_OPTIMIZATION)
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT LTO_SUPPORTED)
|
||||
if(NOT LTO_SUPPORTED)
|
||||
message(WARNING "LTO is not supported!")
|
||||
endif()
|
||||
else()
|
||||
set(LTO_SUPPORTED OFF)
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
set(TRACY_PUBLIC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/public)
|
||||
|
||||
if(TRACY_STATIC)
|
||||
set(TRACY_VISIBILITY "STATIC")
|
||||
if(LTO_SUPPORTED)
|
||||
set(TRACY_VISIBILITY "OBJECT")
|
||||
elseif(TRACY_STATIC)
|
||||
set(TRACY_VISIBILITY "STATIC")
|
||||
else()
|
||||
set(TRACY_VISIBILITY "SHARED")
|
||||
set(TRACY_VISIBILITY "SHARED")
|
||||
endif()
|
||||
|
||||
add_library(TracyClient ${TRACY_VISIBILITY} "${TRACY_PUBLIC_DIR}/TracyClient.cpp")
|
||||
target_compile_features(TracyClient PUBLIC cxx_std_11)
|
||||
set_target_properties(TracyClient PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${LTO_SUPPORTED})
|
||||
target_include_directories(TracyClient SYSTEM PUBLIC
|
||||
$<BUILD_INTERFACE:${TRACY_PUBLIC_DIR}>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
@ -37,6 +57,20 @@ target_link_libraries(
|
||||
${CMAKE_DL_LIBS}
|
||||
)
|
||||
|
||||
if(TRACY_Fortran)
|
||||
add_library(TracyClientF90 ${TRACY_VISIBILITY} "${TRACY_PUBLIC_DIR}/TracyClient.F90")
|
||||
target_include_directories(TracyClientF90 PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
target_link_libraries(
|
||||
TracyClientF90
|
||||
PUBLIC
|
||||
TracyClient
|
||||
)
|
||||
set_target_properties(TracyClientF90 PROPERTIES Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
INTERPROCEDURAL_OPTIMIZATION ${LTO_SUPPORTED})
|
||||
endif()
|
||||
|
||||
# Public dependency on some libraries required when using Mingw
|
||||
if(WIN32 AND ${CMAKE_CXX_COMPILER_ID} MATCHES "GNU|Clang")
|
||||
target_link_libraries(TracyClient PUBLIC ws2_32 dbghelp)
|
||||
@ -54,7 +88,17 @@ if(TRACY_LIBUNWIND_BACKTRACE)
|
||||
target_link_libraries(TracyClient INTERFACE ${unwind_LINK_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(TRACY_DEBUGINFOD)
|
||||
include(FindPkgConfig)
|
||||
pkg_check_modules(debuginfod REQUIRED libdebuginfod)
|
||||
target_include_directories(TracyClient INTERFACE ${debuginfod_INCLUDE_DIRS})
|
||||
target_link_libraries(TracyClient INTERFACE ${debuginfod_LINK_LIBRARIES})
|
||||
endif()
|
||||
|
||||
add_library(Tracy::TracyClient ALIAS TracyClient)
|
||||
if(TRACY_Fortran)
|
||||
add_library(Tracy::TracyClient_Fortran ALIAS TracyClientF90)
|
||||
endif()
|
||||
|
||||
macro(set_option option help value)
|
||||
option(${option} ${help} ${value})
|
||||
@ -91,6 +135,7 @@ set_option(TRACY_TIMER_FALLBACK "Use lower resolution timers" OFF)
|
||||
set_option(TRACY_LIBUNWIND_BACKTRACE "Use libunwind backtracing where supported" OFF)
|
||||
set_option(TRACY_SYMBOL_OFFLINE_RESOLVE "Instead of full runtime symbol resolution, only resolve the image path and offset to enable offline symbol resolution" OFF)
|
||||
set_option(TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT "Enable libbacktrace to support dynamically loaded elfs in symbol resolution resolution after the first symbol resolve operation" OFF)
|
||||
set_option(TRACY_DEBUGINFOD "Enable debuginfod support" OFF)
|
||||
|
||||
# advanced
|
||||
set_option(TRACY_VERBOSE "[advanced] Verbose output from the profiler" OFF)
|
||||
@ -98,6 +143,11 @@ mark_as_advanced(TRACY_VERBOSE)
|
||||
set_option(TRACY_DEMANGLE "[advanced] Don't use default demangling function - You'll need to provide your own" OFF)
|
||||
mark_as_advanced(TRACY_DEMANGLE)
|
||||
|
||||
# handle incompatible combinations
|
||||
if(TRACY_MANUAL_LIFETIME AND NOT TRACY_DELAYED_INIT)
|
||||
message(FATAL_ERROR "TRACY_MANUAL_LIFETIME can not be activated with disabled TRACY_DELAYED_INIT")
|
||||
endif()
|
||||
|
||||
if(NOT TRACY_STATIC)
|
||||
target_compile_definitions(TracyClient PRIVATE TRACY_EXPORTS)
|
||||
target_compile_definitions(TracyClient PUBLIC TRACY_IMPORTS)
|
||||
@ -107,6 +157,9 @@ include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set_target_properties(TracyClient PROPERTIES VERSION ${PROJECT_VERSION})
|
||||
if(TRACY_Fortran)
|
||||
set_target_properties(TracyClientF90 PROPERTIES VERSION ${PROJECT_VERSION})
|
||||
endif()
|
||||
|
||||
set(tracy_includes
|
||||
${TRACY_PUBLIC_DIR}/tracy/TracyC.h
|
||||
@ -163,26 +216,49 @@ install(TARGETS TracyClient
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
COMPONENT lib)
|
||||
if(TRACY_Fortran)
|
||||
install(TARGETS TracyClientF90
|
||||
EXPORT TracyConfig
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
COMPONENT lib)
|
||||
endif()
|
||||
# Export targets to build tree root
|
||||
export(TARGETS TracyClient
|
||||
NAMESPACE Tracy::
|
||||
FILE ${CMAKE_BINARY_DIR}/TracyTargets.cmake)
|
||||
if(TRACY_Fortran)
|
||||
export(TARGETS TracyClientF90
|
||||
NAMESPACE Tracy::
|
||||
APPEND
|
||||
FILE ${CMAKE_BINARY_DIR}/TracyTargets.cmake)
|
||||
endif()
|
||||
install(FILES ${tracy_includes}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy)
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy/tracy)
|
||||
install(FILES ${client_includes}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/client)
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy/client)
|
||||
install(FILES ${common_includes}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/common)
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy/common)
|
||||
if(TRACY_Fortran)
|
||||
if(${CMAKE_Fortran_COMPILER_ID} MATCHES "Cray")
|
||||
install(FILES ${PROJECT_BINARY_DIR}/TRACY.mod
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy)
|
||||
else()
|
||||
install(FILES ${PROJECT_BINARY_DIR}/tracy.mod
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy)
|
||||
endif()
|
||||
endif()
|
||||
install(EXPORT TracyConfig
|
||||
NAMESPACE Tracy::
|
||||
FILE TracyTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/Tracy)
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||
include(CMakePackageConfigHelpers)
|
||||
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/TracyConfig.cmake"
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/Tracy)
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TracyConfig.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/Tracy)
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||
|
||||
option(TRACY_CLIENT_PYTHON "Whether to build Tracy python client library" OFF)
|
||||
|
||||
|
2
LICENSE
2
LICENSE
@ -1,7 +1,7 @@
|
||||
Tracy Profiler (https://github.com/wolfpld/tracy) is licensed under the
|
||||
3-clause BSD license.
|
||||
|
||||
Copyright (c) 2017-2024, Bartosz Taudul <wolf@nereid.pl>
|
||||
Copyright (c) 2017-2025, Bartosz Taudul <wolf@nereid.pl>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
50
NEWS
50
NEWS
@ -2,6 +2,56 @@ Note: There is no guarantee that version mismatched client and server will
|
||||
be able to talk with each other. Network protocol breakages won't be listed
|
||||
here.
|
||||
|
||||
vx.xx.x (xxxx-xx-xx)
|
||||
--------------------
|
||||
|
||||
- Enabled workaround for MSVC runtime library SNAFU, which manifested with
|
||||
the profiler executables crashing at startup inside mutex code.
|
||||
- CPU topology data now includes CPU die information.
|
||||
- Clients running under Wine will now report that in the trace info.
|
||||
- Added flame graph.
|
||||
- The Git ref information for the build is now included in the about dialog.
|
||||
- Added support for clipboard copy and paste on Wayland.
|
||||
- The welcome dialog client address entry field will now trim the entered
|
||||
address, so that stray spaces at the start and the end are removed. This
|
||||
should reduce the amount of user precision required when copy pasting the
|
||||
address from somewhere else.
|
||||
- Metal GPU profiling is now available.
|
||||
- Profiling zones can now optionally inherit their parent color.
|
||||
- It is no longer needed to have up-to-date copy of wayland-protocols
|
||||
installed. CMake will download the required version from GitHub.
|
||||
- Added option to show the top inline in symbol statistics list in stead of
|
||||
the symbol name.
|
||||
- Parallel sorting is now performed with PPQSort (which removes potential
|
||||
dependency on TBB).
|
||||
- Added CMake option TRACY_DEBUGINFOD to enable use of libdebuginfod to
|
||||
retrieve symbols on Linux clients.
|
||||
- Added a "custom" label as an option to select for GPU context type.
|
||||
- Symbol code retrieval is now protected against reading no longer available
|
||||
memory.
|
||||
- Clicking on a symbol in the symbol statistics list will now open a popup
|
||||
with two options. This change intends to make the useful but quite hidden
|
||||
disassembly view more discoverable.
|
||||
- "View symbol" shows the symbol code disassembly. It was previously
|
||||
available by right-click on the source file name.
|
||||
- "Sample entry stacks" shows the list window that was previously
|
||||
opened when the symbol entry was clicked.
|
||||
- Plots are now extended to the end of the trace, instead of ending at the
|
||||
last data point.
|
||||
- Added TracyMemoryDiscard macros to mark that all allocations made in a
|
||||
certain memory pool were freed. This enables better support for arena
|
||||
allocators.
|
||||
- It is now possible to fine-tune horizontal and vertical mouse wheel scroll
|
||||
sensitivity.
|
||||
- Added p75 and p90 percentiles in the Find zone window.
|
||||
- Zone info window will now display (approximate) wall-clock time of when
|
||||
the zone appeared, in addition to the previously displayed time from the
|
||||
start of the program.
|
||||
- Zone values passed via ZoneValue macro will be now also displayed in hex.
|
||||
- The csvexport utility can now export plots.
|
||||
- Fortran integration is now available.
|
||||
|
||||
|
||||
v0.11.1 (2024-08-22)
|
||||
--------------------
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
### A real time, nanosecond resolution, remote telemetry, hybrid frame and sampling profiler for games and other applications.
|
||||
|
||||
Tracy supports profiling CPU (Direct support is provided for C, C++, Lua and Python integration. At the same time, third-party bindings to many other languages exist on the internet, such as [Rust](https://github.com/nagisa/rust_tracy_client), [Zig](https://github.com/nektro/zig-tracy), [C#](https://github.com/clibequilibrium/Tracy-CSharp), [OCaml](https://github.com/imandra-ai/ocaml-tracy), [Odin](https://github.com/oskarnp/odin-tracy), etc.), GPU (All major graphic APIs: OpenGL, Vulkan, Direct3D 11/12, OpenCL.), memory allocations, locks, context switches, automatically attribute screenshots to captured frames, and much more.
|
||||
Tracy supports profiling CPU (Direct support is provided for C, C++, Lua, Python and Fortran integration. At the same time, third-party bindings to many other languages exist on the internet, such as [Rust](https://github.com/nagisa/rust_tracy_client), [Zig](https://github.com/tealsnow/zig-tracy), [C#](https://github.com/clibequilibrium/Tracy-CSharp), [OCaml](https://github.com/imandra-ai/ocaml-tracy), [Odin](https://github.com/oskarnp/odin-tracy), etc.), GPU (All major graphic APIs: OpenGL, Vulkan, Direct3D 11/12, Metal, OpenCL.), memory allocations, locks, context switches, automatically attribute screenshots to captured frames, and much more.
|
||||
|
||||
- [Documentation](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf) for usage and build process instructions
|
||||
- [Releases](https://github.com/wolfpld/tracy/releases) containing the documentation (`tracy.pdf`) and compiled Windows x64 binaries (`Tracy-<version>.7z`) as assets
|
||||
|
@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
||||
option(NO_STATISTICS "Disable calculation of statistics" ON)
|
||||
option(NO_PARALLEL_STL "Disable parallel STL" OFF)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
|
||||
|
||||
@ -25,3 +24,5 @@ set(PROGRAM_FILES
|
||||
add_executable(${PROJECT_NAME} ${PROGRAM_FILES} ${COMMON_FILES} ${SERVER_FILES})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE TracyServer TracyGetOpt)
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
@ -154,7 +154,7 @@ set(CPM_DRY_RUN
|
||||
if(DEFINED ENV{CPM_SOURCE_CACHE})
|
||||
set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE})
|
||||
else()
|
||||
set(CPM_SOURCE_CACHE_DEFAULT OFF)
|
||||
set(CPM_SOURCE_CACHE_DEFAULT ${CMAKE_CURRENT_BINARY_DIR}/.cpm-cache)
|
||||
endif()
|
||||
|
||||
set(CPM_SOURCE_CACHE
|
||||
|
@ -3,19 +3,16 @@ if (NOT NO_ISA_EXTENSIONS)
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
|
||||
CHECK_CXX_COMPILER_FLAG("-mcpu=native" COMPILER_SUPPORTS_MCPU_NATIVE)
|
||||
if(COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=native")
|
||||
add_compile_options(-mcpu=native)
|
||||
endif()
|
||||
else()
|
||||
CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||
if(COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
|
||||
add_compile_options(-march=native)
|
||||
endif()
|
||||
endif()
|
||||
if(WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX2")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:AVX2")
|
||||
add_compile_options(/arch:AVX2)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -25,32 +22,41 @@ else()
|
||||
set(USE_WAYLAND OFF)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fexperimental-library>)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
||||
add_compile_options(/MP)
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always")
|
||||
endif()
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
add_compile_options(-pthread -DIMGUI_IMPL_OPENGL_ES2)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT EMSCRIPTEN)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
|
||||
endif()
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
add_compile_options(-pthread)
|
||||
add_link_options(-pthread)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT EMSCRIPTEN)
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
find_program(MOLD_LINKER mold)
|
||||
if(MOLD_LINKER)
|
||||
set(CMAKE_LINKER_TYPE "MOLD")
|
||||
endif()
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-eliminate-unused-debug-types")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-eliminate-unused-debug-types")
|
||||
add_compile_options(-fno-eliminate-unused-debug-types)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_program(CCACHE ccache)
|
||||
if(CCACHE)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
endif()
|
||||
|
||||
file(GENERATE OUTPUT .gitignore CONTENT "*")
|
||||
|
||||
set(CMAKE_COLOR_DIAGNOSTICS ON)
|
||||
|
12
cmake/gl3w-extra-symbols.patch
Normal file
12
cmake/gl3w-extra-symbols.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff --git a/extra_symbols.txt b/extra_symbols.txt
|
||||
index b95bb58..6b8f616 100644
|
||||
--- a/extra_symbols.txt
|
||||
+++ b/extra_symbols.txt
|
||||
@@ -1,3 +1,7 @@
|
||||
+glCompressedTexImage2D
|
||||
+GL_LINEAR_MIPMAP_LINEAR
|
||||
+GL_TEXTURE_WRAP_S
|
||||
+GL_TEXTURE_WRAP_T
|
||||
glReadPixels
|
||||
glClearColor
|
||||
glClear
|
14
cmake/imgui-emscripten.patch
Normal file
14
cmake/imgui-emscripten.patch
Normal file
@ -0,0 +1,14 @@
|
||||
diff '--color=auto' -ruN 72d8f61727dc878102157113d1998f86b852d20e/imconfig.h new/imconfig.h
|
||||
--- 72d8f61727dc878102157113d1998f86b852d20e/imconfig.h 2024-09-27 14:28:05.568760349 +0200
|
||||
+++ new/imconfig.h 2024-09-27 14:29:47.310243707 +0200
|
||||
@@ -113,6 +113,10 @@
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
//#define ImDrawIdx unsigned int
|
||||
|
||||
+#ifdef __EMSCRIPTEN__
|
||||
+#define ImDrawIdx unsigned int
|
||||
+#endif
|
||||
+
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
//struct ImDrawCmd;
|
56
cmake/imgui-loader.patch
Normal file
56
cmake/imgui-loader.patch
Normal file
@ -0,0 +1,56 @@
|
||||
diff --git a/backends/imgui_impl_opengl3_loader.h b/backends/imgui_impl_opengl3_loader.h
|
||||
index d6ffa5a2d..e48372c64 100644
|
||||
--- a/backends/imgui_impl_opengl3_loader.h
|
||||
+++ b/backends/imgui_impl_opengl3_loader.h
|
||||
@@ -179,6 +179,7 @@ typedef khronos_uint8_t GLubyte;
|
||||
#define GL_VERSION 0x1F02
|
||||
#define GL_EXTENSIONS 0x1F03
|
||||
#define GL_LINEAR 0x2601
|
||||
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
|
||||
#define GL_TEXTURE_MAG_FILTER 0x2800
|
||||
#define GL_TEXTURE_MIN_FILTER 0x2801
|
||||
#define GL_TEXTURE_WRAP_S 0x2802
|
||||
@@ -241,8 +242,10 @@ GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
|
||||
#define GL_TEXTURE0 0x84C0
|
||||
#define GL_ACTIVE_TEXTURE 0x84E0
|
||||
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
|
||||
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glActiveTexture (GLenum texture);
|
||||
+GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_3 */
|
||||
#ifndef GL_VERSION_1_4
|
||||
@@ -478,7 +481,7 @@ GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
|
||||
|
||||
/* gl3w internal state */
|
||||
union ImGL3WProcs {
|
||||
- GL3WglProc ptr[59];
|
||||
+ GL3WglProc ptr[60];
|
||||
struct {
|
||||
PFNGLACTIVETEXTUREPROC ActiveTexture;
|
||||
PFNGLATTACHSHADERPROC AttachShader;
|
||||
@@ -494,6 +497,7 @@ union ImGL3WProcs {
|
||||
PFNGLCLEARPROC Clear;
|
||||
PFNGLCLEARCOLORPROC ClearColor;
|
||||
PFNGLCOMPILESHADERPROC CompileShader;
|
||||
+ PFNGLCOMPRESSEDTEXIMAGE2DPROC CompressedTexImage2D;
|
||||
PFNGLCREATEPROGRAMPROC CreateProgram;
|
||||
PFNGLCREATESHADERPROC CreateShader;
|
||||
PFNGLDELETEBUFFERSPROC DeleteBuffers;
|
||||
@@ -559,6 +563,7 @@ GL3W_API extern union ImGL3WProcs imgl3wProcs;
|
||||
#define glClear imgl3wProcs.gl.Clear
|
||||
#define glClearColor imgl3wProcs.gl.ClearColor
|
||||
#define glCompileShader imgl3wProcs.gl.CompileShader
|
||||
+#define glCompressedTexImage2D imgl3wProcs.gl.CompressedTexImage2D
|
||||
#define glCreateProgram imgl3wProcs.gl.CreateProgram
|
||||
#define glCreateShader imgl3wProcs.gl.CreateShader
|
||||
#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
|
||||
@@ -854,6 +859,7 @@ static const char *proc_names[] = {
|
||||
"glClear",
|
||||
"glClearColor",
|
||||
"glCompileShader",
|
||||
+ "glCompressedTexImage2D",
|
||||
"glCreateProgram",
|
||||
"glCreateShader",
|
||||
"glDeleteBuffers",
|
@ -27,13 +27,9 @@ set(TRACY_SERVER_SOURCES
|
||||
list(TRANSFORM TRACY_SERVER_SOURCES PREPEND "${TRACY_SERVER_DIR}/")
|
||||
|
||||
|
||||
add_library(TracyServer STATIC ${TRACY_COMMON_SOURCES} ${TRACY_SERVER_SOURCES})
|
||||
add_library(TracyServer STATIC EXCLUDE_FROM_ALL ${TRACY_COMMON_SOURCES} ${TRACY_SERVER_SOURCES})
|
||||
target_include_directories(TracyServer PUBLIC ${TRACY_COMMON_DIR} ${TRACY_SERVER_DIR})
|
||||
target_link_libraries(TracyServer PUBLIC TracyCapstone TracyZstd)
|
||||
target_link_libraries(TracyServer PUBLIC TracyCapstone libzstd PPQSort::PPQSort)
|
||||
if(NO_STATISTICS)
|
||||
target_compile_definitions(TracyServer PUBLIC TRACY_NO_STATISTICS)
|
||||
endif()
|
||||
|
||||
if(NOT NO_PARALLEL_STL AND UNIX AND NOT APPLE AND NOT EMSCRIPTEN)
|
||||
target_link_libraries(TracyServer PRIVATE TracyTbb)
|
||||
endif()
|
||||
|
@ -24,7 +24,31 @@ else()
|
||||
CPMAddPackage(
|
||||
NAME capstone
|
||||
GITHUB_REPOSITORY capstone-engine/capstone
|
||||
GIT_TAG 5.0.3
|
||||
GIT_TAG 6.0.0-Alpha1
|
||||
OPTIONS
|
||||
"CAPSTONE_X86_ATT_DISABLE ON"
|
||||
"CAPSTONE_ALPHA_SUPPORT OFF"
|
||||
"CAPSTONE_HPPA_SUPPORT OFF"
|
||||
"CAPSTONE_LOONGARCH_SUPPORT OFF"
|
||||
"CAPSTONE_M680X_SUPPORT OFF"
|
||||
"CAPSTONE_M68K_SUPPORT OFF"
|
||||
"CAPSTONE_MIPS_SUPPORT OFF"
|
||||
"CAPSTONE_MOS65XX_SUPPORT OFF"
|
||||
"CAPSTONE_PPC_SUPPORT OFF"
|
||||
"CAPSTONE_SPARC_SUPPORT OFF"
|
||||
"CAPSTONE_SYSTEMZ_SUPPORT OFF"
|
||||
"CAPSTONE_XCORE_SUPPORT OFF"
|
||||
"CAPSTONE_TRICORE_SUPPORT OFF"
|
||||
"CAPSTONE_TMS320C64X_SUPPORT OFF"
|
||||
"CAPSTONE_M680X_SUPPORT OFF"
|
||||
"CAPSTONE_EVM_SUPPORT OFF"
|
||||
"CAPSTONE_WASM_SUPPORT OFF"
|
||||
"CAPSTONE_BPF_SUPPORT OFF"
|
||||
"CAPSTONE_RISCV_SUPPORT OFF"
|
||||
"CAPSTONE_SH_SUPPORT OFF"
|
||||
"CAPSTONE_XTENSA_SUPPORT OFF"
|
||||
"CAPSTONE_BUILD_MACOS_THIN ON"
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
add_library(TracyCapstone INTERFACE)
|
||||
target_include_directories(TracyCapstone INTERFACE ${capstone_SOURCE_DIR}/include/capstone)
|
||||
@ -49,6 +73,7 @@ if(NOT USE_WAYLAND AND NOT EMSCRIPTEN)
|
||||
"GLFW_BUILD_TESTS OFF"
|
||||
"GLFW_BUILD_DOCS OFF"
|
||||
"GLFW_INSTALL OFF"
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
add_library(TracyGlfw3 INTERFACE)
|
||||
target_link_libraries(TracyGlfw3 INTERFACE glfw)
|
||||
@ -66,60 +91,28 @@ else()
|
||||
CPMAddPackage(
|
||||
NAME freetype
|
||||
GITHUB_REPOSITORY freetype/freetype
|
||||
GIT_TAG VER-2-13-2
|
||||
GIT_TAG VER-2-13-3
|
||||
OPTIONS
|
||||
"FT_DISABLE_HARFBUZZ ON"
|
||||
"FT_WITH_HARFBUZZ OFF"
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
add_library(TracyFreetype INTERFACE)
|
||||
target_link_libraries(TracyFreetype INTERFACE freetype)
|
||||
endif()
|
||||
|
||||
# zstd
|
||||
# Zstd
|
||||
|
||||
set(ZSTD_DIR "${ROOT_DIR}/zstd")
|
||||
|
||||
set(ZSTD_SOURCES
|
||||
decompress/zstd_ddict.c
|
||||
decompress/zstd_decompress_block.c
|
||||
decompress/huf_decompress.c
|
||||
decompress/zstd_decompress.c
|
||||
common/zstd_common.c
|
||||
common/error_private.c
|
||||
common/xxhash.c
|
||||
common/entropy_common.c
|
||||
common/debug.c
|
||||
common/threading.c
|
||||
common/pool.c
|
||||
common/fse_decompress.c
|
||||
compress/zstd_ldm.c
|
||||
compress/zstd_compress_superblock.c
|
||||
compress/zstd_opt.c
|
||||
compress/zstd_compress_sequences.c
|
||||
compress/fse_compress.c
|
||||
compress/zstd_double_fast.c
|
||||
compress/zstd_compress.c
|
||||
compress/zstd_compress_literals.c
|
||||
compress/hist.c
|
||||
compress/zstdmt_compress.c
|
||||
compress/zstd_lazy.c
|
||||
compress/huf_compress.c
|
||||
compress/zstd_fast.c
|
||||
dictBuilder/zdict.c
|
||||
dictBuilder/cover.c
|
||||
dictBuilder/divsufsort.c
|
||||
dictBuilder/fastcover.c
|
||||
CPMAddPackage(
|
||||
NAME zstd
|
||||
GITHUB_REPOSITORY facebook/zstd
|
||||
GIT_TAG v1.5.7
|
||||
OPTIONS
|
||||
"ZSTD_BUILD_SHARED OFF"
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
SOURCE_SUBDIR build/cmake
|
||||
)
|
||||
|
||||
list(TRANSFORM ZSTD_SOURCES PREPEND "${ZSTD_DIR}/")
|
||||
|
||||
set_property(SOURCE ${ZSTD_DIR}/decompress/huf_decompress_amd64.S APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp")
|
||||
|
||||
add_library(TracyZstd STATIC ${ZSTD_SOURCES})
|
||||
target_include_directories(TracyZstd PUBLIC ${ZSTD_DIR})
|
||||
target_compile_definitions(TracyZstd PRIVATE ZSTD_DISABLE_ASM)
|
||||
|
||||
|
||||
# Diff Template Library
|
||||
|
||||
set(DTL_DIR "${ROOT_DIR}/dtl")
|
||||
@ -134,13 +127,21 @@ target_include_directories(TracyDtl INTERFACE ${DTL_DIR})
|
||||
set(GETOPT_DIR "${ROOT_DIR}/getopt")
|
||||
set(GETOPT_SOURCES ${GETOPT_DIR}/getopt.c)
|
||||
set(GETOPT_HEADERS ${GETOPT_DIR}/getopt.h)
|
||||
add_library(TracyGetOpt STATIC ${GETOPT_SOURCES} ${GETOPT_HEADERS})
|
||||
add_library(TracyGetOpt STATIC EXCLUDE_FROM_ALL ${GETOPT_SOURCES} ${GETOPT_HEADERS})
|
||||
target_include_directories(TracyGetOpt PUBLIC ${GETOPT_DIR})
|
||||
|
||||
|
||||
# ImGui
|
||||
|
||||
set(IMGUI_DIR "${ROOT_DIR}/imgui")
|
||||
CPMAddPackage(
|
||||
NAME ImGui
|
||||
GITHUB_REPOSITORY ocornut/imgui
|
||||
GIT_TAG v1.91.8-docking
|
||||
DOWNLOAD_ONLY TRUE
|
||||
PATCHES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/imgui-emscripten.patch"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/imgui-loader.patch"
|
||||
)
|
||||
|
||||
set(IMGUI_SOURCES
|
||||
imgui_widgets.cpp
|
||||
@ -149,15 +150,19 @@ set(IMGUI_SOURCES
|
||||
imgui.cpp
|
||||
imgui_tables.cpp
|
||||
misc/freetype/imgui_freetype.cpp
|
||||
backends/imgui_impl_opengl3.cpp
|
||||
)
|
||||
|
||||
list(TRANSFORM IMGUI_SOURCES PREPEND "${IMGUI_DIR}/")
|
||||
list(TRANSFORM IMGUI_SOURCES PREPEND "${ImGui_SOURCE_DIR}/")
|
||||
|
||||
add_definitions(-DIMGUI_ENABLE_FREETYPE)
|
||||
|
||||
add_library(TracyImGui STATIC ${IMGUI_SOURCES})
|
||||
target_include_directories(TracyImGui PUBLIC ${IMGUI_DIR})
|
||||
add_library(TracyImGui STATIC EXCLUDE_FROM_ALL ${IMGUI_SOURCES})
|
||||
target_include_directories(TracyImGui PUBLIC ${ImGui_SOURCE_DIR})
|
||||
target_link_libraries(TracyImGui PUBLIC TracyFreetype)
|
||||
target_compile_definitions(TracyImGui PRIVATE "IMGUI_ENABLE_FREETYPE")
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_definitions(TracyImGui PRIVATE "IMGUI_DISABLE_DEBUG_TOOLS")
|
||||
endif()
|
||||
|
||||
# NFD
|
||||
|
||||
@ -177,7 +182,7 @@ if (NOT NO_FILESELECTOR AND NOT EMSCRIPTEN)
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE NFD_HEADERS CONFIGURE_DEPENDS RELATIVE ${NFD_DIR} "*.h")
|
||||
add_library(TracyNfd STATIC ${NFD_SOURCES} ${NFD_HEADERS})
|
||||
add_library(TracyNfd STATIC EXCLUDE_FROM_ALL ${NFD_SOURCES} ${NFD_HEADERS})
|
||||
target_include_directories(TracyNfd PUBLIC ${NFD_DIR})
|
||||
|
||||
if (APPLE)
|
||||
@ -188,7 +193,7 @@ if (NOT NO_FILESELECTOR AND NOT EMSCRIPTEN)
|
||||
if (GTK_FILESELECTOR)
|
||||
pkg_check_modules(GTK3 gtk+-3.0)
|
||||
if (NOT GTK3_FOUND)
|
||||
message(FATAL_ERROR "GTK3 not found. Please install it or set TRACY_GTK_FILESELECTOR to OFF.")
|
||||
message(FATAL_ERROR "GTK3 not found. Please install it or set GTK_FILESELECTOR to OFF.")
|
||||
endif()
|
||||
add_library(TracyGtk3 INTERFACE)
|
||||
target_include_directories(TracyGtk3 INTERFACE ${GTK3_INCLUDE_DIRS})
|
||||
@ -197,7 +202,7 @@ if (NOT NO_FILESELECTOR AND NOT EMSCRIPTEN)
|
||||
else()
|
||||
pkg_check_modules(DBUS dbus-1)
|
||||
if (NOT DBUS_FOUND)
|
||||
message(FATAL_ERROR "D-Bus not found. Please install it or set TRACY_GTK_FILESELECTOR to ON.")
|
||||
message(FATAL_ERROR "D-Bus not found. Please install it or set GTK_FILESELECTOR to ON.")
|
||||
endif()
|
||||
add_library(TracyDbus INTERFACE)
|
||||
target_include_directories(TracyDbus INTERFACE ${DBUS_INCLUDE_DIRS})
|
||||
@ -207,32 +212,11 @@ if (NOT NO_FILESELECTOR AND NOT EMSCRIPTEN)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# TBB
|
||||
if (NO_PARALLEL_STL)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_PARALLEL_SORT")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_PARALLEL_SORT")
|
||||
else()
|
||||
if (UNIX AND NOT APPLE AND NOT EMSCRIPTEN)
|
||||
# Tracy does not use TBB directly, but the implementation of parallel algorithms
|
||||
# in some versions of libstdc++ depends on TBB. When it does, you must
|
||||
# explicitly link against -ltbb.
|
||||
#
|
||||
# Some distributions have pgk-config files for TBB, others don't.
|
||||
# PPQSort
|
||||
|
||||
pkg_check_modules(TBB tbb)
|
||||
if (TBB_FOUND)
|
||||
add_library(TracyTbb INTERFACE)
|
||||
target_include_directories(TracyTbb INTERFACE ${TBB_INCLUDE_DIRS})
|
||||
target_link_libraries(TracyTbb INTERFACE ${TBB_LINK_LIBRARIES})
|
||||
else()
|
||||
CPMAddPackage(
|
||||
NAME tbb
|
||||
GITHUB_REPOSITORY oneapi-src/oneTBB
|
||||
GIT_TAG v2021.12.0-rc2
|
||||
OPTIONS "TBB_TEST OFF"
|
||||
)
|
||||
add_library(TracyTbb INTERFACE)
|
||||
target_link_libraries(TracyTbb INTERFACE tbb)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
CPMAddPackage(
|
||||
NAME PPQSort
|
||||
GITHUB_REPOSITORY GabTux/PPQSort
|
||||
VERSION 1.0.5
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
|
@ -1,7 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
||||
option(NO_PARALLEL_STL "Disable parallel STL" OFF)
|
||||
|
||||
set(NO_STATISTICS OFF)
|
||||
|
||||
@ -26,3 +25,5 @@ set(PROGRAM_FILES
|
||||
add_executable(${PROJECT_NAME} ${PROGRAM_FILES} ${COMMON_FILES} ${SERVER_FILES})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE TracyServer TracyGetOpt)
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
@ -28,8 +28,10 @@ void print_usage_exit(int e)
|
||||
fprintf(stderr, " -s, --sep arg CSV separator (default: ,)\n");
|
||||
fprintf(stderr, " -c, --case Case sensitive filtering\n");
|
||||
fprintf(stderr, " -e, --self Get self times\n");
|
||||
fprintf(stderr, " -u, --unwrap Report each zone event\n");
|
||||
fprintf(stderr, " -u, --unwrap Report each cpu zone event\n");
|
||||
fprintf(stderr, " -g, --gpu Report each gpu zone event\n" );
|
||||
fprintf(stderr, " -m, --messages Report only messages\n");
|
||||
fprintf(stderr, " -p, --plot Report plot data (only with -u)\n");
|
||||
|
||||
exit(e);
|
||||
}
|
||||
@ -41,7 +43,9 @@ struct Args {
|
||||
bool case_sensitive;
|
||||
bool self_time;
|
||||
bool unwrap;
|
||||
bool show_gpu;
|
||||
bool unwrapMessages;
|
||||
bool plot;
|
||||
};
|
||||
|
||||
Args parse_args(int argc, char** argv)
|
||||
@ -51,7 +55,7 @@ Args parse_args(int argc, char** argv)
|
||||
print_usage_exit(1);
|
||||
}
|
||||
|
||||
Args args = { "", ",", "", false, false, false, false };
|
||||
Args args = { "", ",", "", false, false, false, false, false, false };
|
||||
|
||||
struct option long_opts[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
@ -60,12 +64,14 @@ Args parse_args(int argc, char** argv)
|
||||
{ "case", no_argument, NULL, 'c' },
|
||||
{ "self", no_argument, NULL, 'e' },
|
||||
{ "unwrap", no_argument, NULL, 'u' },
|
||||
{ "gpu", no_argument, NULL, 'g' },
|
||||
{ "messages", no_argument, NULL, 'm' },
|
||||
{ "plot", no_argument, NULL, 'p' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "hf:s:ceum", long_opts, NULL)) != -1)
|
||||
while ((c = getopt_long(argc, argv, "hf:s:ceugmp", long_opts, NULL)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@ -87,9 +93,15 @@ Args parse_args(int argc, char** argv)
|
||||
case 'u':
|
||||
args.unwrap = true;
|
||||
break;
|
||||
case 'g':
|
||||
args.show_gpu = true;
|
||||
break;
|
||||
case 'm':
|
||||
args.unwrapMessages = true;
|
||||
break;
|
||||
case 'p':
|
||||
args.plot = true;
|
||||
break;
|
||||
default:
|
||||
print_usage_exit(1);
|
||||
break;
|
||||
@ -241,6 +253,68 @@ int main(int argc, char** argv)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
if (args.show_gpu)
|
||||
{
|
||||
auto& gpu_slz = worker.GetGpuSourceLocationZones();
|
||||
tracy::Vector<decltype( gpu_slz.begin() )> gpu_slz_selected;
|
||||
gpu_slz_selected.reserve( gpu_slz.size() );
|
||||
|
||||
uint32_t total_cnt = 0;
|
||||
for (auto it = gpu_slz.begin(); it != gpu_slz.end(); ++it)
|
||||
{
|
||||
if (it->second.total != 0)
|
||||
{
|
||||
++total_cnt;
|
||||
if (args.filter[0] == '\0')
|
||||
{
|
||||
gpu_slz_selected.push_back_no_space_check( it );
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = get_name( it->first, worker );
|
||||
if (is_substring( args.filter, name, args.case_sensitive))
|
||||
{
|
||||
gpu_slz_selected.push_back_no_space_check( it );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const char*> columns;
|
||||
columns = {"name", "src_file", "Time from start of program", "GPU execution time"};
|
||||
|
||||
std::string header = join(columns, args.separator);
|
||||
printf("%s\n", header.data());
|
||||
|
||||
const auto last_time = worker.GetLastTime();
|
||||
for (auto& it : gpu_slz_selected)
|
||||
{
|
||||
std::vector<std::string> values( columns.size() );
|
||||
|
||||
values[0] = get_name( it->first, worker );
|
||||
|
||||
const auto& srcloc = worker.GetSourceLocation( it->first );
|
||||
values[1] = worker.GetString( srcloc.file );
|
||||
|
||||
const auto& zone_data = it->second;
|
||||
for (const auto& zone_thread_data : zone_data.zones)
|
||||
{
|
||||
tracy::GpuEvent* gpu_event = zone_thread_data.Zone();
|
||||
const auto start = gpu_event->GpuStart();
|
||||
const auto end = gpu_event->GpuEnd();
|
||||
|
||||
values[2] = std::to_string( start );
|
||||
|
||||
auto timespan = end - start;
|
||||
values[3] = std::to_string( timespan );
|
||||
|
||||
std::string row = join( values, args.separator );
|
||||
printf( "%s\n", row.data() );
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto& slz = worker.GetSourceLocationZones();
|
||||
tracy::Vector<decltype(slz.begin())> slz_selected;
|
||||
slz_selected.reserve(slz.size());
|
||||
@ -270,7 +344,7 @@ int main(int argc, char** argv)
|
||||
if (args.unwrap)
|
||||
{
|
||||
columns = {
|
||||
"name", "src_file", "src_line", "ns_since_start", "exec_time_ns", "thread"
|
||||
"name", "src_file", "src_line", "ns_since_start", "exec_time_ns", "thread", "value"
|
||||
};
|
||||
}
|
||||
else
|
||||
@ -313,6 +387,12 @@ int main(int argc, char** argv)
|
||||
}
|
||||
values[4] = std::to_string(timespan);
|
||||
values[5] = std::to_string(tId);
|
||||
if (worker.HasZoneExtra(*zone_event)) {
|
||||
const auto& text = worker.GetZoneExtra(*zone_event).text;
|
||||
if (text.Active()) {
|
||||
values[6] = worker.GetString(text);
|
||||
}
|
||||
}
|
||||
|
||||
std::string row = join(values, args.separator);
|
||||
printf("%s\n", row.data());
|
||||
@ -349,5 +429,26 @@ int main(int argc, char** argv)
|
||||
}
|
||||
}
|
||||
|
||||
if(args.plot && args.unwrap)
|
||||
{
|
||||
auto& plots = worker.GetPlots();
|
||||
for(const auto& plot : plots)
|
||||
{
|
||||
std::vector<std::string> values(columns.size());
|
||||
values[0] = worker.GetString(plot->name);
|
||||
|
||||
for(const auto& val : plot->data)
|
||||
{
|
||||
if (args.unwrap)
|
||||
{
|
||||
values[3] = std::to_string(val.time.Val());
|
||||
values[6] = std::to_string(val.val);
|
||||
}
|
||||
std::string row = join(values, args.separator);
|
||||
printf("%s\n", row.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include <math.h>
|
||||
|
||||
#include <CL/cl.h>
|
||||
|
||||
|
30
extra/git-ref.py
Normal file
30
extra/git-ref.py
Normal file
@ -0,0 +1,30 @@
|
||||
#!/bin/env python3
|
||||
|
||||
import filecmp
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
|
||||
out = "GitRef.hpp"
|
||||
tmp = f"{out}.tmp"
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
rev = sys.argv[1]
|
||||
else:
|
||||
rev = "HEAD"
|
||||
|
||||
try:
|
||||
ref = subprocess.run(["git", "rev-parse", "--short", rev], check=True, capture_output=True).stdout.decode().strip()
|
||||
except subprocess.CalledProcessError:
|
||||
ref = "unknown"
|
||||
|
||||
if not os.path.exists(out):
|
||||
with open(out, "w") as f:
|
||||
print(f"#pragma once\n\nnamespace tracy {{ static inline const char* GitRef = \"{ref}\"; }}", file=f)
|
||||
else:
|
||||
with open(tmp, "w") as f:
|
||||
print(f"#pragma once\n\nnamespace tracy {{ static inline const char* GitRef = \"{ref}\"; }}", file=f)
|
||||
if not filecmp.cmp(out, tmp, shallow=False):
|
||||
os.replace(tmp, out)
|
||||
else:
|
||||
os.unlink(tmp)
|
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2024 Omar Cornut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
135
imgui/imconfig.h
135
imgui/imconfig.h
@ -1,135 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// DEAR IMGUI COMPILE-TIME OPTIONS
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||
//-----------------------------------------------------------------------------
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS.
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//#define IMGUI_USE_WCHAR32
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
|
||||
|
||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||
//#define IMGUI_USE_STB_SPRINTF
|
||||
|
||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
|
||||
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
|
||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
//---- ...Or use Dear ImGui's own very basic math operators.
|
||||
//#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
//#define ImDrawIdx unsigned int
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#define ImDrawIdx unsigned int
|
||||
#endif
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
//struct ImDrawCmd;
|
||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||
//#define ImDrawCallback MyImDrawCallback
|
||||
|
||||
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
|
||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
//#define IM_DEBUG_BREAK __debugbreak()
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||
}
|
||||
*/
|
21850
imgui/imgui.cpp
21850
imgui/imgui.cpp
File diff suppressed because it is too large
Load Diff
3643
imgui/imgui.h
3643
imgui/imgui.h
File diff suppressed because it is too large
Load Diff
9050
imgui/imgui_demo.cpp
9050
imgui/imgui_demo.cpp
File diff suppressed because it is too large
Load Diff
4649
imgui/imgui_draw.cpp
4649
imgui/imgui_draw.cpp
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,627 +0,0 @@
|
||||
// [DEAR IMGUI]
|
||||
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
//
|
||||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Before #including,
|
||||
//
|
||||
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||
//
|
||||
// in the file that you want to have the implementation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Credits
|
||||
//
|
||||
// Library
|
||||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||
// 0.99 (2019-02-07) warning fixes
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
// 0.09 (2016-08-27) fix compiler warnings
|
||||
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
typedef int stbrp_coord;
|
||||
|
||||
#define STBRP__MAXVAL 0x7fffffff
|
||||
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
//
|
||||
// The function returns 1 if all of the rectangles were successfully
|
||||
// packed and 0 otherwise.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#ifndef STBRP_SORT
|
||||
#include <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
context->extra[1].y = (1<<30);
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
|
||||
STBRP__NOTUSED(c);
|
||||
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
// if it can't possibly fit, bail immediately
|
||||
if (width > c->width || height > c->height) {
|
||||
fr.prev_link = NULL;
|
||||
fr.x = fr.y = 0;
|
||||
return fr;
|
||||
}
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height <= c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags and all_rects_packed status
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
if (!rects[i].was_packed)
|
||||
all_rects_packed = 0;
|
||||
}
|
||||
|
||||
// return the all_rects_packed status
|
||||
return all_rects_packed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,44 +0,0 @@
|
||||
# imgui_freetype
|
||||
|
||||
Build font atlases using FreeType instead of stb_truetype (which is the default font rasterizer).
|
||||
<br>by @vuhdo, @mikesart, @ocornut.
|
||||
|
||||
### Usage
|
||||
|
||||
1. Get latest FreeType binaries or build yourself (under Windows you may use vcpkg with `vcpkg install freetype --triplet=x64-windows`, `vcpkg integrate install`).
|
||||
2. Add imgui_freetype.h/cpp alongside your project files.
|
||||
3. Add `#define IMGUI_ENABLE_FREETYPE` in your [imconfig.h](https://github.com/ocornut/imgui/blob/master/imconfig.h) file
|
||||
|
||||
### About Gamma Correct Blending
|
||||
|
||||
FreeType assumes blending in linear space rather than gamma space.
|
||||
See FreeType note for [FT_Render_Glyph](https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_render_glyph).
|
||||
For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
|
||||
The default Dear ImGui styles will be impacted by this change (alpha values will need tweaking).
|
||||
|
||||
### Testbed for toying with settings (for developers)
|
||||
|
||||
See https://gist.github.com/ocornut/b3a9ecf13502fd818799a452969649ad
|
||||
|
||||
### Known issues
|
||||
|
||||
- Oversampling settings are ignored but also not so much necessary with the higher quality rendering.
|
||||
|
||||
### Comparison
|
||||
|
||||
Small, thin anti-aliased fonts typically benefit a lot from FreeType's hinting:
|
||||

|
||||
|
||||
### Colorful glyphs/emojis
|
||||
|
||||
You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain colorful glyphs. See the
|
||||
["Using Colorful Glyphs/Emojis"](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md#using-colorful-glyphsemojis) section of FONTS.md.
|
||||
|
||||

|
||||
|
||||
### Using OpenType SVG fonts (SVGinOT)
|
||||
- *SVG in Open Type* is a standard by Adobe and Mozilla for color OpenType and Open Font Format fonts. It allows font creators to embed complete SVG files within a font enabling full color and even animations.
|
||||
- Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT
|
||||
- Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above
|
||||
1. Add `#define IMGUI_ENABLE_FREETYPE_LUNASVG` in your `imconfig.h`.
|
||||
2. Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`.
|
@ -1,950 +0,0 @@
|
||||
// dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder)
|
||||
// (code)
|
||||
|
||||
// Get the latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
||||
// Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained since 2019 by @ocornut.
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics.
|
||||
// 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG' (#6591)
|
||||
// 2023/01/04: fixed a packing issue which in some occurrences would prevent large amount of glyphs from being packed correctly.
|
||||
// 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL.
|
||||
// 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs.
|
||||
// 2021/03/02: set 'atlas->TexPixelsUseColors = true' to help some backends with deciding of a preferred texture format.
|
||||
// 2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+).
|
||||
// 2021/01/26: simplified integration by using '#define IMGUI_ENABLE_FREETYPE'. renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. removed ImGuiFreeType::BuildFontAtlas().
|
||||
// 2020/06/04: fix for rare case where FT_Get_Char_Index() succeed but FT_Load_Glyph() fails.
|
||||
// 2019/02/09: added RasterizerFlags::Monochrome flag to disable font anti-aliasing (combine with ::MonoHinting for best results!)
|
||||
// 2019/01/15: added support for imgui allocators + added FreeType only override function SetAllocatorFunctions().
|
||||
// 2019/01/10: re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding.
|
||||
// 2018/06/08: added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX.
|
||||
// 2018/02/04: moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club)
|
||||
// 2018/01/22: fix for addition of ImFontAtlas::TexUvscale member.
|
||||
// 2017/10/22: minor inconsequential change to match change in master (removed an unnecessary statement).
|
||||
// 2017/09/26: fixes for imgui internal changes.
|
||||
// 2017/08/26: cleanup, optimizations, support for ImFontConfig::RasterizerFlags, ImFontConfig::RasterizerMultiply.
|
||||
// 2017/08/16: imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks.
|
||||
|
||||
// About Gamma Correct Blending:
|
||||
// - FreeType assumes blending in linear space rather than gamma space.
|
||||
// - See https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Render_Glyph
|
||||
// - For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
|
||||
// - The default dear imgui styles will be impacted by this change (alpha values will need tweaking).
|
||||
|
||||
// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer).
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui_freetype.h"
|
||||
#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*,
|
||||
#include <stdint.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H // <freetype/freetype.h>
|
||||
#include FT_MODULE_H // <freetype/ftmodapi.h>
|
||||
#include FT_GLYPH_H // <freetype/ftglyph.h>
|
||||
#include FT_SYNTHESIS_H // <freetype/ftsynth.h>
|
||||
|
||||
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
#include FT_OTSVG_H // <freetype/otsvg.h>
|
||||
#include FT_BBOX_H // <freetype/ftbbox.h>
|
||||
#include <lunasvg.h>
|
||||
#if !((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12))
|
||||
#error IMGUI_ENABLE_FREETYPE_LUNASVG requires FreeType version >= 2.12
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||
#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
||||
#ifndef __clang__
|
||||
#pragma GCC diagnostic ignored "-Wsubobject-linkage" // warning: 'xxxx' has a field 'xxxx' whose type uses the anonymous namespace
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Data
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// Default memory allocators
|
||||
static void* ImGuiFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return IM_ALLOC(size); }
|
||||
static void ImGuiFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_FREE(ptr); }
|
||||
|
||||
// Current memory allocators
|
||||
static void* (*GImGuiFreeTypeAllocFunc)(size_t size, void* user_data) = ImGuiFreeTypeDefaultAllocFunc;
|
||||
static void (*GImGuiFreeTypeFreeFunc)(void* ptr, void* user_data) = ImGuiFreeTypeDefaultFreeFunc;
|
||||
static void* GImGuiFreeTypeAllocatorUserData = nullptr;
|
||||
|
||||
// Lunasvg support
|
||||
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
static FT_Error ImGuiLunasvgPortInit(FT_Pointer* state);
|
||||
static void ImGuiLunasvgPortFree(FT_Pointer* state);
|
||||
static FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state);
|
||||
static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state);
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Code
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
// Glyph metrics:
|
||||
// --------------
|
||||
//
|
||||
// xmin xmax
|
||||
// | |
|
||||
// |<-------- width -------->|
|
||||
// | |
|
||||
// | +-------------------------+----------------- ymax
|
||||
// | | ggggggggg ggggg | ^ ^
|
||||
// | | g:::::::::ggg::::g | | |
|
||||
// | | g:::::::::::::::::g | | |
|
||||
// | | g::::::ggggg::::::gg | | |
|
||||
// | | g:::::g g:::::g | | |
|
||||
// offsetX -|-------->| g:::::g g:::::g | offsetY |
|
||||
// | | g:::::g g:::::g | | |
|
||||
// | | g::::::g g:::::g | | |
|
||||
// | | g:::::::ggggg:::::g | | |
|
||||
// | | g::::::::::::::::g | | height
|
||||
// | | gg::::::::::::::g | | |
|
||||
// baseline ---*---------|---- gggggggg::::::g-----*-------- |
|
||||
// / | | g:::::g | |
|
||||
// origin | | gggggg g:::::g | |
|
||||
// | | g:::::gg gg:::::g | |
|
||||
// | | g::::::ggg:::::::g | |
|
||||
// | | gg:::::::::::::g | |
|
||||
// | | ggg::::::ggg | |
|
||||
// | | gggggg | v
|
||||
// | +-------------------------+----------------- ymin
|
||||
// | |
|
||||
// |------------- advanceX ----------->|
|
||||
|
||||
// A structure that describe a glyph.
|
||||
struct GlyphInfo
|
||||
{
|
||||
int Width; // Glyph's width in pixels.
|
||||
int Height; // Glyph's height in pixels.
|
||||
FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
|
||||
FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
|
||||
float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
|
||||
bool IsColored; // The glyph is colored
|
||||
};
|
||||
|
||||
// Font parameters and metrics.
|
||||
struct FontInfo
|
||||
{
|
||||
uint32_t PixelHeight; // Size this font was generated with.
|
||||
float Ascender; // The pixel extents above the baseline in pixels (typically positive).
|
||||
float Descender; // The extents below the baseline in pixels (typically negative).
|
||||
float LineSpacing; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate.
|
||||
float LineGap; // The spacing in pixels between one row's descent and the next row's ascent.
|
||||
float MaxAdvanceWidth; // This field gives the maximum horizontal cursor advance for all glyphs in the font.
|
||||
};
|
||||
|
||||
// FreeType glyph rasterizer.
|
||||
// NB: No ctor/dtor, explicitly call Init()/Shutdown()
|
||||
struct FreeTypeFont
|
||||
{
|
||||
bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
|
||||
void CloseFont();
|
||||
void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
|
||||
const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);
|
||||
const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info);
|
||||
void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = nullptr);
|
||||
~FreeTypeFont() { CloseFont(); }
|
||||
|
||||
// [Internals]
|
||||
FontInfo Info; // Font descriptor of the current font.
|
||||
FT_Face Face;
|
||||
unsigned int UserFlags; // = ImFontConfig::RasterizerFlags
|
||||
FT_Int32 LoadFlags;
|
||||
FT_Render_Mode RenderMode;
|
||||
float RasterizationDensity;
|
||||
float InvRasterizationDensity;
|
||||
};
|
||||
|
||||
// From SDL_ttf: Handy routines for converting from fixed point
|
||||
#define FT_CEIL(X) (((X + 63) & -64) / 64)
|
||||
|
||||
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_font_builder_flags)
|
||||
{
|
||||
FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face);
|
||||
if (error != 0)
|
||||
return false;
|
||||
error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE);
|
||||
if (error != 0)
|
||||
return false;
|
||||
|
||||
// Convert to FreeType flags (NB: Bold and Oblique are processed separately)
|
||||
UserFlags = cfg.FontBuilderFlags | extra_font_builder_flags;
|
||||
|
||||
LoadFlags = 0;
|
||||
if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0)
|
||||
LoadFlags |= FT_LOAD_NO_BITMAP;
|
||||
|
||||
if (UserFlags & ImGuiFreeTypeBuilderFlags_NoHinting)
|
||||
LoadFlags |= FT_LOAD_NO_HINTING;
|
||||
if (UserFlags & ImGuiFreeTypeBuilderFlags_NoAutoHint)
|
||||
LoadFlags |= FT_LOAD_NO_AUTOHINT;
|
||||
if (UserFlags & ImGuiFreeTypeBuilderFlags_ForceAutoHint)
|
||||
LoadFlags |= FT_LOAD_FORCE_AUTOHINT;
|
||||
if (UserFlags & ImGuiFreeTypeBuilderFlags_LightHinting)
|
||||
LoadFlags |= FT_LOAD_TARGET_LIGHT;
|
||||
else if (UserFlags & ImGuiFreeTypeBuilderFlags_MonoHinting)
|
||||
LoadFlags |= FT_LOAD_TARGET_MONO;
|
||||
else
|
||||
LoadFlags |= FT_LOAD_TARGET_NORMAL;
|
||||
|
||||
if (UserFlags & ImGuiFreeTypeBuilderFlags_Monochrome)
|
||||
RenderMode = FT_RENDER_MODE_MONO;
|
||||
else
|
||||
RenderMode = FT_RENDER_MODE_NORMAL;
|
||||
|
||||
if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor)
|
||||
LoadFlags |= FT_LOAD_COLOR;
|
||||
|
||||
RasterizationDensity = cfg.RasterizerDensity;
|
||||
InvRasterizationDensity = 1.0f / RasterizationDensity;
|
||||
|
||||
memset(&Info, 0, sizeof(Info));
|
||||
SetPixelHeight((uint32_t)cfg.SizePixels);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FreeTypeFont::CloseFont()
|
||||
{
|
||||
if (Face)
|
||||
{
|
||||
FT_Done_Face(Face);
|
||||
Face = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void FreeTypeFont::SetPixelHeight(int pixel_height)
|
||||
{
|
||||
// Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height'
|
||||
// is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me.
|
||||
// NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result.
|
||||
FT_Size_RequestRec req;
|
||||
req.type = (UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
||||
req.width = 0;
|
||||
req.height = (uint32_t)(pixel_height * 64 * RasterizationDensity);
|
||||
req.horiResolution = 0;
|
||||
req.vertResolution = 0;
|
||||
FT_Request_Size(Face, &req);
|
||||
|
||||
// Update font info
|
||||
FT_Size_Metrics metrics = Face->size->metrics;
|
||||
Info.PixelHeight = (uint32_t)(pixel_height * InvRasterizationDensity);
|
||||
Info.Ascender = (float)FT_CEIL(metrics.ascender) * InvRasterizationDensity;
|
||||
Info.Descender = (float)FT_CEIL(metrics.descender) * InvRasterizationDensity;
|
||||
Info.LineSpacing = (float)FT_CEIL(metrics.height) * InvRasterizationDensity;
|
||||
Info.LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * InvRasterizationDensity;
|
||||
Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * InvRasterizationDensity;
|
||||
}
|
||||
|
||||
const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint)
|
||||
{
|
||||
uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint);
|
||||
if (glyph_index == 0)
|
||||
return nullptr;
|
||||
|
||||
// If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts.
|
||||
// - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076
|
||||
// - https://github.com/ocornut/imgui/issues/4567
|
||||
// - https://github.com/ocornut/imgui/issues/4566
|
||||
// You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version.
|
||||
FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags);
|
||||
if (error)
|
||||
return nullptr;
|
||||
|
||||
// Need an outline for this to work
|
||||
FT_GlyphSlot slot = Face->glyph;
|
||||
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP || slot->format == FT_GLYPH_FORMAT_SVG);
|
||||
#else
|
||||
#if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12))
|
||||
IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_LUNASVG in imconfig.h and install required libraries in order to use this font");
|
||||
#endif
|
||||
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP);
|
||||
#endif // IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
|
||||
// Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting)
|
||||
if (UserFlags & ImGuiFreeTypeBuilderFlags_Bold)
|
||||
FT_GlyphSlot_Embolden(slot);
|
||||
if (UserFlags & ImGuiFreeTypeBuilderFlags_Oblique)
|
||||
{
|
||||
FT_GlyphSlot_Oblique(slot);
|
||||
//FT_BBox bbox;
|
||||
//FT_Outline_Get_BBox(&slot->outline, &bbox);
|
||||
//slot->metrics.width = bbox.xMax - bbox.xMin;
|
||||
//slot->metrics.height = bbox.yMax - bbox.yMin;
|
||||
}
|
||||
|
||||
return &slot->metrics;
|
||||
}
|
||||
|
||||
const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info)
|
||||
{
|
||||
FT_GlyphSlot slot = Face->glyph;
|
||||
FT_Error error = FT_Render_Glyph(slot, RenderMode);
|
||||
if (error != 0)
|
||||
return nullptr;
|
||||
|
||||
FT_Bitmap* ft_bitmap = &Face->glyph->bitmap;
|
||||
out_glyph_info->Width = (int)ft_bitmap->width;
|
||||
out_glyph_info->Height = (int)ft_bitmap->rows;
|
||||
out_glyph_info->OffsetX = Face->glyph->bitmap_left;
|
||||
out_glyph_info->OffsetY = -Face->glyph->bitmap_top;
|
||||
out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x);
|
||||
out_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA);
|
||||
|
||||
return ft_bitmap;
|
||||
}
|
||||
|
||||
void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
|
||||
{
|
||||
IM_ASSERT(ft_bitmap != nullptr);
|
||||
const uint32_t w = ft_bitmap->width;
|
||||
const uint32_t h = ft_bitmap->rows;
|
||||
const uint8_t* src = ft_bitmap->buffer;
|
||||
const uint32_t src_pitch = ft_bitmap->pitch;
|
||||
|
||||
switch (ft_bitmap->pixel_mode)
|
||||
{
|
||||
case FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel.
|
||||
{
|
||||
if (multiply_table == nullptr)
|
||||
{
|
||||
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||
for (uint32_t x = 0; x < w; x++)
|
||||
dst[x] = IM_COL32(255, 255, 255, src[x]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||
for (uint32_t x = 0; x < w; x++)
|
||||
dst[x] = IM_COL32(255, 255, 255, multiply_table[src[x]]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB.
|
||||
{
|
||||
uint8_t color0 = multiply_table ? multiply_table[0] : 0;
|
||||
uint8_t color1 = multiply_table ? multiply_table[255] : 255;
|
||||
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||
{
|
||||
uint8_t bits = 0;
|
||||
const uint8_t* bits_ptr = src;
|
||||
for (uint32_t x = 0; x < w; x++, bits <<= 1)
|
||||
{
|
||||
if ((x & 7) == 0)
|
||||
bits = *bits_ptr++;
|
||||
dst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? color1 : color0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FT_PIXEL_MODE_BGRA:
|
||||
{
|
||||
// FIXME: Converting pre-multiplied alpha to straight. Doesn't smell good.
|
||||
#define DE_MULTIPLY(color, alpha) (ImU32)(255.0f * (float)color / (float)alpha + 0.5f)
|
||||
if (multiply_table == nullptr)
|
||||
{
|
||||
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||
for (uint32_t x = 0; x < w; x++)
|
||||
{
|
||||
uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];
|
||||
dst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||
{
|
||||
for (uint32_t x = 0; x < w; x++)
|
||||
{
|
||||
uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];
|
||||
dst[x] = IM_COL32(multiply_table[DE_MULTIPLY(r, a)], multiply_table[DE_MULTIPLY(g, a)], multiply_table[DE_MULTIPLY(b, a)], multiply_table[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef DE_MULTIPLY
|
||||
break;
|
||||
}
|
||||
default:
|
||||
IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!");
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
|
||||
#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
#define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0)
|
||||
#define STBRP_STATIC
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
#endif
|
||||
#ifdef IMGUI_STB_RECT_PACK_FILENAME
|
||||
#include IMGUI_STB_RECT_PACK_FILENAME
|
||||
#else
|
||||
#include "imstb_rectpack.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct ImFontBuildSrcGlyphFT
|
||||
{
|
||||
GlyphInfo Info;
|
||||
uint32_t Codepoint;
|
||||
unsigned int* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array
|
||||
|
||||
ImFontBuildSrcGlyphFT() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
struct ImFontBuildSrcDataFT
|
||||
{
|
||||
FreeTypeFont Font;
|
||||
stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position.
|
||||
const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
|
||||
int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[]
|
||||
int GlyphsHighest; // Highest requested codepoint
|
||||
int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
|
||||
ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
|
||||
ImVector<ImFontBuildSrcGlyphFT> GlyphsList;
|
||||
};
|
||||
|
||||
// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
|
||||
struct ImFontBuildDstDataFT
|
||||
{
|
||||
int SrcCount; // Number of source fonts targeting this destination font.
|
||||
int GlyphsHighest;
|
||||
int GlyphsCount;
|
||||
ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font.
|
||||
};
|
||||
|
||||
bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags)
|
||||
{
|
||||
IM_ASSERT(atlas->ConfigData.Size > 0);
|
||||
|
||||
ImFontAtlasBuildInit(atlas);
|
||||
|
||||
// Clear atlas
|
||||
atlas->TexID = 0;
|
||||
atlas->TexWidth = atlas->TexHeight = 0;
|
||||
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
|
||||
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
||||
atlas->ClearTexData();
|
||||
|
||||
// Temporary storage for building
|
||||
bool src_load_color = false;
|
||||
ImVector<ImFontBuildSrcDataFT> src_tmp_array;
|
||||
ImVector<ImFontBuildDstDataFT> dst_tmp_array;
|
||||
src_tmp_array.resize(atlas->ConfigData.Size);
|
||||
dst_tmp_array.resize(atlas->Fonts.Size);
|
||||
memset((void*)src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
||||
memset((void*)dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
|
||||
|
||||
// 1. Initialize font loading structure, check font data validity
|
||||
for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
FreeTypeFont& font_face = src_tmp.Font;
|
||||
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
||||
|
||||
// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||
src_tmp.DstIndex = -1;
|
||||
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
|
||||
if (cfg.DstFont == atlas->Fonts[output_i])
|
||||
src_tmp.DstIndex = output_i;
|
||||
IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
|
||||
if (src_tmp.DstIndex == -1)
|
||||
return false;
|
||||
|
||||
// Load font
|
||||
if (!font_face.InitFont(ft_library, cfg, extra_flags))
|
||||
return false;
|
||||
|
||||
// Measure highest codepoints
|
||||
src_load_color |= (cfg.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0;
|
||||
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||
{
|
||||
// Check for valid range. This may also help detect *some* dangling pointers, because a common
|
||||
// user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent.
|
||||
IM_ASSERT(src_range[0] <= src_range[1]);
|
||||
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
|
||||
}
|
||||
dst_tmp.SrcCount++;
|
||||
dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
|
||||
}
|
||||
|
||||
// 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
|
||||
int total_glyphs_count = 0;
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||
src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1);
|
||||
if (dst_tmp.GlyphsSet.Storage.empty())
|
||||
dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1);
|
||||
|
||||
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||
for (int codepoint = src_range[0]; codepoint <= (int)src_range[1]; codepoint++)
|
||||
{
|
||||
if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
|
||||
continue;
|
||||
uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..)
|
||||
if (glyph_index == 0)
|
||||
continue;
|
||||
|
||||
// Add to avail set/counters
|
||||
src_tmp.GlyphsCount++;
|
||||
dst_tmp.GlyphsCount++;
|
||||
src_tmp.GlyphsSet.SetBit(codepoint);
|
||||
dst_tmp.GlyphsSet.SetBit(codepoint);
|
||||
total_glyphs_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||
src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
|
||||
|
||||
IM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(ImU32));
|
||||
const ImU32* it_begin = src_tmp.GlyphsSet.Storage.begin();
|
||||
const ImU32* it_end = src_tmp.GlyphsSet.Storage.end();
|
||||
for (const ImU32* it = it_begin; it < it_end; it++)
|
||||
if (ImU32 entries_32 = *it)
|
||||
for (ImU32 bit_n = 0; bit_n < 32; bit_n++)
|
||||
if (entries_32 & ((ImU32)1 << bit_n))
|
||||
{
|
||||
ImFontBuildSrcGlyphFT src_glyph;
|
||||
src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n);
|
||||
//src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it..
|
||||
src_tmp.GlyphsList.push_back(src_glyph);
|
||||
}
|
||||
src_tmp.GlyphsSet.Clear();
|
||||
IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
|
||||
}
|
||||
for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
|
||||
dst_tmp_array[dst_i].GlyphsSet.Clear();
|
||||
dst_tmp_array.clear();
|
||||
|
||||
// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
|
||||
// (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
|
||||
ImVector<stbrp_rect> buf_rects;
|
||||
buf_rects.resize(total_glyphs_count);
|
||||
memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
|
||||
|
||||
// Allocate temporary rasterization data buffers.
|
||||
// We could not find a way to retrieve accurate glyph size without rendering them.
|
||||
// (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform)
|
||||
// We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't mind the temporary allocations.
|
||||
const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;
|
||||
int buf_bitmap_current_used_bytes = 0;
|
||||
ImVector<unsigned char*> buf_bitmap_buffers;
|
||||
buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
|
||||
|
||||
// 4. Gather glyphs sizes so we can pack them in our virtual canvas.
|
||||
// 8. Render/rasterize font characters into the texture
|
||||
int total_surface = 0;
|
||||
int buf_rects_out_n = 0;
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
if (src_tmp.GlyphsCount == 0)
|
||||
continue;
|
||||
|
||||
src_tmp.Rects = &buf_rects[buf_rects_out_n];
|
||||
buf_rects_out_n += src_tmp.GlyphsCount;
|
||||
|
||||
// Compute multiply table if requested
|
||||
const bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
|
||||
unsigned char multiply_table[256];
|
||||
if (multiply_enabled)
|
||||
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
||||
|
||||
// Gather the sizes of all rectangles we will need to pack
|
||||
const int padding = atlas->TexGlyphPadding;
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
||||
{
|
||||
ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
|
||||
|
||||
const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint);
|
||||
if (metrics == nullptr)
|
||||
continue;
|
||||
|
||||
// Render glyph into a bitmap (currently held by FreeType)
|
||||
const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info);
|
||||
if (ft_bitmap == nullptr)
|
||||
continue;
|
||||
|
||||
// Allocate new temporary chunk if needed
|
||||
const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height * 4;
|
||||
if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE)
|
||||
{
|
||||
buf_bitmap_current_used_bytes = 0;
|
||||
buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
|
||||
}
|
||||
IM_ASSERT(buf_bitmap_current_used_bytes + bitmap_size_in_bytes <= BITMAP_BUFFERS_CHUNK_SIZE); // We could probably allocate custom-sized buffer instead.
|
||||
|
||||
// Blit rasterized pixels to our temporary buffer and keep a pointer to it.
|
||||
src_glyph.BitmapData = (unsigned int*)(buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes);
|
||||
buf_bitmap_current_used_bytes += bitmap_size_in_bytes;
|
||||
src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width, multiply_enabled ? multiply_table : nullptr);
|
||||
|
||||
src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding);
|
||||
src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding);
|
||||
total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
|
||||
}
|
||||
}
|
||||
|
||||
// We need a width for the skyline algorithm, any width!
|
||||
// The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
|
||||
// User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
|
||||
const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
|
||||
atlas->TexHeight = 0;
|
||||
if (atlas->TexDesiredWidth > 0)
|
||||
atlas->TexWidth = atlas->TexDesiredWidth;
|
||||
else
|
||||
atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512;
|
||||
|
||||
// 5. Start packing
|
||||
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
||||
const int TEX_HEIGHT_MAX = 1024 * 32;
|
||||
const int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding;
|
||||
ImVector<stbrp_node> pack_nodes;
|
||||
pack_nodes.resize(num_nodes_for_packing_algorithm);
|
||||
stbrp_context pack_context;
|
||||
stbrp_init_target(&pack_context, atlas->TexWidth - atlas->TexGlyphPadding, TEX_HEIGHT_MAX - atlas->TexGlyphPadding, pack_nodes.Data, pack_nodes.Size);
|
||||
ImFontAtlasBuildPackCustomRects(atlas, &pack_context);
|
||||
|
||||
// 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||
if (src_tmp.GlyphsCount == 0)
|
||||
continue;
|
||||
|
||||
stbrp_pack_rects(&pack_context, src_tmp.Rects, src_tmp.GlyphsCount);
|
||||
|
||||
// Extend texture height and mark missing glyphs as non-packed so we won't render them.
|
||||
// FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||
if (src_tmp.Rects[glyph_i].was_packed)
|
||||
atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
|
||||
}
|
||||
|
||||
// 7. Allocate texture
|
||||
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
|
||||
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
||||
if (src_load_color)
|
||||
{
|
||||
size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 4;
|
||||
atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(tex_size);
|
||||
memset(atlas->TexPixelsRGBA32, 0, tex_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 1;
|
||||
atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(tex_size);
|
||||
memset(atlas->TexPixelsAlpha8, 0, tex_size);
|
||||
}
|
||||
|
||||
// 8. Copy rasterized font characters back into the main texture
|
||||
// 9. Setup ImFont and glyphs for runtime
|
||||
bool tex_use_colors = false;
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||
if (src_tmp.GlyphsCount == 0)
|
||||
continue;
|
||||
|
||||
// When merging fonts with MergeMode=true:
|
||||
// - We can have multiple input fonts writing into a same destination font.
|
||||
// - dst_font->ConfigData is != from cfg which is our source configuration.
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFont* dst_font = cfg.DstFont;
|
||||
|
||||
const float ascent = src_tmp.Font.Info.Ascender;
|
||||
const float descent = src_tmp.Font.Info.Descender;
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
||||
const float font_off_x = cfg.GlyphOffset.x;
|
||||
const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
|
||||
const int padding = atlas->TexGlyphPadding;
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||
{
|
||||
ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
|
||||
stbrp_rect& pack_rect = src_tmp.Rects[glyph_i];
|
||||
IM_ASSERT(pack_rect.was_packed);
|
||||
if (pack_rect.w == 0 && pack_rect.h == 0)
|
||||
continue;
|
||||
|
||||
GlyphInfo& info = src_glyph.Info;
|
||||
IM_ASSERT(info.Width + padding <= pack_rect.w);
|
||||
IM_ASSERT(info.Height + padding <= pack_rect.h);
|
||||
const int tx = pack_rect.x + padding;
|
||||
const int ty = pack_rect.y + padding;
|
||||
|
||||
// Register glyph
|
||||
float x0 = info.OffsetX * src_tmp.Font.InvRasterizationDensity + font_off_x;
|
||||
float y0 = info.OffsetY * src_tmp.Font.InvRasterizationDensity + font_off_y;
|
||||
float x1 = x0 + info.Width * src_tmp.Font.InvRasterizationDensity;
|
||||
float y1 = y0 + info.Height * src_tmp.Font.InvRasterizationDensity;
|
||||
float u0 = (tx) / (float)atlas->TexWidth;
|
||||
float v0 = (ty) / (float)atlas->TexHeight;
|
||||
float u1 = (tx + info.Width) / (float)atlas->TexWidth;
|
||||
float v1 = (ty + info.Height) / (float)atlas->TexHeight;
|
||||
dst_font->AddGlyph(&cfg, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity);
|
||||
|
||||
ImFontGlyph* dst_glyph = &dst_font->Glyphs.back();
|
||||
IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint);
|
||||
if (src_glyph.Info.IsColored)
|
||||
dst_glyph->Colored = tex_use_colors = true;
|
||||
|
||||
// Blit from temporary buffer to final texture
|
||||
size_t blit_src_stride = (size_t)src_glyph.Info.Width;
|
||||
size_t blit_dst_stride = (size_t)atlas->TexWidth;
|
||||
unsigned int* blit_src = src_glyph.BitmapData;
|
||||
if (atlas->TexPixelsAlpha8 != nullptr)
|
||||
{
|
||||
unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx;
|
||||
for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
|
||||
for (int x = 0; x < info.Width; x++)
|
||||
blit_dst[x] = (unsigned char)((blit_src[x] >> IM_COL32_A_SHIFT) & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int* blit_dst = atlas->TexPixelsRGBA32 + (ty * blit_dst_stride) + tx;
|
||||
for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
|
||||
for (int x = 0; x < info.Width; x++)
|
||||
blit_dst[x] = blit_src[x];
|
||||
}
|
||||
}
|
||||
|
||||
src_tmp.Rects = nullptr;
|
||||
}
|
||||
atlas->TexPixelsUseColors = tex_use_colors;
|
||||
|
||||
// Cleanup
|
||||
for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)
|
||||
IM_FREE(buf_bitmap_buffers[buf_i]);
|
||||
src_tmp_array.clear_destruct();
|
||||
|
||||
ImFontAtlasBuildFinish(atlas);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// FreeType memory allocation callbacks
|
||||
static void* FreeType_Alloc(FT_Memory /*memory*/, long size)
|
||||
{
|
||||
return GImGuiFreeTypeAllocFunc((size_t)size, GImGuiFreeTypeAllocatorUserData);
|
||||
}
|
||||
|
||||
static void FreeType_Free(FT_Memory /*memory*/, void* block)
|
||||
{
|
||||
GImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);
|
||||
}
|
||||
|
||||
static void* FreeType_Realloc(FT_Memory /*memory*/, long cur_size, long new_size, void* block)
|
||||
{
|
||||
// Implement realloc() as we don't ask user to provide it.
|
||||
if (block == nullptr)
|
||||
return GImGuiFreeTypeAllocFunc((size_t)new_size, GImGuiFreeTypeAllocatorUserData);
|
||||
|
||||
if (new_size == 0)
|
||||
{
|
||||
GImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (new_size > cur_size)
|
||||
{
|
||||
void* new_block = GImGuiFreeTypeAllocFunc((size_t)new_size, GImGuiFreeTypeAllocatorUserData);
|
||||
memcpy(new_block, block, (size_t)cur_size);
|
||||
GImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);
|
||||
return new_block;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
static bool ImFontAtlasBuildWithFreeType(ImFontAtlas* atlas)
|
||||
{
|
||||
// FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html
|
||||
FT_MemoryRec_ memory_rec = {};
|
||||
memory_rec.user = nullptr;
|
||||
memory_rec.alloc = &FreeType_Alloc;
|
||||
memory_rec.free = &FreeType_Free;
|
||||
memory_rec.realloc = &FreeType_Realloc;
|
||||
|
||||
// https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library
|
||||
FT_Library ft_library;
|
||||
FT_Error error = FT_New_Library(&memory_rec, &ft_library);
|
||||
if (error != 0)
|
||||
return false;
|
||||
|
||||
// If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator.
|
||||
FT_Add_Default_Modules(ft_library);
|
||||
|
||||
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
// Install svg hooks for FreeType
|
||||
// https://freetype.org/freetype2/docs/reference/ft2-properties.html#svg-hooks
|
||||
// https://freetype.org/freetype2/docs/reference/ft2-svg_fonts.html#svg_fonts
|
||||
SVG_RendererHooks hooks = { ImGuiLunasvgPortInit, ImGuiLunasvgPortFree, ImGuiLunasvgPortRender, ImGuiLunasvgPortPresetSlot };
|
||||
FT_Property_Set(ft_library, "ot-svg", "svg-hooks", &hooks);
|
||||
#endif // IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
|
||||
bool ret = ImFontAtlasBuildWithFreeTypeEx(ft_library, atlas, atlas->FontBuilderFlags);
|
||||
FT_Done_Library(ft_library);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const ImFontBuilderIO* ImGuiFreeType::GetBuilderForFreeType()
|
||||
{
|
||||
static ImFontBuilderIO io;
|
||||
io.FontBuilder_Build = ImFontAtlasBuildWithFreeType;
|
||||
return &io;
|
||||
}
|
||||
|
||||
void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
|
||||
{
|
||||
GImGuiFreeTypeAllocFunc = alloc_func;
|
||||
GImGuiFreeTypeFreeFunc = free_func;
|
||||
GImGuiFreeTypeAllocatorUserData = user_data;
|
||||
}
|
||||
|
||||
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
// For more details, see https://gitlab.freedesktop.org/freetype/freetype-demos/-/blob/master/src/rsvg-port.c
|
||||
// The original code from the demo is licensed under CeCILL-C Free Software License Agreement (https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/LICENSE.TXT)
|
||||
struct LunasvgPortState
|
||||
{
|
||||
FT_Error err = FT_Err_Ok;
|
||||
lunasvg::Matrix matrix;
|
||||
std::unique_ptr<lunasvg::Document> svg = nullptr;
|
||||
};
|
||||
|
||||
static FT_Error ImGuiLunasvgPortInit(FT_Pointer* _state)
|
||||
{
|
||||
*_state = IM_NEW(LunasvgPortState)();
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
static void ImGuiLunasvgPortFree(FT_Pointer* _state)
|
||||
{
|
||||
IM_DELETE(*(LunasvgPortState**)_state);
|
||||
}
|
||||
|
||||
static FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state)
|
||||
{
|
||||
LunasvgPortState* state = *(LunasvgPortState**)_state;
|
||||
|
||||
// If there was an error while loading the svg in ImGuiLunasvgPortPresetSlot(), the renderer hook still get called, so just returns the error.
|
||||
if (state->err != FT_Err_Ok)
|
||||
return state->err;
|
||||
|
||||
// rows is height, pitch (or stride) equals to width * sizeof(int32)
|
||||
lunasvg::Bitmap bitmap((uint8_t*)slot->bitmap.buffer, slot->bitmap.width, slot->bitmap.rows, slot->bitmap.pitch);
|
||||
state->svg->setMatrix(state->svg->matrix().identity()); // Reset the svg matrix to the default value
|
||||
state->svg->render(bitmap, state->matrix); // state->matrix is already scaled and translated
|
||||
state->err = FT_Err_Ok;
|
||||
return state->err;
|
||||
}
|
||||
|
||||
static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state)
|
||||
{
|
||||
FT_SVG_Document document = (FT_SVG_Document)slot->other;
|
||||
LunasvgPortState* state = *(LunasvgPortState**)_state;
|
||||
FT_Size_Metrics& metrics = document->metrics;
|
||||
|
||||
// This function is called twice, once in the FT_Load_Glyph() and another right before ImGuiLunasvgPortRender().
|
||||
// If it's the latter, don't do anything because it's // already done in the former.
|
||||
if (cache)
|
||||
return state->err;
|
||||
|
||||
state->svg = lunasvg::Document::loadFromData((const char*)document->svg_document, document->svg_document_length);
|
||||
if (state->svg == nullptr)
|
||||
{
|
||||
state->err = FT_Err_Invalid_SVG_Document;
|
||||
return state->err;
|
||||
}
|
||||
|
||||
lunasvg::Box box = state->svg->box();
|
||||
double scale = std::min(metrics.x_ppem / box.w, metrics.y_ppem / box.h);
|
||||
double xx = (double)document->transform.xx / (1 << 16);
|
||||
double xy = -(double)document->transform.xy / (1 << 16);
|
||||
double yx = -(double)document->transform.yx / (1 << 16);
|
||||
double yy = (double)document->transform.yy / (1 << 16);
|
||||
double x0 = (double)document->delta.x / 64 * box.w / metrics.x_ppem;
|
||||
double y0 = -(double)document->delta.y / 64 * box.h / metrics.y_ppem;
|
||||
|
||||
// Scale and transform, we don't translate the svg yet
|
||||
state->matrix.identity();
|
||||
state->matrix.scale(scale, scale);
|
||||
state->matrix.transform(xx, xy, yx, yy, x0, y0);
|
||||
state->svg->setMatrix(state->matrix);
|
||||
|
||||
// Pre-translate the matrix for the rendering step
|
||||
state->matrix.translate(-box.x, -box.y);
|
||||
|
||||
// Get the box again after the transformation
|
||||
box = state->svg->box();
|
||||
|
||||
// Calculate the bitmap size
|
||||
slot->bitmap_left = FT_Int(box.x);
|
||||
slot->bitmap_top = FT_Int(-box.y);
|
||||
slot->bitmap.rows = (unsigned int)(ImCeil((float)box.h));
|
||||
slot->bitmap.width = (unsigned int)(ImCeil((float)box.w));
|
||||
slot->bitmap.pitch = slot->bitmap.width * 4;
|
||||
slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
|
||||
|
||||
// Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box.
|
||||
double metrics_width = box.w;
|
||||
double metrics_height = box.h;
|
||||
double horiBearingX = box.x;
|
||||
double horiBearingY = -box.y;
|
||||
double vertBearingX = slot->metrics.horiBearingX / 64.0 - slot->metrics.horiAdvance / 64.0 / 2.0;
|
||||
double vertBearingY = (slot->metrics.vertAdvance / 64.0 - slot->metrics.height / 64.0) / 2.0;
|
||||
slot->metrics.width = FT_Pos(IM_ROUND(metrics_width * 64.0)); // Using IM_ROUND() assume width and height are positive
|
||||
slot->metrics.height = FT_Pos(IM_ROUND(metrics_height * 64.0));
|
||||
slot->metrics.horiBearingX = FT_Pos(horiBearingX * 64);
|
||||
slot->metrics.horiBearingY = FT_Pos(horiBearingY * 64);
|
||||
slot->metrics.vertBearingX = FT_Pos(vertBearingX * 64);
|
||||
slot->metrics.vertBearingY = FT_Pos(vertBearingY * 64);
|
||||
|
||||
if (slot->metrics.vertAdvance == 0)
|
||||
slot->metrics.vertAdvance = FT_Pos(metrics_height * 1.2 * 64.0);
|
||||
|
||||
state->err = FT_Err_Ok;
|
||||
return state->err;
|
||||
}
|
||||
|
||||
#endif // #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
@ -1,51 +0,0 @@
|
||||
// dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder)
|
||||
// (headers)
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_API
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
// Forward declarations
|
||||
struct ImFontAtlas;
|
||||
struct ImFontBuilderIO;
|
||||
|
||||
// Hinting greatly impacts visuals (and glyph sizes).
|
||||
// - By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter.
|
||||
// - When disabled, FreeType generates blurrier glyphs, more or less matches the stb_truetype.h
|
||||
// - The Default hinting mode usually looks good, but may distort glyphs in an unusual way.
|
||||
// - The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer.
|
||||
// You can set those flags globaly in ImFontAtlas::FontBuilderFlags
|
||||
// You can set those flags on a per font basis in ImFontConfig::FontBuilderFlags
|
||||
enum ImGuiFreeTypeBuilderFlags
|
||||
{
|
||||
ImGuiFreeTypeBuilderFlags_NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes.
|
||||
ImGuiFreeTypeBuilderFlags_NoAutoHint = 1 << 1, // Disable auto-hinter.
|
||||
ImGuiFreeTypeBuilderFlags_ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter.
|
||||
ImGuiFreeTypeBuilderFlags_LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text.
|
||||
ImGuiFreeTypeBuilderFlags_MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output.
|
||||
ImGuiFreeTypeBuilderFlags_Bold = 1 << 5, // Styling: Should we artificially embolden the font?
|
||||
ImGuiFreeTypeBuilderFlags_Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style?
|
||||
ImGuiFreeTypeBuilderFlags_Monochrome = 1 << 7, // Disable anti-aliasing. Combine this with MonoHinting for best results!
|
||||
ImGuiFreeTypeBuilderFlags_LoadColor = 1 << 8, // Enable FreeType color-layered glyphs
|
||||
ImGuiFreeTypeBuilderFlags_Bitmap = 1 << 9 // Enable FreeType bitmap glyphs
|
||||
};
|
||||
|
||||
namespace ImGuiFreeType
|
||||
{
|
||||
// This is automatically assigned when using '#define IMGUI_ENABLE_FREETYPE'.
|
||||
// If you need to dynamically select between multiple builders:
|
||||
// - you can manually assign this builder with 'atlas->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()'
|
||||
// - prefer deep-copying this into your own ImFontBuilderIO instance if you use hot-reloading that messes up static data.
|
||||
IMGUI_API const ImFontBuilderIO* GetBuilderForFreeType();
|
||||
|
||||
// Override allocators. By default ImGuiFreeType will use IM_ALLOC()/IM_FREE()
|
||||
// However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired.
|
||||
IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = nullptr);
|
||||
|
||||
// Obsolete names (will be removed soon)
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
//static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); } // Prefer using '#define IMGUI_ENABLE_FREETYPE'
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
||||
option(NO_STATISTICS "Disable calculation of statistics" ON)
|
||||
option(NO_PARALLEL_STL "Disable parallel STL" OFF)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
|
||||
|
||||
|
@ -7,9 +7,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unordered_map>
|
||||
#include <zstd.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define stat64 _stat64
|
||||
@ -23,7 +23,6 @@
|
||||
#include "../../server/TracyFileWrite.hpp"
|
||||
#include "../../server/TracyMmap.hpp"
|
||||
#include "../../server/TracyWorker.hpp"
|
||||
#include "../../zstd/zstd.h"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
|
@ -15,10 +15,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <zstd.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define stat64 _stat64
|
||||
@ -30,7 +30,6 @@
|
||||
#include "../../server/TracyFileWrite.hpp"
|
||||
#include "../../server/TracyMmap.hpp"
|
||||
#include "../../server/TracyWorker.hpp"
|
||||
#include "../../zstd/zstd.h"
|
||||
|
||||
void Usage() {
|
||||
printf("Usage: import-fuchsia input.json output.tracy\n\n");
|
||||
|
@ -1,17 +0,0 @@
|
||||
all: release
|
||||
|
||||
debug:
|
||||
@$(MAKE) -f debug.mk all
|
||||
|
||||
release:
|
||||
@$(MAKE) -f release.mk all
|
||||
|
||||
clean:
|
||||
@$(MAKE) -f build.mk clean
|
||||
rm -f libtracy-*.so
|
||||
|
||||
db: clean
|
||||
@bear -- $(MAKE) -f debug.mk all
|
||||
@mv -f compile_commands.json ../../
|
||||
|
||||
.PHONY: all clean debug release db
|
@ -1,12 +0,0 @@
|
||||
CFLAGS +=
|
||||
CXXFLAGS := $(CFLAGS) -std=c++11 -fpic
|
||||
DEFINES += -DTRACY_ENABLE
|
||||
INCLUDES :=
|
||||
LIBS := -lpthread -ldl
|
||||
PROJECT := libtracy
|
||||
IMAGE := $(PROJECT)-$(BUILD).so
|
||||
SHARED_LIBRARY := yes
|
||||
|
||||
SRC := ../../public/TracyClient.cpp
|
||||
|
||||
include ../../common/unix.mk
|
@ -1,13 +0,0 @@
|
||||
ARCH := $(shell uname -m)
|
||||
|
||||
CFLAGS := -g3 -Wall
|
||||
DEFINES := -DDEBUG
|
||||
BUILD := debug
|
||||
|
||||
ifndef TRACY_NO_ISA_EXTENSIONS
|
||||
ifeq ($(ARCH),x86_64)
|
||||
CFLAGS += -msse4.1
|
||||
endif
|
||||
endif
|
||||
|
||||
include build.mk
|
@ -1,13 +0,0 @@
|
||||
ARCH := $(shell uname -m)
|
||||
|
||||
CFLAGS := -O3 -s
|
||||
DEFINES := -DNDEBUG
|
||||
BUILD := release
|
||||
|
||||
ifndef TRACY_NO_ISA_EXTENSIONS
|
||||
ifeq ($(ARCH),x86_64)
|
||||
CFLAGS += -msse4.1
|
||||
endif
|
||||
endif
|
||||
|
||||
include build.mk
|
@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30907.101
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TracyProfiler", "TracyProfiler.vcxproj", "{C5B825D3-F140-45AB-8A47-B740E56631FB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Release|x64 = Release|x64
|
||||
ReleaseOnDemand|x64 = ReleaseOnDemand|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C5B825D3-F140-45AB-8A47-B740E56631FB}.Release|x64.ActiveCfg = Release|x64
|
||||
{C5B825D3-F140-45AB-8A47-B740E56631FB}.Release|x64.Build.0 = Release|x64
|
||||
{C5B825D3-F140-45AB-8A47-B740E56631FB}.ReleaseOnDemand|x64.ActiveCfg = ReleaseOnDemand|x64
|
||||
{C5B825D3-F140-45AB-8A47-B740E56631FB}.ReleaseOnDemand|x64.Build.0 = ReleaseOnDemand|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E739AC0A-0937-46D7-8807-1EE95CEB576D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,229 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="ReleaseOnDemand|Win32">
|
||||
<Configuration>ReleaseOnDemand</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="ReleaseOnDemand|x64">
|
||||
<Configuration>ReleaseOnDemand</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\public\TracyClient.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{C5B825D3-F140-45AB-8A47-B740E56631FB}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>TracyProfiler</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>TRACY_ENABLE;NDEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseOnDemand|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>TRACY_ON_DEMAND;TRACY_ENABLE;NDEBUG;TRACY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\public\TracyClient.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
366
manual/tracy.tex
366
manual/tracy.tex
@ -139,7 +139,7 @@ There's much more Tracy can do, which can be explored by carefully reading this
|
||||
\section{A quick look at Tracy Profiler}
|
||||
\label{quicklook}
|
||||
|
||||
Tracy is a real-time, nanosecond resolution \emph{hybrid frame and sampling profiler} that you can use for remote or embedded telemetry of games and other applications. It can profile CPU\footnote{Direct support is provided for C, C++, and Lua integration. At the same time, third-party bindings to many other languages exist on the internet, such as Rust, Zig, C\#, OCaml, Odin, etc.}, GPU\footnote{All major graphic APIs: OpenGL, Vulkan, Direct3D 11/12, OpenCL.}, memory allocations, locks, context switches, automatically attribute screenshots to captured frames, and much more.
|
||||
Tracy is a real-time, nanosecond resolution \emph{hybrid frame and sampling profiler} that you can use for remote or embedded telemetry of games and other applications. It can profile CPU\footnote{Direct support is provided for C, C++, Lua, Python and Fortran integration. At the same time, third-party bindings to many other languages exist on the internet, such as Rust, Zig, C\#, OCaml, Odin, etc.}, GPU\footnote{All major graphic APIs: OpenGL, Vulkan, Direct3D 11/12, Metal, OpenCL.}, memory allocations, locks, context switches, automatically attribute screenshots to captured frames, and much more.
|
||||
|
||||
While Tracy can perform statistical analysis of sampled call stack data, just like other \emph{statistical profilers} (such as VTune, perf, or Very Sleepy), it mainly focuses on manual markup of the source code. Such markup allows frame-by-frame inspection of the program execution. For example, you will be able to see exactly which functions are called, how much time they require, and how they interact with each other in a multi-threaded environment. In contrast, the statistical analysis may show you the hot spots in your code, but it cannot accurately pinpoint the underlying cause for semi-random frame stutter that may occur every couple of seconds.
|
||||
|
||||
@ -441,7 +441,7 @@ You can integrate Tracy with CMake by adding the git submodule folder as a subdi
|
||||
|
||||
\begin{lstlisting}
|
||||
# set options before add_subdirectory
|
||||
# available options: TRACY_ENABLE, TRACY_ON_DEMAND, TRACY_NO_BROADCAST, TRACY_NO_CODE_TRANSFER, ...
|
||||
# available options: TRACY_ENABLE, TRACY_LTO, TRACY_ON_DEMAND, TRACY_NO_BROADCAST, TRACY_NO_CODE_TRANSFER, ...
|
||||
option(TRACY_ENABLE "" ON)
|
||||
option(TRACY_ON_DEMAND "" ON)
|
||||
add_subdirectory(3rdparty/tracy) # target: TracyClient or alias Tracy::TracyClient
|
||||
@ -479,6 +479,9 @@ target_link_libraries(<TARGET> PUBLIC TracyClient)
|
||||
\end{lstlisting}
|
||||
\end{bclogo}
|
||||
|
||||
While using \texttt{set(CMAKE\_INTERPROCEDURAL\_OPTIMIZATION ON)} is a convenient way to enable Link-Time Optimization (LTO) for an entire project, there are situations in which this may not work due to excessive compilation times, linking issues, compiler bugs, or other reasons.
|
||||
For such cases, Tracy provides an option to enable Link-Time Optimization for itself using the \texttt{TRACY\_LTO} variable during the CMake configuration stage.
|
||||
|
||||
\subsubsection{Meson integration}
|
||||
|
||||
If you are using the Meson build system, you can add Tracy using the Wrap dependency system. To do this, place the \texttt{tracy.wrap} file in the \texttt{subprojects} directory of your project, with the following content. The \texttt{head} \texttt{revision} field tracks Tracy's \texttt{master} branch. If you want to lock to a specific version of Tracy instead, you can just set the \texttt{revision} field to an appropriate git tag.
|
||||
@ -553,7 +556,7 @@ By default, the Tracy client will listen on IPv6 interfaces, falling back to IPv
|
||||
|
||||
Things are a bit different in projects that consist of multiple DLLs/shared objects. Compiling \texttt{TracyClient.cpp} into every DLL is not an option because this would result in several instances of Tracy objects lying around in the process. We instead need to pass their instances to the different DLLs to be reused there.
|
||||
|
||||
For that, you need a \emph{profiler DLL} to which your executable and the other DLLs link. If that doesn't exist, you have to create one explicitly for Tracy\footnote{You may also look at the \texttt{library} directory in the profiler source tree.}. This library should contain the \texttt{public/TracyClient.cpp} source file. Link the executable and all DLLs you want to profile to this DLL.
|
||||
For that, you need a \emph{profiler DLL} to which your executable and the other DLLs link. If that doesn't exist, you have to create one explicitly for Tracy\footnote{You can use the top-level Meson or CMake build scripts to get it. Make sure that the same build flags are set for both the library and your application, or you may find yourself chasing weird issues.}. This library should contain the \texttt{public/TracyClient.cpp} source file. Link the executable and all DLLs you want to profile to this DLL.
|
||||
|
||||
If you are targeting Windows with Microsoft Visual Studio or MinGW, add the \texttt{TRACY\_IMPORTS} define to your application.
|
||||
|
||||
@ -579,6 +582,8 @@ In the case of some programming environments, you may need to take extra steps t
|
||||
|
||||
If you are using MSVC, you will need to disable the \emph{Edit And Continue} feature, as it makes the compiler non-conformant to some aspects of the C++ standard. In order to do so, open the project properties and go to \menu[,]{C/C++,General,Debug Information Format} and make sure \emph{Program Database for Edit And Continue (/ZI)} is \emph{not} selected.
|
||||
|
||||
For context, if you experience errors like "error C2131: expression did not evaluate to a constant", "failure was caused by non-constant arguments or reference to a non-constant symbol", and "see usage of '\texttt{\_\_LINE\_\_Var}'", chances are that your project has the \emph{Edit And Continue} feature enabled.
|
||||
|
||||
\paragraph{Universal Windows Platform}
|
||||
|
||||
Due to a restricted access to Win32 APIs and other sandboxing issues (like network isolation), several limitations apply to using Tracy in a UWP application compared to Windows Desktop:
|
||||
@ -807,6 +812,20 @@ cmake --build profiler/build --config Release --parallel
|
||||
The build directory can be reused if you want to compile the program in the future, for example if there have been some updates to the source code, and usually does not need to be regenerated. Note that all build artifacts are contained in the build directory.
|
||||
\end{bclogo}
|
||||
|
||||
\begin{bclogo}[
|
||||
noborder=true,
|
||||
couleur=black!5,
|
||||
logo=\bcattention
|
||||
]{Caveats}
|
||||
Tracy requires network connectivity and \texttt{git} to be available during the build configuration step in order to download the necessary libraries. By default, this is done for each build directory you configure with CMake. To make this requirement more reasonable, it is recommended to set a cache directory, for example:
|
||||
|
||||
\begin{lstlisting}[language=sh]
|
||||
export CPM_SOURCE_CACHE=~/.cache/cpm
|
||||
\end{lstlisting}
|
||||
|
||||
With this environment variable set, the library download will be performed only once, and the cached checkouts will be used in all future CMake build directory setups, allowing offline builds. Access to the network will then only be needed if the cache directory is cleared, or if the requirements for the libraries change, for example after an upgrade to a different version of Tracy.
|
||||
\end{bclogo}
|
||||
|
||||
\begin{bclogo}[
|
||||
noborder=true,
|
||||
couleur=black!5,
|
||||
@ -817,40 +836,16 @@ Due to the memory requirements for data storage, the Tracy server is only suppos
|
||||
|
||||
\subsubsection{Required libraries}
|
||||
|
||||
The core libraries necessary for the building of Tracy utilities are:
|
||||
|
||||
\begin{itemize}
|
||||
\item capstone
|
||||
\item glfw
|
||||
\item freetype
|
||||
\end{itemize}
|
||||
|
||||
The capstone library will always be downloaded from GitHub when the CMake build directory is created, unless you have it installed on your system and set the specific build option. You must have git installed for this download to work. Using the capstone library provided by package managers is not recommended, as these packages are typically slow to provide up-to-date versions of the library, and the API may be incompatible.
|
||||
|
||||
It is recommended that you install the glfw and freetype libraries on your system so that Tracy can find them with \texttt{pkg-config}. However, if these libraries are not available, they will be downloaded from GitHub.
|
||||
|
||||
\paragraph{Windows}
|
||||
|
||||
There is no need to install external libraries (e.g. with vcpkg). All libraries are downloaded automatically by CMake. You still need git, though.
|
||||
In most cases it is possible to build Tracy without manually installing additional libraries. All requirements are automatically downloaded by CMake.
|
||||
|
||||
\paragraph{Unix}
|
||||
|
||||
On Unix systems (including Linux), you will need to install the \texttt{pkg-config} utility to provide information about libraries.
|
||||
On Unix systems, such as Linux or macOS, it is possible to link with certain common system libraries to reduce build times and resource usage through shared objects. This is optional and will be done automatically if all requirements are met. If it's not possible, there is no loss of functionality as Tracy will build and statically link these libraries anyway.
|
||||
|
||||
Due to some questionable design decisions by the compiler developers, you will most likely also need the \texttt{tbb} library\footnote{Technically, this is not a Tracy dependency, but rather a \texttt{libstdc++} dependency, but it may still not be installed by default.}. If not found, this library is downloaded automatically.
|
||||
You will need to install the \texttt{pkg-config} utility to provide information about libraries. Then you will need to install \texttt{freetype} and \texttt{glfw} libraries.
|
||||
|
||||
Installation of the libraries on OSX can be facilitated using the \texttt{brew} package manager.
|
||||
|
||||
\paragraph{Linux}
|
||||
|
||||
There are some Linux-specific libraries that you need to have installed on your system. These won't be downloaded automatically.
|
||||
|
||||
For XDG Portal support in the file selector, you need to install the \texttt{dbus} library. If you're one of those weird people who doesn't like modern things, you can install \texttt{gtk3} instead and force the GTK file selector with a build option.
|
||||
|
||||
Linux builds of Tracy use the Wayland protocol by default, which allows proper support for Hi-DPI scaling and high-precision input devices such as touchpads. As such, the \texttt{glfw} library is no longer needed, but you will need to install \texttt{libxkbcommon}, \texttt{wayland}, \texttt{wayland-protocols}, \texttt{libglvnd} (or \texttt{libegl} on some distributions).
|
||||
|
||||
If you want to use X11 instead, you can enable the \texttt{LEGACY} option in CMake build settings.
|
||||
|
||||
\begin{bclogo}[
|
||||
noborder=true,
|
||||
couleur=black!5,
|
||||
@ -861,6 +856,16 @@ Some Linux distributions require you to add a \texttt{lib} prefix and a \texttt{
|
||||
Some Linux distributions ship outdated versions of libraries that are too old for Tracy to build, and do not provide new versions by design. Please reconsider your choice of distribution in this case, as the only function of a Linux distribution is to provide packages, and the one you have chosen is clearly failing at this task.
|
||||
\end{bclogo}
|
||||
|
||||
\paragraph{Linux}
|
||||
|
||||
There are some Linux-specific libraries that you need to have installed on your system. These won't be downloaded automatically.
|
||||
|
||||
For XDG Portal support in the file selector, you need to install the \texttt{dbus} library (and a portal appropriate for your desktop environment). If you're one of those weird people who doesn't like modern things, you can install \texttt{gtk3} instead and force the GTK file selector with a build option.
|
||||
|
||||
Linux builds of Tracy use the Wayland protocol by default, which allows proper support for Hi-DPI scaling, high-precision input devices such as touchpads, proper handling of mouse cursors, and so on. As such, the \texttt{glfw} library is no longer needed, but you will need to install \texttt{libxkbcommon}, \texttt{wayland}, \texttt{wayland-protocols}, \texttt{libglvnd} (or \texttt{libegl} on some distributions).
|
||||
|
||||
If you want to use X11 instead, you can enable the \texttt{LEGACY} option in CMake build settings. Going this way is discouraged.
|
||||
|
||||
\begin{bclogo}[
|
||||
noborder=true,
|
||||
couleur=black!5,
|
||||
@ -976,6 +981,7 @@ Memory & \faCheck & \faCheck & \faCheck & \faCheck & \faCheck & \faCheck & \faTi
|
||||
% GPU zones fields intentionally left blank for BSDs
|
||||
GPU zones (OpenGL) & \faCheck & \faCheck & \faCheck & \faPoo & \faPoo & & \faTimes \\
|
||||
GPU zones (Vulkan) & \faCheck & \faCheck & \faCheck & \faCheck & \faCheck & & \faTimes \\
|
||||
GPU zones (Metal) & \faTimes & \faTimes & \faTimes & \faCheck\textsuperscript{\emph{b}} & \faCheck\textsuperscript{\emph{b}} & \faTimes & \faTimes \\
|
||||
Call stacks & \faCheck & \faCheck & \faCheck & \faCheck & \faCheck & \faCheck & \faTimes \\
|
||||
Symbol resolution & \faCheck & \faCheck & \faCheck & \faCheck & \faCheck & \faCheck & \faCheck \\
|
||||
Crash handling & \faCheck & \faCheck & \faCheck & \faTimes & \faTimes & \faTimes & \faTimes \\
|
||||
@ -991,6 +997,7 @@ VSync capture & \faCheck & \faCheck & \faTimes & \faTimes & \faTimes & \faTimes
|
||||
\vspace{1em}
|
||||
\faPoo{} -- Not possible to support due to platform limitations. \\
|
||||
\textsuperscript{\emph{a}}Possible through WSL2.
|
||||
\textsuperscript{\emph{b}}Only tested on Apple Silicon M1 series
|
||||
\caption{Feature support matrix}
|
||||
\label{featuretable}
|
||||
\end{table}
|
||||
@ -1559,7 +1566,7 @@ To mark that a separate memory pool is to be tracked you should use the named ve
|
||||
\subsection{GPU profiling}
|
||||
\label{gpuprofiling}
|
||||
|
||||
Tracy provides bindings for profiling OpenGL, Vulkan, Direct3D 11, Direct3D 12, and OpenCL execution time on GPU.
|
||||
Tracy provides bindings for profiling OpenGL, Vulkan, Direct3D 11, Direct3D 12, Metal and OpenCL execution time on GPU.
|
||||
|
||||
Note that the CPU and GPU timers may be unsynchronized unless you create a calibrated context, but the availability of calibrated contexts is limited. You can try to correct the desynchronization of uncalibrated contexts in the profiler's options (section~\ref{options}).
|
||||
|
||||
@ -1665,6 +1672,16 @@ Note that GPU profiling may be slightly inaccurate due to artifacts from dynamic
|
||||
|
||||
Direct3D 12 contexts are always calibrated.
|
||||
|
||||
\subsubsection{Metal}
|
||||
|
||||
To enable Metal support, include the \texttt{public/tracy/TracyMetal.hmm} header file, and create a \texttt{tracy::MetalCtx} object with the \texttt{TracyMetalContext(device)} macro. The object should later be cleaned up with the \texttt{TracyMetalDestroy(context)} macro. To set a custom name for the context, use the \texttt{TracyMetalContextName(name, namelen)} macro. The header file \texttt{TracyMetal.hmm} is intended to be included by \textbf{Objective-C} code, and Objective-C Automatic Reference Counting (ARC) support is required.
|
||||
|
||||
At the moment, the Metal back-end in Tracy operates differently than other GPU back-ends like Vulkan, Direct3D and OpenGL. Specifically, \texttt{TracyMetalZone(name, encoderDescriptor)} must be placed before the site where a command encoder is about to be created. This is because not all Apple hardware supports timestamps at command granularity, and can only provide timestamps around an entire command encoder (this accommodates for all tiers of GPU hardware on Apple platforms).
|
||||
|
||||
You may also use \texttt{TracyMetalZoneC(name, encoderDescriptor, color)} to specify a zone color. There is no interface for callstack or transient Metal zones at the moment.
|
||||
|
||||
You are required to periodically collect the GPU events using the \texttt{TracyMetalCollect(ctx)} macro. Good places for collection are: after synchronous waits, after present drawable calls, and inside the completion handler of command buffers.
|
||||
|
||||
\subsubsection{OpenCL}
|
||||
|
||||
OpenCL support is achieved by including the \texttt{public/tracy/TracyOpenCL.hpp} header file. Tracing OpenCL requires the creation of a Tracy OpenCL context using the macro \texttt{TracyCLContext(context, device)}, which will return an instance of \texttt{TracyCLCtx} object that must be used when creating zones. The specified \texttt{device} must be part of the \texttt{context}. Cleanup is performed using the \texttt{TracyCLDestroy(ctx)} macro. Although not common, it is possible to create multiple OpenCL contexts for the same application. To set a custom name for the context, use the \texttt{TracyCLContextName(ctx, name, size)} macro.
|
||||
@ -1679,13 +1696,13 @@ Similar to Vulkan and OpenGL, you also need to periodically collect the OpenCL e
|
||||
|
||||
Putting more than one GPU zone macro in a single scope features the same issue as with the \texttt{ZoneScoped} macros, described in section~\ref{multizone} (but this time the variable name is \texttt{\_\_\_tracy\_gpu\_zone}).
|
||||
|
||||
To solve this problem, in case of OpenGL use the \texttt{TracyGpuNamedZone} macro in place of \texttt{TracyGpuZone} (or the color variant). The same applies to Vulkan and Direct3D 11/12 -- replace \texttt{TracyVkZone} with \texttt{TracyVkNamedZone} and \texttt{TracyD3D11Zone}/\texttt{TracyD3D12Zone} with \texttt{TracyD3D11NamedZone}/\texttt{TracyD3D12NamedZone}.
|
||||
To solve this problem, in case of OpenGL use the \texttt{TracyGpuNamedZone} macro in place of \texttt{TracyGpuZone} (or the color variant). The same applies to Vulkan, Direct3D 11/12 and Metal -- replace \texttt{TracyVkZone} with \texttt{TracyVkNamedZone}, \texttt{TracyD3D11Zone}/\texttt{TracyD3D12Zone} with \texttt{TracyD3D11NamedZone}/\texttt{TracyD3D12NamedZone}, and \texttt{TracyMetalZone} with \texttt{TracyMetalNamedZone}.
|
||||
|
||||
Remember to provide your name for the created stack variable as the first parameter to the macros.
|
||||
|
||||
\subsubsection{Transient GPU zones}
|
||||
|
||||
Transient zones (see section~\ref{transientzones} for details) are available in OpenGL, Vulkan, and Direct3D 11/12 macros.
|
||||
Transient zones (see section~\ref{transientzones} for details) are available in OpenGL, Vulkan, and Direct3D 11/12 macros. Transient zones are not available for Metal at this moment.
|
||||
|
||||
\subsection{Fibers}
|
||||
\label{fibers}
|
||||
@ -1985,6 +2002,14 @@ Cost of performing Lua call stack capture is presented in table~\ref{CallstackTi
|
||||
|
||||
Even if Tracy is disabled, you still have to pay the no-op function call cost. To prevent that, you may want to use the \texttt{tracy::LuaRemove(char* script)} function, which will replace instrumentation calls with white-space. This function does nothing if the profiler is enabled.
|
||||
|
||||
\subsubsection{Automatic instrumentation}
|
||||
|
||||
Lua code can be automatically instrumented by using Lua hooks. The \texttt{tracy::LuaHook(lua\_State*, lua\_Debug*)} function may be used as or within a Lua hook. There is a small performance impact from using Lua hooks since the Lua VM will be required to invoke the hook function.
|
||||
|
||||
The Lua hook must have the \texttt{LUA\_HOOKCALL} and \texttt{LUA\_HOOKRET} event mask set. You may either directly set the function as your hook or chain it to your existing hook.
|
||||
|
||||
Use \texttt{lua\_sethook(L, tracy::LuaHook, LUA\_MASKCALL | LUA\_MASKRET, 0)} if you do not already have a Lua hook set or directly call \texttt{tracy::LuaHook(L, ar)} within your hook if you already have one set.
|
||||
|
||||
\subsection{C API}
|
||||
\label{capi}
|
||||
|
||||
@ -2107,6 +2132,7 @@ TracyCLockAfterUnlock(tracy_lock_ctx);
|
||||
You can optionally mark the location of where the lock is held by using the \texttt{TracyCLockMark} macro, this should be done after acquiring the lock.
|
||||
|
||||
\subsubsection{Memory profiling}
|
||||
\label{cmemoryprofiling}
|
||||
|
||||
Use the following macros in your implementations of \texttt{malloc} and \texttt{free}:
|
||||
|
||||
@ -2354,6 +2380,249 @@ python3 setup.py bdist_wheel
|
||||
|
||||
The created package will be in the folder \texttt{python/dist}.
|
||||
|
||||
\subsection{Fortran API}
|
||||
\label{fortranapi}
|
||||
|
||||
To profile code written in Fortran programming language, you will need to use the \texttt{tracy} module, which exposes the Fortran API.
|
||||
|
||||
At the moment, there's no support for Fortran API based markup of locks (as well as Fortran lacks them) and GPU zones.
|
||||
|
||||
\begin{bclogo}[
|
||||
noborder=true,
|
||||
couleur=black!5,
|
||||
logo=\bcbombe
|
||||
]{Important}
|
||||
Tracy is written in C++, so you will need to have a C++ compiler and link with C++ standard library, even if your program is strictly pure Fortran.
|
||||
For mixed Fortran/C++ applications, be sure that the same compiler is used both for Tracy and for C++-part of application.
|
||||
\end{bclogo}
|
||||
|
||||
\subsubsection{First steps}
|
||||
|
||||
\paragraph{CMake integration}
|
||||
|
||||
You can integrate Tracy with CMake by adding the git submodule folder as a subdirectory.
|
||||
|
||||
\begin{lstlisting}
|
||||
# set options before add_subdirectory
|
||||
# available options: TRACY_ENABLE, TRACY_ON_DEMAND, TRACY_NO_BROADCAST, TRACY_NO_CODE_TRANSFER, ...
|
||||
option(TRACY_ENABLE "" ON)
|
||||
# must be enabled
|
||||
option(TRACY_Fortran "" ON)
|
||||
option(TRACY_DELAYED_INIT "" ON)
|
||||
option(TRACY_MANUAL_LIFETIME "" ON)
|
||||
add_subdirectory(3rdparty/tracy) # target: TracyClientF90 or alias Tracy::TracyClientF90
|
||||
\end{lstlisting}
|
||||
|
||||
Link \texttt{Tracy::TracyClientF90} to any target where you use Tracy for profiling:
|
||||
|
||||
\begin{lstlisting}
|
||||
target_link_libraries(<TARGET> PUBLIC Tracy::TracyClientF90)
|
||||
\end{lstlisting}
|
||||
|
||||
For using Link-Time optimizations, link both \texttt{Tracy::TracyClient} and \texttt{Tracy::TracyClientF90} to any target where you use Tracy for profiling:
|
||||
|
||||
\begin{lstlisting}
|
||||
target_link_libraries(<TARGET> PUBLIC Tracy::TracyClient Tracy::TracyClientF90)
|
||||
\end{lstlisting}
|
||||
|
||||
\begin{bclogo}[
|
||||
noborder=true,
|
||||
couleur=black!5,
|
||||
logo=\bcbombe
|
||||
]{Important}
|
||||
The same compiler (vendor + version) must be used for LTO for \textbf{ALL} languages in project.
|
||||
\end{bclogo}
|
||||
|
||||
\begin{bclogo}[
|
||||
noborder=true,
|
||||
couleur=black!5,
|
||||
logo=\bclampe
|
||||
]{CMake FetchContent}
|
||||
When using CMake 3.11 or newer, you can use Tracy via CMake FetchContent. In this case, you do not need to add a git submodule for Tracy manually. Add this to your CMakeLists.txt:
|
||||
|
||||
\begin{lstlisting}
|
||||
option(TRACY_Fortran "" ON)
|
||||
option(TRACY_DELAYED_INIT "" ON)
|
||||
option(TRACY_MANUAL_LIFETIME "" ON)
|
||||
|
||||
FetchContent_Declare(
|
||||
tracy
|
||||
GIT_REPOSITORY https://github.com/wolfpld/tracy.git
|
||||
GIT_TAG master
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(tracy)
|
||||
\end{lstlisting}
|
||||
|
||||
Then add this to any target where you use tracy for profiling:
|
||||
|
||||
\begin{lstlisting}
|
||||
target_link_libraries(<TARGET> PUBLIC TracyClientF90)
|
||||
\end{lstlisting}
|
||||
|
||||
For using Link-Time optimizations (LTO), you also need to link with \texttt{TracyClient}:
|
||||
|
||||
\begin{lstlisting}
|
||||
target_link_libraries(<TARGET> PUBLIC TracyClient TracyClientF90)
|
||||
\end{lstlisting}
|
||||
\end{bclogo}
|
||||
|
||||
\paragraph{\texttt{tracy} module}
|
||||
|
||||
Fortran API is available \textit{via} \texttt{tracy} module. FORTRAN 77 is not supported.
|
||||
|
||||
\paragraph{Manual start and stop}
|
||||
|
||||
To start profiling, you need to call \texttt{tracy\_startup\_profiler()} manually.
|
||||
At the end of profiling, you need to call \texttt{tracy\_shutdown\_profiler()} manually.
|
||||
Be sure that it is called in all possible exit branches.
|
||||
To check profiler status, you may use \texttt{tracy\_profiler\_started()} function.
|
||||
|
||||
\begin{bclogo}[
|
||||
noborder=true,
|
||||
couleur=black!5,
|
||||
logo=\bcbombe
|
||||
]{Tip}
|
||||
\texttt{stop} and \texttt{error stop} statements can be intercept at \texttt{exit} system call on UNIX systems.
|
||||
\end{bclogo}
|
||||
|
||||
\paragraph{Example usage}
|
||||
|
||||
A simple example of Fortran API usage is presented below:
|
||||
|
||||
\begin{lstlisting}
|
||||
program main
|
||||
#ifdef TRACY_ENABLE
|
||||
use tracy
|
||||
#endif
|
||||
implicit none
|
||||
|
||||
#ifdef TRACY_ENABLE
|
||||
if (.not.tracy_profiler_started()) call tracy_startup_profiler()
|
||||
! wait connection
|
||||
do while (.not.tracy_connected())
|
||||
call sleep(1) ! GNU extension
|
||||
end do
|
||||
#endif
|
||||
|
||||
! do something useful
|
||||
|
||||
#ifdef TRACY_ENABLE
|
||||
call tracy_shutdown_profiler()
|
||||
#endif
|
||||
end program main
|
||||
\end{lstlisting}
|
||||
|
||||
\begin{bclogo}[
|
||||
noborder=true,
|
||||
couleur=black!5,
|
||||
logo=\bcbombe
|
||||
]{Important}
|
||||
Since you are directly calling the profiler functions here, you will need to take care of manually disabling the code if the \texttt{TRACY\_ENABLE} macro is not defined.
|
||||
\end{bclogo}
|
||||
|
||||
\subsubsection{Setting thread names}
|
||||
|
||||
To set thread names (section~\ref{namingthreads}) using the Fortran API you should use the \texttt{tracy\_set\_thread\_name(name)} call.
|
||||
\texttt{zone\_name} is any Fortran strings.
|
||||
|
||||
\subsubsection{Zone markup}
|
||||
|
||||
The \texttt{tracy\_zone\_begin} call mark the beginning of a zone and returns \texttt{type(tracy\_zone\_context)} context.
|
||||
As a source location data, it can accept \texttt{type(tracy\_source\_location\_data)} or ID (\texttt{integer(c\_int64\_t)}) of source location data.
|
||||
This ID can be obtained \textit{via} \texttt{tracy\_alloc\_srcloc(line, source, function\_name, zone\_name, color)} call.
|
||||
\texttt{source}, \texttt{function\_name} and \texttt{zone\_name} are any Fortran strings.
|
||||
For using \texttt{type(tracy\_source\_location\_data)}, strings must be null-terminated.
|
||||
|
||||
Like C++, Fortran has an automatic destruction mechanism which unfortunately was not implemented prior GCC 10 (which are still popular as of beginning of 2025) and therefore context must be destroyed manually.
|
||||
To do so use the \texttt{tracy\_zone\_end(ctx)} call.
|
||||
|
||||
Zone text and name, as well as color and value, may be set by using the \texttt{tracy\_zone\_set\_properties(ctx, text, name, color, value)} call.
|
||||
\texttt{text} and \texttt{name} are any Fortran strings.
|
||||
Make sure you are following the zone stack rules, as described in section~\ref{multizone}!
|
||||
|
||||
\paragraph{Zone validation}
|
||||
|
||||
Since all Fortran API instrumentation has to be done by hand, it is possible to miss some code paths where a zone should be started or ended. Tracy will perform additional validation of instrumentation correctness to prevent bad profiling runs. Read section~\ref{instrumentationfailures} for more information.
|
||||
|
||||
However, the validation comes with a performance cost, which you may not want to pay. Therefore, if you are \emph{entirely sure} that the instrumentation is not broken in any way, you may use the \texttt{TRACY\_NO\_VERIFY} macro, which will disable the validation code.
|
||||
|
||||
\subsubsection{Frame markup}
|
||||
|
||||
To mark frames, as described in section~\ref{markingframes}, use the following calls:
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{tracy\_frame\_mark(name)}
|
||||
\item \texttt{tracy\_frame\_start(name)}
|
||||
\item \texttt{tracy\_frame\_end(name)}
|
||||
\end{itemize}
|
||||
|
||||
\texttt{name} can be omitted as optional argument or must be a null-terminated constant string.
|
||||
|
||||
To collect frame images, use \texttt{tracy\_image(image, w, h, offset, flip)} call.
|
||||
|
||||
\begin{bclogo}[
|
||||
noborder=true,
|
||||
couleur=black!5,
|
||||
logo=\bclampe
|
||||
]{Collecting matrices}
|
||||
\texttt{tracy\_image} can also collect matrix after a proper encoding it as \texttt{integer(c\_int32\_t)} 2D matrix.
|
||||
\end{bclogo}
|
||||
|
||||
\subsubsection{Memory profiling}
|
||||
|
||||
Use the following calls in your implementations of allocator/deallocator:
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{tracy\_memory\_alloc(ptr, size, name, depth, secure)}
|
||||
\item \texttt{tracy\_memory\_free(ptr, name, depth, secure)}
|
||||
\end{itemize}
|
||||
|
||||
Correctly using this functionality can be pretty tricky especially in Fortran.
|
||||
In Fortran, you can not redefine \texttt{allocate} statement (as well as \texttt{deallocate} statement) to profile memory usage by \texttt{allocatable} variables.
|
||||
However, many applications\footnote{Examples from Quantum Chemistry: GAMESS(US), MRCC} uses stack allocator on memory tape where these calls can be useful.
|
||||
|
||||
Memory pools (section~\ref{memorypools}) are supported through optional argument \texttt{name} which must be a null-terminated constant string.
|
||||
|
||||
For more information about memory profiling, refer to section~\ref{memoryprofiling}.
|
||||
For memory allocations implemented in C++/C, refer to section~\ref{memoryprofiling} and section~\ref{cmemoryprofiling}, respectively.
|
||||
|
||||
\subsubsection{Plots and messages}
|
||||
|
||||
To send additional markup in form of plot data points or messages use the following calls:
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{tracy\_message(msg, color, depth)}
|
||||
\item \texttt{tracy\_plot(name, val)}
|
||||
\item \texttt{tracy\_plot\_config(name, type, step, fill, color)}
|
||||
\item \texttt{tracy\_appinfo(info)}
|
||||
\end{itemize}
|
||||
|
||||
Note, \texttt{name} must be a null-terminated constant string, while \texttt{msg} and \texttt{info} are any Fortran strings.
|
||||
|
||||
Consult sections~\ref{plottingdata} and~\ref{messagelog} for more information.
|
||||
|
||||
\subsubsection{Fibers}
|
||||
|
||||
Fibers are available in the Fortran API through the \texttt{tracy\_fiber\_enter(name)} and \texttt{tracy\_fiber\_leave()} calls. To use them, you should observe the requirements listed in section~\ref{fibers}.
|
||||
Note, \texttt{name} must be a null-terminated constant string.
|
||||
|
||||
\subsubsection{Connection Status}
|
||||
|
||||
To query the connection status (section~\ref{connectionstatus}) using the Fortran API you should use the \texttt{tracy\_connected()} function.
|
||||
|
||||
\subsubsection{Call stacks}
|
||||
|
||||
You can collect call stacks of zones and memory allocation events, as described in section~\ref{collectingcallstacks}, by using optional \texttt{depth} argument in functions/subroutines calls.
|
||||
|
||||
\subsubsection{Colors}
|
||||
|
||||
A set of predefined colors is available with \texttt{TracyColors} variable inside of \texttt{tracy} module.
|
||||
To get a specific color, use \texttt{TracyColors\%COLOR} where \texttt{COLOR} is a specific one like \texttt{Red} or \texttt{Blue}.
|
||||
|
||||
|
||||
\subsection{Automated data collection}
|
||||
\label{automated}
|
||||
|
||||
@ -2901,11 +3170,12 @@ The main profiler window is split into three sections, as seen in figure~\ref{ma
|
||||
\draw (0, 0) rectangle (16.1, -5.5);
|
||||
\draw[pattern=crosshatch dots] (0, 0) rectangle+(16.1, 0.3);
|
||||
\draw[rounded corners=5pt] (0.1, -0.1) rectangle+(0.5, -0.5) node [midway] {\faPowerOff};
|
||||
\draw[rounded corners=5pt] (0.7, -0.1) rectangle+(1.8, -0.5) node [midway] {\faCog{} Options};
|
||||
\draw[rounded corners=5pt] (2.6, -0.1) rectangle+(2.2, -0.5) node [midway] {\faTags{} Messages};
|
||||
\draw[rounded corners=5pt] (4.9, -0.1) rectangle+(2.1, -0.5) node [midway] {\faSearch{} Find zone};
|
||||
\draw[rounded corners=5pt] (7.1, -0.1) rectangle+(2, -0.5) node [midway] {\faSortAmountUp{} Statistics};
|
||||
\draw[rounded corners=5pt] (9.2, -0.1) rectangle+(2, -0.5) node [midway] {\faMemory{} Memory};
|
||||
\draw[rounded corners=5pt] (0.7, -0.1) rectangle+(0.5, -0.5) node [midway] {\faCog{}};
|
||||
\draw[rounded corners=5pt] (1.3, -0.1) rectangle+(2.2, -0.5) node [midway] {\faTags{} Messages};
|
||||
\draw[rounded corners=5pt] (3.6, -0.1) rectangle+(1.5, -0.5) node [midway] {\faSearch{} Find};
|
||||
\draw[rounded corners=5pt] (5.2, -0.1) rectangle+(2, -0.5) node [midway] {\faSortAmountUp{} Statistics};
|
||||
\draw[rounded corners=5pt] (7.3, -0.1) rectangle+(1.6, -0.5) node [midway] {\faFire{} Flame};
|
||||
\draw[rounded corners=5pt] (9.0, -0.1) rectangle+(2.2, -0.5) node [midway] {\faMemory{} Memory};
|
||||
\draw[rounded corners=5pt] (11.3, -0.1) rectangle+(2.1, -0.5) node [midway] {\faBalanceScale{} Compare};
|
||||
\draw[rounded corners=5pt] (13.5, -0.1) rectangle+(1.3, -0.5) node [midway] {\faFingerprint{} Info};
|
||||
\draw[rounded corners=5pt] (14.9, -0.1) rectangle+(0.5, -0.5) node [midway] {\faTools{}};
|
||||
@ -2937,8 +3207,9 @@ The control menu (top row of buttons) provides access to various profiler featur
|
||||
\item \emph{\faSquare{} Stopped} -- Inactive button used to indicate that the client application was terminated.
|
||||
\item \emph{\faCog{} Options} -- Toggles the settings menu (section~\ref{options}).
|
||||
\item \emph{\faTags{} Messages} -- Toggles the message log window (section~\ref{messages}), which displays custom messages sent by the client, as described in section~\ref{messagelog}.
|
||||
\item \emph{\faSearch{} Find zone} -- This buttons toggles the find zone window, which allows inspection of zone behavior statistics (section~\ref{findzone}).
|
||||
\item \emph{\faSearch{} Find} -- This buttons toggles the find zone window, which allows inspection of zone behavior statistics (section~\ref{findzone}).
|
||||
\item \emph{\faSortAmountUp{} Statistics} -- Toggles the statistics window, which displays zones sorted by their total time cost (section~\ref{statistics}).
|
||||
\item \emph{\faFire{} Flame} -- Enables the flame graph window.
|
||||
\item \emph{\faMemory{} Memory} -- Various memory profiling options may be accessed here (section~\ref{memorywindow}).
|
||||
\item \emph{\faBalanceScale{} Compare} -- Toggles the trace compare window, which allows you to see the performance difference between two profiling runs (section~\ref{compare}).
|
||||
\item \emph{\faFingerprint{} Info} -- Show general information about the trace (section~\ref{traceinfo}).
|
||||
@ -3198,7 +3469,7 @@ You will find the zones with locks and their associated threads on this combined
|
||||
The left-hand side \emph{index area} of the timeline view displays various labels (threads, locks), which can be categorized in the following way:
|
||||
|
||||
\begin{itemize}
|
||||
\item \emph{Light blue label} -- GPU context. Multi-threaded Vulkan, OpenCL, and Direct3D 12 contexts are additionally split into separate threads.
|
||||
\item \emph{Light blue label} -- GPU context. Multi-threaded Vulkan, OpenCL, Direct3D 12 and Metal contexts are additionally split into separate threads.
|
||||
\item \emph{Pink label} -- CPU data graph.
|
||||
\item \emph{White label} -- A CPU thread. It will be replaced by a bright red label in a thread that has crashed (section~\ref{crashhandling}). If automated sampling was performed, clicking the~\LMB{}~left mouse button on the \emph{\faGhost{}~ghost zones} button will switch zone display mode between 'instrumented' and 'ghost.'
|
||||
\item \emph{Green label} -- Fiber, coroutine, or any other sort of cooperative multitasking 'green thread.'
|
||||
@ -3218,7 +3489,7 @@ In an example in figure~\ref{zoneslocks} you can see that there are two threads:
|
||||
|
||||
Meanwhile, the \emph{Streaming thread} is performing some \emph{Streaming jobs}. The first \emph{Streaming job} sent a message (section~\ref{messagelog}). In addition to being listed in the message log, it is indicated by a triangle over the thread separator. When multiple messages are in one place, the triangle outline shape changes to a filled triangle.
|
||||
|
||||
The GPU zones are displayed just like CPU zones, with an OpenGL/Vulkan/Direct3D/OpenCL context in place of a thread name.
|
||||
The GPU zones are displayed just like CPU zones, with an OpenGL/Vulkan/Direct3D/Metal/OpenCL context in place of a thread name.
|
||||
|
||||
Hovering the \faMousePointer{} mouse pointer over a zone will highlight all other zones that have the exact source location with a white outline. Clicking the \LMB{}~left mouse button on a zone will open the zone information window (section~\ref{zoneinfo}). Holding the \keys{\ctrl} key and clicking the \LMB{}~left mouse button on a zone will open the zone statistics window (section~\ref{findzone}). Clicking the \MMB{}~middle mouse button on a zone will zoom the view to the extent of the zone.
|
||||
|
||||
@ -3389,7 +3660,7 @@ In this window, you can set various trace-related options. For example, the time
|
||||
\begin{itemize}
|
||||
\item \emph{\faSignature{} Draw CPU usage graph} -- You can disable drawing of the CPU usage graph here.
|
||||
\end{itemize}
|
||||
\item \emph{\faEye{} Draw GPU zones} -- Allows disabling display of OpenGL/Vulkan/Direct3D/OpenCL zones. The \emph{GPU zones} drop-down allows disabling individual GPU contexts and setting CPU/GPU drift offsets of uncalibrated contexts (see section~\ref{gpuprofiling} for more information). The \emph{\faRobot~Auto} button automatically measures the GPU drift value\footnote{There is an assumption that drift is linear. Automated measurement calculates and removes change over time in delay-to-execution of GPU zones. Resulting value may still be incorrect.}.
|
||||
\item \emph{\faEye{} Draw GPU zones} -- Allows disabling display of OpenGL/Vulkan/Metal/Direct3D/OpenCL zones. The \emph{GPU zones} drop-down allows disabling individual GPU contexts and setting CPU/GPU drift offsets of uncalibrated contexts (see section~\ref{gpuprofiling} for more information). The \emph{\faRobot~Auto} button automatically measures the GPU drift value\footnote{There is an assumption that drift is linear. Automated measurement calculates and removes change over time in delay-to-execution of GPU zones. Resulting value may still be incorrect.}.
|
||||
\item \emph{\faMicrochip{} Draw CPU zones} -- Determines whether CPU zones are displayed.
|
||||
\begin{itemize}
|
||||
\item \emph{\faGhost{} Draw ghost zones} -- Controls if ghost zones should be displayed in threads which don't have any instrumented zones available.
|
||||
@ -3400,6 +3671,7 @@ In this window, you can set various trace-related options. For example, the time
|
||||
\item \emph{Source location dynamic} -- Zone color is determined by source location (function name) and depth level.
|
||||
\end{itemize}
|
||||
Enabling the \emph{Ignore custom} option will force usage of the selected zone coloring scheme, disregarding any colors set by the user in profiled code.
|
||||
Enabling the \emph{Inherit parent colors} option will cause zones that have a color set by the user in the profiled code to be propagated down to the child zones, although slightly darker.
|
||||
\item \emph{\faRulerHorizontal{} Zone name shortening} -- controls display behavior of long zone names, which don't fit inside a zone box:
|
||||
\begin{itemize}
|
||||
\item \emph{Disabled} -- Shortening of zone names is not performed and names are always displayed in full (e.g.\ \texttt{bool ns::container<float>::add(const float\&)}).
|
||||
@ -3466,9 +3738,11 @@ First and foremost, the presented information is constructed from many call stac
|
||||
|
||||
The sample statistics list symbols, not functions. These terms are similar, but not exactly the same. A symbol always has a base function that gives it its name. In most cases, a symbol will also contain a number of inlined functions. In some cases, the same function may be inlined more than once within the same symbol.
|
||||
|
||||
The \emph{Name} column contains name of the symbol in which the sampling was done. Kernel-mode symbol samples are distinguished with the red color. Symbols containing inlined functions are listed with the number of inlined functions in parentheses and can be expanded to show all inlined functions (some functions may be hidden if the \emph{\faPuzzlePiece{}~Show all} option is disabled due to lack of sampling data). Clicking on a function name will open the sample entry call stacks window (see chapter~\ref{sampleparents})\footnote{Note that if inclusive times are displayed, listed functions will be partially or completely coming from mid-stack frames, preventing, or limiting the capability to display parent call stacks.}.
|
||||
The \emph{Name} column contains name of the symbol in which the sampling was done. Kernel-mode symbol samples are distinguished with the red color. Symbols containing inlined functions are listed with the number of inlined functions in parentheses and can be expanded to show all inlined functions (some functions may be hidden if the \emph{\faPuzzlePiece{}~Show all} option is disabled due to lack of sampling data). Clicking the \LMB{}~left mouse button on a function name will open a popup with options to select: you can either open the symbol view window (section~\ref{symbolview}), or the sample entry stacks window (see chapter~\ref{sampleparents})\footnote{Note that if inclusive times are displayed, listed functions will be partially or completely coming from mid-stack frames, preventing, or limiting the capability to display the data.}.
|
||||
|
||||
By default, each inlining of a function is listed separately. If you prefer to combine the measurements for functions that are inlined multiple times within a function, you can do so by enabling the \emph{\faLayerGroup{}~Aggregate} option. You cannot view sample entry call stacks of inlined functions when this grouping method is enabled.
|
||||
By default, each inlining of a function is listed separately. If you prefer to combine the measurements for functions that are inlined multiple times within a function, you can do so by enabling the \emph{\faLayerGroup{}~Aggregate} option. You cannot view sample entry stacks of inlined functions when this grouping method is enabled.
|
||||
|
||||
In some cases it may be more interesting to see the most time consuming inline within the symbol rather than the symbol name. If you enable the \emph{\faFire*~Top inline} option, the name of the busiest inline function will be displayed in the \emph{Name} column.
|
||||
|
||||
If the \emph{\faSitemap{}~Inlines} option is enabled, the list will show all functions without grouping them by symbol. In this mode, inline functions are preceded by a \faCaretRight{} symbol and their parent function name is displayed in parentheses.
|
||||
|
||||
@ -3866,7 +4140,7 @@ Stack frame location may be displayed in the following number of ways, depending
|
||||
|
||||
In some cases, it may not be possible to decode stack frame addresses correctly. Such frames will be presented with a dimmed '\texttt{[ntdll.dll]}' name of the image containing the frame address, or simply '\texttt{[unknown]}' if the profiler cannot retrieve even this information. Additionally, '\texttt{[kernel]}' is used to indicate unknown stack frames within the operating system's internal routines.
|
||||
|
||||
If the displayed call stack is a sampled call stack (chapter~\ref{sampling}), an additional button will be available, \emph{\faDoorOpen{}~Global entry statistics}. Clicking it will open the sample entry call stacks window (chapter~\ref{sampleparents}) for the current call stack.
|
||||
If the displayed call stack is a sampled call stack (chapter~\ref{sampling}), an additional button will be available, \emph{\faDoorOpen{}~Global entry statistics}. Clicking it will open the sample entry stacks window (chapter~\ref{sampleparents}) for the current call stack.
|
||||
|
||||
Clicking on the \emph{\faClipboard{}~Copy to clipboard} button will copy call stack to the clipboard.
|
||||
|
||||
@ -3898,7 +4172,7 @@ At the first glance it may look like \texttt{unique\_ptr::reset} was the \emph{c
|
||||
|
||||
Moreover, the linker may determine in some rare cases that any two functions in your program are identical\footnote{For example, if all they do is zero-initialize a region of memory. As some constructors would do.}. As a result, only one copy of the binary code will be provided in the executable for both functions to share. While this optimization produces more compact programs, it also means that there's no way to distinguish the two functions apart in the resulting machine code. In effect, some call stacks may look nonsensical until you perform a small investigation.
|
||||
|
||||
\subsection{Sample entry call stacks window}
|
||||
\subsection{Sample entry stacks window}
|
||||
\label{sampleparents}
|
||||
|
||||
This window displays statistical information about the selected symbol. All sampled call stacks (chapter~\ref{sampling}) leading to the symbol are counted and displayed in descending order. You can choose the displayed call stack using the \emph{entry call stack} controls, which also display time spent in the selected call stack. Alternatively, sample counts may be shown by disabling the \emph{\faStopwatch{}~Show time} option, which is described in more detail in chapter~\ref{statisticssampling}.
|
||||
|
14
meson.build
14
meson.build
@ -1,4 +1,4 @@
|
||||
project('tracy', ['cpp'], version: '0.11.0', meson_version: '>=1.1.0')
|
||||
project('tracy', ['cpp'], version: '0.11.1', meson_version: '>=1.3.0', default_options : ['cpp_std=c++11'])
|
||||
|
||||
# internal compiler flags
|
||||
tracy_compile_args = []
|
||||
@ -150,6 +150,7 @@ client_includes = [
|
||||
'public/client/TracyDebug.hpp',
|
||||
'public/client/TracyDxt1.hpp',
|
||||
'public/client/TracyFastVector.hpp',
|
||||
'public/client/TracyKCore.hpp',
|
||||
'public/client/TracyLock.hpp',
|
||||
'public/client/TracyProfiler.hpp',
|
||||
'public/client/TracyRingBuffer.hpp',
|
||||
@ -189,8 +190,9 @@ tracy_public_include_dirs = include_directories('public')
|
||||
|
||||
compiler = meson.get_compiler('cpp')
|
||||
override_options = []
|
||||
if compiler.get_id() != 'msvc' and compiler.get_id() != 'clang-cl'
|
||||
override_options += 'cpp_std=c++11'
|
||||
# MSVC c++ lib does not work properly with C++11 and compilation may fail
|
||||
if compiler.has_define('_MSC_VER') and get_option('cpp_std') == 'c++11'
|
||||
override_options += 'cpp_std=c++14'
|
||||
endif
|
||||
|
||||
tracy_compile_args += tracy_common_args
|
||||
@ -204,9 +206,9 @@ tracy = library('tracy', tracy_src, tracy_header_files,
|
||||
override_options : override_options,
|
||||
install : true)
|
||||
|
||||
install_headers(includes, subdir : 'tracy')
|
||||
install_headers(common_includes, subdir : 'common')
|
||||
install_headers(client_includes, subdir : 'client')
|
||||
install_headers(includes, subdir : 'tracy/tracy')
|
||||
install_headers(common_includes, subdir : 'tracy/common')
|
||||
install_headers(client_includes, subdir : 'tracy/client')
|
||||
|
||||
tracy_dep_compile_args = tracy_common_args
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
|
||||
option(NO_FILESELECTOR "Disable the file selector" OFF)
|
||||
option(GTK_FILESELECTOR "Use the GTK file selector on Linux instead of the xdg-portal one" OFF)
|
||||
@ -6,7 +6,6 @@ option(LEGACY "Instead of Wayland, use the legacy X11 backend on Linux" OFF)
|
||||
option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
|
||||
option(NO_STATISTICS "Disable calculation of statistics" OFF)
|
||||
option(SELF_PROFILE "Enable self-profiling" OFF)
|
||||
option(NO_PARALLEL_STL "Disable parallel STL" OFF)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
|
||||
|
||||
@ -18,6 +17,11 @@ project(
|
||||
VERSION ${TRACY_VERSION_STRING}
|
||||
)
|
||||
|
||||
if(SELF_PROFILE)
|
||||
add_definitions(-DTRACY_ENABLE)
|
||||
add_compile_options(-g -O3 -fno-omit-frame-pointer)
|
||||
endif()
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/config.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/vendor.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/server.cmake)
|
||||
@ -55,6 +59,7 @@ set(SERVER_FILES
|
||||
TracyView_ContextSwitch.cpp
|
||||
TracyView_CpuData.cpp
|
||||
TracyView_FindZone.cpp
|
||||
TracyView_FlameGraph.cpp
|
||||
TracyView_FrameOverview.cpp
|
||||
TracyView_FrameTimeline.cpp
|
||||
TracyView_FrameTree.cpp
|
||||
@ -81,7 +86,6 @@ set(SERVER_FILES
|
||||
list(TRANSFORM SERVER_FILES PREPEND "src/profiler/")
|
||||
|
||||
set(PROFILER_FILES
|
||||
src/imgui/imgui_impl_opengl3.cpp
|
||||
src/ConnectionHistory.cpp
|
||||
src/Filters.cpp
|
||||
src/Fonts.cpp
|
||||
@ -97,12 +101,11 @@ set(PROFILER_FILES
|
||||
src/winmainArchDiscovery.cpp
|
||||
)
|
||||
|
||||
set(INCLUDES "")
|
||||
set(INCLUDES "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
set(LIBS "")
|
||||
|
||||
if(USE_WAYLAND)
|
||||
pkg_check_modules(WAYLAND REQUIRED egl wayland-egl wayland-cursor xkbcommon)
|
||||
set(INCLUDES "${INCLUDES};${CMAKE_CURRENT_BINARY_DIR}")
|
||||
set(LIBS "${LIBS};${WAYLAND_LIBRARIES}")
|
||||
set(PROFILER_FILES ${PROFILER_FILES}
|
||||
src/BackendWayland.cpp
|
||||
@ -110,41 +113,53 @@ if(USE_WAYLAND)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/FindWaylandScanner.cmake)
|
||||
|
||||
pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols)
|
||||
pkg_get_variable(WAYLAND_PROTOCOLS_PKGDATADIR wayland-protocols pkgdatadir)
|
||||
CPMAddPackage(
|
||||
NAME wayland-protocols
|
||||
GIT_REPOSITORY https://gitlab.freedesktop.org/wayland/wayland-protocols.git
|
||||
GIT_TAG 1.37
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml
|
||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/stable/xdg-shell/xdg-shell.xml
|
||||
BASENAME xdg-shell
|
||||
)
|
||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/staging/xdg-activation/xdg-activation-v1.xml
|
||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/staging/xdg-activation/xdg-activation-v1.xml
|
||||
BASENAME xdg-activation
|
||||
)
|
||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
|
||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
|
||||
BASENAME xdg-decoration
|
||||
)
|
||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/staging/fractional-scale/fractional-scale-v1.xml
|
||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/staging/fractional-scale/fractional-scale-v1.xml
|
||||
BASENAME fractional-scale
|
||||
)
|
||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml
|
||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/stable/viewporter/viewporter.xml
|
||||
BASENAME viewporter
|
||||
)
|
||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/staging/cursor-shape/cursor-shape-v1.xml
|
||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/staging/cursor-shape/cursor-shape-v1.xml
|
||||
BASENAME cursor-shape
|
||||
)
|
||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||
PROTOCOL ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/tablet/tablet-unstable-v2.xml
|
||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/unstable/tablet/tablet-unstable-v2.xml
|
||||
BASENAME tablet
|
||||
)
|
||||
ecm_add_wayland_client_protocol(PROFILER_FILES
|
||||
PROTOCOL ${wayland-protocols_SOURCE_DIR}/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml
|
||||
BASENAME xdg-toplevel-icon
|
||||
)
|
||||
elseif(EMSCRIPTEN)
|
||||
set(PROFILER_FILES ${PROFILER_FILES}
|
||||
src/BackendEmscripten.cpp
|
||||
)
|
||||
else()
|
||||
set(PROFILER_FILES ${PROFILER_FILES}
|
||||
src/BackendGlfw.cpp
|
||||
src/imgui/imgui_impl_glfw.cpp
|
||||
${ImGui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
@ -152,9 +167,6 @@ include_directories(${INCLUDES})
|
||||
link_libraries(${LIBS})
|
||||
|
||||
if(SELF_PROFILE)
|
||||
add_definitions(-DTRACY_ENABLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -fno-omit-frame-pointer")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -fno-omit-frame-pointer")
|
||||
set(PROFILER_FILES ${PROFILER_FILES}
|
||||
../public/TracyClient.cpp
|
||||
)
|
||||
@ -173,6 +185,17 @@ endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE TracyServer TracyImGui)
|
||||
|
||||
if(NOT DEFINED GIT_REV)
|
||||
set(GIT_REV "HEAD")
|
||||
endif()
|
||||
|
||||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||
add_custom_target(git-ref
|
||||
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/../extra/git-ref.py ${GIT_REV}
|
||||
BYPRODUCTS GitRef.hpp
|
||||
)
|
||||
add_dependencies(${PROJECT_NAME} git-ref)
|
||||
|
||||
if(NOT EMSCRIPTEN)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE TracyNfd)
|
||||
if (NOT USE_WAYLAND)
|
||||
@ -181,10 +204,12 @@ if(NOT EMSCRIPTEN)
|
||||
endif()
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY COMPILE_FLAGS "-sUSE_FREETYPE=1 -pthread -DIMGUI_IMPL_OPENGL_ES2")
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY LINK_FLAGS "-sASSERTIONS=0 -sUSE_GLFW=3 -sINITIAL_MEMORY=384mb -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=4gb -sWASM_BIGINT=1 -sPTHREAD_POOL_SIZE=4 -sEXPORTED_FUNCTIONS=_main,_nativeResize,_nativeOpenFile -sEXPORTED_RUNTIME_METHODS=ccall -sENVIRONMENT=web,worker --preload-file embed.tracy")
|
||||
target_link_options(${PROJECT_NAME} PRIVATE -pthread -sASSERTIONS=0 -sINITIAL_MEMORY=384mb -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=4gb -sSTACK_SIZE=1048576 -sWASM_BIGINT=1 -sPTHREAD_POOL_SIZE=8 -sEXPORTED_FUNCTIONS=_main,_nativeOpenFile -sEXPORTED_RUNTIME_METHODS=ccall -sENVIRONMENT=web,worker --preload-file embed.tracy)
|
||||
|
||||
file(DOWNLOAD https://share.nereid.pl/i/embed.tracy ${CMAKE_CURRENT_BINARY_DIR}/embed.tracy EXPECTED_MD5 ca0fa4f01e7b8ca5581daa16b16c768d)
|
||||
file(COPY ${CMAKE_CURRENT_LIST_DIR}/wasm/index.html DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
file(COPY ${CMAKE_CURRENT_LIST_DIR}/wasm/httpd.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
file(COPY_FILE ${CMAKE_CURRENT_LIST_DIR}/../icon/icon.svg ${CMAKE_CURRENT_BINARY_DIR}/favicon.svg)
|
||||
endif()
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
341
profiler/src/BackendEmscripten.cpp
Normal file
341
profiler/src/BackendEmscripten.cpp
Normal file
@ -0,0 +1,341 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <emscripten/html5.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
|
||||
#include "Backend.hpp"
|
||||
#include "RunQueue.hpp"
|
||||
#include "profiler/TracyImGui.hpp"
|
||||
|
||||
static std::function<void()> s_redraw;
|
||||
static std::function<void(float)> s_scaleChanged;
|
||||
static std::function<int(void)> s_isBusy;
|
||||
static RunQueue* s_mainThreadTasks;
|
||||
|
||||
static EGLDisplay s_eglDpy;
|
||||
static EGLContext s_eglCtx;
|
||||
static EGLSurface s_eglSurf;
|
||||
|
||||
static float s_prevScale = -1;
|
||||
static int s_width, s_height;
|
||||
static uint64_t s_time;
|
||||
static const char* s_prevCursor = nullptr;
|
||||
|
||||
static ImGuiKey TranslateKeyCode( const char* code )
|
||||
{
|
||||
if( strcmp( code, "Backquote" ) == 0 ) return ImGuiKey_GraveAccent;
|
||||
if( strcmp( code, "Backslash" ) == 0 ) return ImGuiKey_Backslash;
|
||||
if( strcmp( code, "BracketLeft" ) == 0 ) return ImGuiKey_LeftBracket;
|
||||
if( strcmp( code, "BracketRight" ) == 0 ) return ImGuiKey_RightBracket;
|
||||
if( strcmp( code, "Comma" ) == 0 ) return ImGuiKey_Comma;
|
||||
if( strcmp( code, "Digit0" ) == 0 ) return ImGuiKey_0;
|
||||
if( strcmp( code, "Digit1" ) == 0 ) return ImGuiKey_1;
|
||||
if( strcmp( code, "Digit2" ) == 0 ) return ImGuiKey_2;
|
||||
if( strcmp( code, "Digit3" ) == 0 ) return ImGuiKey_3;
|
||||
if( strcmp( code, "Digit4" ) == 0 ) return ImGuiKey_4;
|
||||
if( strcmp( code, "Digit5" ) == 0 ) return ImGuiKey_5;
|
||||
if( strcmp( code, "Digit6" ) == 0 ) return ImGuiKey_6;
|
||||
if( strcmp( code, "Digit7" ) == 0 ) return ImGuiKey_7;
|
||||
if( strcmp( code, "Digit8" ) == 0 ) return ImGuiKey_8;
|
||||
if( strcmp( code, "Digit9" ) == 0 ) return ImGuiKey_9;
|
||||
if( strcmp( code, "Equal" ) == 0 ) return ImGuiKey_Equal;
|
||||
if( strcmp( code, "IntlBackslash" ) == 0 ) return ImGuiKey_Backslash;
|
||||
if( strcmp( code, "IntlRo" ) == 0 ) return ImGuiKey_Backslash;
|
||||
if( strcmp( code, "IntlYen" ) == 0 ) return ImGuiKey_Backslash;
|
||||
if( strcmp( code, "KeyA" ) == 0 ) return ImGuiKey_A;
|
||||
if( strcmp( code, "KeyB" ) == 0 ) return ImGuiKey_B;
|
||||
if( strcmp( code, "KeyC" ) == 0 ) return ImGuiKey_C;
|
||||
if( strcmp( code, "KeyD" ) == 0 ) return ImGuiKey_D;
|
||||
if( strcmp( code, "KeyE" ) == 0 ) return ImGuiKey_E;
|
||||
if( strcmp( code, "KeyF" ) == 0 ) return ImGuiKey_F;
|
||||
if( strcmp( code, "KeyG" ) == 0 ) return ImGuiKey_G;
|
||||
if( strcmp( code, "KeyH" ) == 0 ) return ImGuiKey_H;
|
||||
if( strcmp( code, "KeyI" ) == 0 ) return ImGuiKey_I;
|
||||
if( strcmp( code, "KeyJ" ) == 0 ) return ImGuiKey_J;
|
||||
if( strcmp( code, "KeyK" ) == 0 ) return ImGuiKey_K;
|
||||
if( strcmp( code, "KeyL" ) == 0 ) return ImGuiKey_L;
|
||||
if( strcmp( code, "KeyM" ) == 0 ) return ImGuiKey_M;
|
||||
if( strcmp( code, "KeyN" ) == 0 ) return ImGuiKey_N;
|
||||
if( strcmp( code, "KeyO" ) == 0 ) return ImGuiKey_O;
|
||||
if( strcmp( code, "KeyP" ) == 0 ) return ImGuiKey_P;
|
||||
if( strcmp( code, "KeyQ" ) == 0 ) return ImGuiKey_Q;
|
||||
if( strcmp( code, "KeyR" ) == 0 ) return ImGuiKey_R;
|
||||
if( strcmp( code, "KeyS" ) == 0 ) return ImGuiKey_S;
|
||||
if( strcmp( code, "KeyT" ) == 0 ) return ImGuiKey_T;
|
||||
if( strcmp( code, "KeyU" ) == 0 ) return ImGuiKey_U;
|
||||
if( strcmp( code, "KeyV" ) == 0 ) return ImGuiKey_V;
|
||||
if( strcmp( code, "KeyW" ) == 0 ) return ImGuiKey_W;
|
||||
if( strcmp( code, "KeyX" ) == 0 ) return ImGuiKey_X;
|
||||
if( strcmp( code, "KeyY" ) == 0 ) return ImGuiKey_Y;
|
||||
if( strcmp( code, "KeyZ" ) == 0 ) return ImGuiKey_Z;
|
||||
if( strcmp( code, "Minus" ) == 0 ) return ImGuiKey_Minus;
|
||||
if( strcmp( code, "Period" ) == 0 ) return ImGuiKey_Period;
|
||||
if( strcmp( code, "Quote" ) == 0 ) return ImGuiKey_Apostrophe;
|
||||
if( strcmp( code, "Semicolon" ) == 0 ) return ImGuiKey_Semicolon;
|
||||
if( strcmp( code, "Slash" ) == 0 ) return ImGuiKey_Slash;
|
||||
if( strcmp( code, "AltLeft" ) == 0 ) return ImGuiKey_LeftAlt;
|
||||
if( strcmp( code, "AltRight" ) == 0 ) return ImGuiKey_RightAlt;
|
||||
if( strcmp( code, "Backspace" ) == 0 ) return ImGuiKey_Backspace;
|
||||
if( strcmp( code, "CapsLock" ) == 0 ) return ImGuiKey_CapsLock;
|
||||
if( strcmp( code, "ContextMenu" ) == 0 ) return ImGuiKey_Menu;
|
||||
if( strcmp( code, "ControlLeft" ) == 0 ) return ImGuiKey_LeftCtrl;
|
||||
if( strcmp( code, "ControlRight" ) == 0 ) return ImGuiKey_RightCtrl;
|
||||
if( strcmp( code, "Enter" ) == 0 ) return ImGuiKey_Enter;
|
||||
if( strcmp( code, "MetaLeft" ) == 0 ) return ImGuiKey_LeftSuper;
|
||||
if( strcmp( code, "MetaRight" ) == 0 ) return ImGuiKey_RightSuper;
|
||||
if( strcmp( code, "ShiftLeft" ) == 0 ) return ImGuiKey_LeftShift;
|
||||
if( strcmp( code, "ShiftRight" ) == 0 ) return ImGuiKey_RightShift;
|
||||
if( strcmp( code, "Space" ) == 0 ) return ImGuiKey_Space;
|
||||
if( strcmp( code, "Tab" ) == 0 ) return ImGuiKey_Tab;
|
||||
if( strcmp( code, "Delete" ) == 0 ) return ImGuiKey_Delete;
|
||||
if( strcmp( code, "End" ) == 0 ) return ImGuiKey_End;
|
||||
if( strcmp( code, "Home" ) == 0 ) return ImGuiKey_Home;
|
||||
if( strcmp( code, "Insert" ) == 0 ) return ImGuiKey_Insert;
|
||||
if( strcmp( code, "PageDown" ) == 0 ) return ImGuiKey_PageDown;
|
||||
if( strcmp( code, "PageUp" ) == 0 ) return ImGuiKey_PageUp;
|
||||
if( strcmp( code, "ArrowDown" ) == 0 ) return ImGuiKey_DownArrow;
|
||||
if( strcmp( code, "ArrowLeft" ) == 0 ) return ImGuiKey_LeftArrow;
|
||||
if( strcmp( code, "ArrowRight" ) == 0 ) return ImGuiKey_RightArrow;
|
||||
if( strcmp( code, "ArrowUp" ) == 0 ) return ImGuiKey_UpArrow;
|
||||
if( strcmp( code, "NumLock" ) == 0 ) return ImGuiKey_NumLock;
|
||||
if( strcmp( code, "Numpad0" ) == 0 ) return ImGuiKey_Keypad0;
|
||||
if( strcmp( code, "Numpad1" ) == 0 ) return ImGuiKey_Keypad1;
|
||||
if( strcmp( code, "Numpad2" ) == 0 ) return ImGuiKey_Keypad2;
|
||||
if( strcmp( code, "Numpad3" ) == 0 ) return ImGuiKey_Keypad3;
|
||||
if( strcmp( code, "Numpad4" ) == 0 ) return ImGuiKey_Keypad4;
|
||||
if( strcmp( code, "Numpad5" ) == 0 ) return ImGuiKey_Keypad5;
|
||||
if( strcmp( code, "Numpad6" ) == 0 ) return ImGuiKey_Keypad6;
|
||||
if( strcmp( code, "Numpad7" ) == 0 ) return ImGuiKey_Keypad7;
|
||||
if( strcmp( code, "Numpad8" ) == 0 ) return ImGuiKey_Keypad8;
|
||||
if( strcmp( code, "Numpad9" ) == 0 ) return ImGuiKey_Keypad9;
|
||||
if( strcmp( code, "NumpadAdd" ) == 0 ) return ImGuiKey_KeypadAdd;
|
||||
if( strcmp( code, "NumpadBackspace" ) == 0 ) return ImGuiKey_Backspace;
|
||||
if( strcmp( code, "NumpadComma" ) == 0 ) return ImGuiKey_KeypadDecimal;
|
||||
if( strcmp( code, "NumpadDecimal" ) == 0 ) return ImGuiKey_KeypadDecimal;
|
||||
if( strcmp( code, "NumpadDivide" ) == 0 ) return ImGuiKey_KeypadDivide;
|
||||
if( strcmp( code, "NumpadEnter" ) == 0 ) return ImGuiKey_KeypadEnter;
|
||||
if( strcmp( code, "NumpadEqual" ) == 0 ) return ImGuiKey_KeypadEqual;
|
||||
if( strcmp( code, "NumpadMultiply" ) == 0 ) return ImGuiKey_KeypadMultiply;
|
||||
if( strcmp( code, "NumpadSubtract" ) == 0 ) return ImGuiKey_KeypadSubtract;
|
||||
if( strcmp( code, "Escape" ) == 0 ) return ImGuiKey_Escape;
|
||||
if( strcmp( code, "F1" ) == 0 ) return ImGuiKey_F1;
|
||||
if( strcmp( code, "F2" ) == 0 ) return ImGuiKey_F2;
|
||||
if( strcmp( code, "F3" ) == 0 ) return ImGuiKey_F3;
|
||||
if( strcmp( code, "F4" ) == 0 ) return ImGuiKey_F4;
|
||||
if( strcmp( code, "F5" ) == 0 ) return ImGuiKey_F5;
|
||||
if( strcmp( code, "F6" ) == 0 ) return ImGuiKey_F6;
|
||||
if( strcmp( code, "F7" ) == 0 ) return ImGuiKey_F7;
|
||||
if( strcmp( code, "F8" ) == 0 ) return ImGuiKey_F8;
|
||||
if( strcmp( code, "F9" ) == 0 ) return ImGuiKey_F9;
|
||||
if( strcmp( code, "F10" ) == 0 ) return ImGuiKey_F10;
|
||||
// F11 is browser fullscreen, F12 is browser dev tools, omitting them
|
||||
if( strcmp( code, "ScrollLock" ) == 0 ) return ImGuiKey_ScrollLock;
|
||||
if( strcmp( code, "Pause" ) == 0 ) return ImGuiKey_Pause;
|
||||
return ImGuiKey_None;
|
||||
}
|
||||
|
||||
Backend::Backend( const char* title, const std::function<void()>& redraw, const std::function<void(float)>& scaleChanged, const std::function<int(void)>& isBusy, RunQueue* mainThreadTasks )
|
||||
{
|
||||
constexpr EGLint eglConfigAttrib[] = {
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
s_eglDpy = eglGetDisplay( EGL_DEFAULT_DISPLAY );
|
||||
EGLBoolean res;
|
||||
res = eglInitialize( s_eglDpy, nullptr, nullptr );
|
||||
if( res != EGL_TRUE ) { fprintf( stderr, "Cannot initialize EGL!\n" ); exit( 1 ); }
|
||||
|
||||
EGLint count;
|
||||
EGLConfig eglConfig;
|
||||
res = eglChooseConfig( s_eglDpy, eglConfigAttrib, &eglConfig, 1, &count );
|
||||
if( res != EGL_TRUE || count != 1 ) { fprintf( stderr, "No suitable EGL config found!\n" ); exit( 1 ); }
|
||||
|
||||
s_eglSurf = eglCreateWindowSurface( s_eglDpy, eglConfig, 0, nullptr );
|
||||
|
||||
constexpr EGLint eglCtxAttrib[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
s_eglCtx = eglCreateContext( s_eglDpy, eglConfig, EGL_NO_CONTEXT, eglCtxAttrib );
|
||||
if( !s_eglCtx ) { fprintf( stderr, "Cannot create OpenGL 3.2 Core Profile context!\n" ); exit( 1 ); }
|
||||
res = eglMakeCurrent( s_eglDpy, s_eglSurf, s_eglSurf, s_eglCtx );
|
||||
if( res != EGL_TRUE ) { fprintf( stderr, "Cannot make EGL context current!\n" ); exit( 1 ); }
|
||||
|
||||
ImGui_ImplOpenGL3_Init( "#version 100" );
|
||||
|
||||
EM_ASM( document.title = UTF8ToString($0), title );
|
||||
|
||||
s_redraw = redraw;
|
||||
s_scaleChanged = scaleChanged;
|
||||
s_isBusy = isBusy;
|
||||
s_mainThreadTasks = mainThreadTasks;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendPlatformName = "wasm (tracy profiler)";
|
||||
|
||||
emscripten_set_mousedown_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
|
||||
ImGui::GetIO().AddMouseButtonEvent( e->button == 0 ? 0 : 3 - e->button, true );
|
||||
tracy::s_wasActive = true;
|
||||
return EM_TRUE;
|
||||
} );
|
||||
emscripten_set_mouseup_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
|
||||
ImGui::GetIO().AddMouseButtonEvent( e->button == 0 ? 0 : 3 - e->button, false );
|
||||
tracy::s_wasActive = true;
|
||||
return EM_TRUE;
|
||||
} );
|
||||
emscripten_set_mousemove_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
|
||||
const auto scale = EM_ASM_DOUBLE( { return window.devicePixelRatio; } );
|
||||
ImGui::GetIO().AddMousePosEvent( e->targetX * scale, e->targetY * scale );
|
||||
tracy::s_wasActive = true;
|
||||
return EM_TRUE;
|
||||
} );
|
||||
emscripten_set_mouseleave_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent*, void* ) -> EM_BOOL {
|
||||
ImGui::GetIO().AddFocusEvent( false );
|
||||
tracy::s_wasActive = true;
|
||||
return EM_TRUE;
|
||||
} );
|
||||
emscripten_set_mouseenter_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent*, void* ) -> EM_BOOL {
|
||||
ImGui::GetIO().AddFocusEvent( true );
|
||||
tracy::s_wasActive = true;
|
||||
return EM_TRUE;
|
||||
} );
|
||||
emscripten_set_wheel_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenWheelEvent* e, void* ) -> EM_BOOL {
|
||||
ImGui::GetIO().AddMouseWheelEvent( e->deltaX * -0.05, e->deltaY * -0.05 );
|
||||
tracy::s_wasActive = true;
|
||||
return EM_TRUE;
|
||||
} );
|
||||
emscripten_set_keydown_callback( EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_TRUE, [] ( int, const EmscriptenKeyboardEvent* e, void* ) -> EM_BOOL {
|
||||
const auto code = TranslateKeyCode( e->code );
|
||||
if( code == ImGuiKey_None ) return EM_FALSE;
|
||||
ImGui::GetIO().AddKeyEvent( code, true );
|
||||
if( e->key[0] && !e->key[1] ) ImGui::GetIO().AddInputCharacter( *e->key );
|
||||
return EM_TRUE;
|
||||
} );
|
||||
emscripten_set_keyup_callback( EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_TRUE, [] ( int, const EmscriptenKeyboardEvent* e, void* ) -> EM_BOOL {
|
||||
const auto code = TranslateKeyCode( e->code );
|
||||
if( code == ImGuiKey_None ) return EM_FALSE;
|
||||
ImGui::GetIO().AddKeyEvent( code, false );
|
||||
return EM_TRUE;
|
||||
} );
|
||||
|
||||
s_time = std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
|
||||
}
|
||||
|
||||
Backend::~Backend()
|
||||
{
|
||||
}
|
||||
|
||||
void Backend::Show()
|
||||
{
|
||||
}
|
||||
|
||||
void Backend::Run()
|
||||
{
|
||||
emscripten_set_main_loop( []() {
|
||||
s_redraw();
|
||||
s_mainThreadTasks->Run();
|
||||
}, 0, 1 );
|
||||
}
|
||||
|
||||
void Backend::Attention()
|
||||
{
|
||||
}
|
||||
|
||||
void Backend::NewFrame( int& w, int& h )
|
||||
{
|
||||
const auto scale = GetDpiScale();
|
||||
if( scale != s_prevScale )
|
||||
{
|
||||
s_prevScale = scale;
|
||||
s_scaleChanged( scale );
|
||||
}
|
||||
|
||||
w = EM_ASM_INT( { return window.innerWidth; } ) * scale;
|
||||
h = EM_ASM_INT( { return window.innerHeight; } ) * scale;
|
||||
|
||||
if( s_width != w || s_height != h )
|
||||
{
|
||||
EM_ASM( Module.canvas.style.width = window.innerWidth + 'px'; Module.canvas.style.height = window.innerHeight + 'px' );
|
||||
EM_ASM( Module.canvas.width = $0; Module.canvas.height = $1, w, h );
|
||||
|
||||
s_width = w;
|
||||
s_height = h;
|
||||
|
||||
glViewport( 0, 0, s_width, s_height );
|
||||
tracy::s_wasActive = true;
|
||||
}
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2( w, h );
|
||||
io.DisplayFramebufferScale = ImVec2( 1, 1 );
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
|
||||
ImGuiMouseCursor cursor = ImGui::GetMouseCursor();
|
||||
const char* cursorName;
|
||||
switch( cursor )
|
||||
{
|
||||
case ImGuiMouseCursor_None: cursorName = "none"; break;
|
||||
case ImGuiMouseCursor_Arrow:
|
||||
switch( s_isBusy() )
|
||||
{
|
||||
default:
|
||||
case 0: cursorName = "default"; break;
|
||||
case 1: cursorName = "progress"; break;
|
||||
case 2: cursorName = "wait"; break;
|
||||
}
|
||||
break;
|
||||
case ImGuiMouseCursor_TextInput: cursorName = "text"; break;
|
||||
case ImGuiMouseCursor_ResizeAll: cursorName = "move"; break;
|
||||
case ImGuiMouseCursor_ResizeNS: cursorName = "ns-resize"; break;
|
||||
case ImGuiMouseCursor_ResizeEW: cursorName = "ew-resize"; break;
|
||||
case ImGuiMouseCursor_ResizeNESW: cursorName = "nesw-resize"; break;
|
||||
case ImGuiMouseCursor_ResizeNWSE: cursorName = "nwse-resize"; break;
|
||||
case ImGuiMouseCursor_Hand: cursorName = "pointer"; break;
|
||||
case ImGuiMouseCursor_NotAllowed: cursorName = "not-allowed"; break;
|
||||
default: cursorName = "auto"; break;
|
||||
};
|
||||
if( s_prevCursor != cursorName )
|
||||
{
|
||||
s_prevCursor = cursorName;
|
||||
EM_ASM_INT( { document.getElementById('canvas').style.cursor = UTF8ToString($0); }, cursorName );
|
||||
}
|
||||
|
||||
uint64_t time = std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
|
||||
io.DeltaTime = std::min( 0.1f, ( time - s_time ) / 1000000.f );
|
||||
s_time = time;
|
||||
}
|
||||
|
||||
void Backend::EndFrame()
|
||||
{
|
||||
const ImVec4 clear_color = ImColor( 20, 20, 17 );
|
||||
|
||||
ImGui::Render();
|
||||
glClearColor( clear_color.x, clear_color.y, clear_color.z, clear_color.w );
|
||||
glClear( GL_COLOR_BUFFER_BIT );
|
||||
ImGui_ImplOpenGL3_RenderDrawData( ImGui::GetDrawData() );
|
||||
}
|
||||
|
||||
void Backend::SetIcon( uint8_t* data, int w, int h )
|
||||
{
|
||||
}
|
||||
|
||||
void Backend::SetTitle( const char* title )
|
||||
{
|
||||
EM_ASM( document.title = UTF8ToString($0), title );
|
||||
}
|
||||
|
||||
float Backend::GetDpiScale()
|
||||
{
|
||||
return EM_ASM_DOUBLE( { return window.devicePixelRatio; } );
|
||||
}
|
@ -1,11 +1,6 @@
|
||||
#include "imgui/imgui_impl_glfw.h"
|
||||
#include "imgui/imgui_impl_opengl3.h"
|
||||
#ifdef __EMSCRIPTEN__
|
||||
# include <GLES2/gl2.h>
|
||||
# include <emscripten/html5.h>
|
||||
#else
|
||||
# include "imgui/imgui_impl_opengl3_loader.h"
|
||||
#endif
|
||||
#include <backends/imgui_impl_glfw.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <backends/imgui_impl_opengl3_loader.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <GLFW/glfw3.h>
|
||||
@ -22,9 +17,11 @@
|
||||
|
||||
static GLFWwindow* s_window;
|
||||
static std::function<void()> s_redraw;
|
||||
static std::function<void(float)> s_scaleChanged;
|
||||
static RunQueue* s_mainThreadTasks;
|
||||
static WindowPosition* s_winPos;
|
||||
static bool s_iconified;
|
||||
static float s_prevScale = -1;
|
||||
|
||||
extern tracy::Config s_config;
|
||||
|
||||
@ -83,6 +80,9 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
||||
# if GLFW_VERSION_MAJOR > 3 || ( GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 4 )
|
||||
glfwWindowHint( GLFW_WIN32_KEYBOARD_MENU, 1 );
|
||||
# endif
|
||||
# if GLFW_VERSION_MAJOR > 3 || ( GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3 )
|
||||
glfwWindowHint( GLFW_SCALE_TO_MONITOR, 1 );
|
||||
# endif
|
||||
#endif
|
||||
s_window = glfwCreateWindow( m_winPos.w, m_winPos.h, title, NULL, NULL );
|
||||
if( !s_window ) exit( 1 );
|
||||
@ -97,13 +97,10 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
||||
glfwSetWindowRefreshCallback( s_window, []( GLFWwindow* ) { tracy::s_wasActive = true; s_redraw(); } );
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL( s_window, true );
|
||||
#ifdef __EMSCRIPTEN__
|
||||
ImGui_ImplOpenGL3_Init( "#version 100" );
|
||||
#else
|
||||
ImGui_ImplOpenGL3_Init( "#version 150" );
|
||||
#endif
|
||||
|
||||
s_redraw = redraw;
|
||||
s_scaleChanged = scaleChanged;
|
||||
s_mainThreadTasks = mainThreadTasks;
|
||||
s_winPos = &m_winPos;
|
||||
s_iconified = false;
|
||||
@ -133,13 +130,6 @@ void Backend::Show()
|
||||
|
||||
void Backend::Run()
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_main_loop( []() {
|
||||
glfwPollEvents();
|
||||
s_redraw();
|
||||
s_mainThreadTasks->Run();
|
||||
}, 0, 1 );
|
||||
#else
|
||||
while( !glfwWindowShouldClose( s_window ) )
|
||||
{
|
||||
if( s_iconified )
|
||||
@ -154,7 +144,6 @@ void Backend::Run()
|
||||
s_mainThreadTasks->Run();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Backend::Attention()
|
||||
@ -169,6 +158,13 @@ void Backend::Attention()
|
||||
|
||||
void Backend::NewFrame( int& w, int& h )
|
||||
{
|
||||
const auto scale = GetDpiScale();
|
||||
if( scale != s_prevScale )
|
||||
{
|
||||
s_prevScale = scale;
|
||||
s_scaleChanged( scale );
|
||||
}
|
||||
|
||||
glfwGetFramebufferSize( s_window, &w, &h );
|
||||
m_w = w;
|
||||
m_h = h;
|
||||
@ -206,25 +202,11 @@ void Backend::SetTitle( const char* title )
|
||||
|
||||
float Backend::GetDpiScale()
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return EM_ASM_DOUBLE( { return window.devicePixelRatio; } );
|
||||
#elif GLFW_VERSION_MAJOR > 3 || ( GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3 )
|
||||
auto monitor = glfwGetWindowMonitor( s_window );
|
||||
if( !monitor ) monitor = glfwGetPrimaryMonitor();
|
||||
if( monitor )
|
||||
{
|
||||
float x, y;
|
||||
glfwGetMonitorContentScale( monitor, &x, &y );
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
#if GLFW_VERSION_MAJOR > 3 || ( GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3 )
|
||||
float x, y;
|
||||
glfwGetWindowContentScale( s_window, &x, &y );
|
||||
return x;
|
||||
#else
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
extern "C" int nativeResize( int width, int height )
|
||||
{
|
||||
glfwSetWindowSize( s_window, width, height );
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "imgui/imgui_impl_opengl3.h"
|
||||
#include "imgui/imgui_impl_opengl3_loader.h"
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <backends/imgui_impl_opengl3_loader.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
@ -25,8 +25,10 @@
|
||||
#include "wayland-fractional-scale-client-protocol.h"
|
||||
#include "wayland-viewporter-client-protocol.h"
|
||||
#include "wayland-cursor-shape-client-protocol.h"
|
||||
#include "wayland-xdg-toplevel-icon-client-protocol.h"
|
||||
|
||||
#include "profiler/TracyImGui.hpp"
|
||||
#include "stb_image_resize.h"
|
||||
|
||||
#include "Backend.hpp"
|
||||
#include "RunQueue.hpp"
|
||||
@ -205,6 +207,16 @@ static xkb_mod_index_t s_xkbCtrl, s_xkbAlt, s_xkbShift, s_xkbSuper;
|
||||
static wp_cursor_shape_device_v1_shape s_mouseCursor;
|
||||
static uint32_t s_mouseCursorSerial;
|
||||
static bool s_hasFocus = false;
|
||||
static struct wl_data_device_manager* s_dataDevMgr;
|
||||
static struct wl_data_device* s_dataDev;
|
||||
static struct wl_data_source* s_dataSource;
|
||||
static uint32_t s_dataSerial;
|
||||
static std::string s_clipboard, s_clipboardIncoming;
|
||||
static struct wl_data_offer* s_dataOffer;
|
||||
static struct wl_data_offer* s_newDataOffer;
|
||||
static bool s_newDataOfferValid;
|
||||
static struct xdg_toplevel_icon_manager_v1* s_iconMgr;
|
||||
static std::vector<int> s_iconSizes;
|
||||
|
||||
struct Output
|
||||
{
|
||||
@ -214,7 +226,7 @@ struct Output
|
||||
};
|
||||
static std::unordered_map<uint32_t, std::unique_ptr<Output>> s_output;
|
||||
static int s_maxScale = 120;
|
||||
static int s_prevScale = 120;
|
||||
static int s_prevScale = -1;
|
||||
|
||||
static bool s_running = true;
|
||||
static int s_width, s_height;
|
||||
@ -233,7 +245,7 @@ static void RecomputeScale()
|
||||
if( s_fracSurf ) return;
|
||||
|
||||
// On wl_compositor >= 6 the scale is sent explicitly via wl_surface.preferred_buffer_scale.
|
||||
if ( s_comp_version >= 6 ) return;
|
||||
if( s_comp_version >= 6 ) return;
|
||||
|
||||
int max = 1;
|
||||
for( auto& out : s_output )
|
||||
@ -391,6 +403,12 @@ static void KeyboardEnter( void*, struct wl_keyboard* kbd, uint32_t serial, stru
|
||||
|
||||
static void KeyboardLeave( void*, struct wl_keyboard* kbd, uint32_t serial, struct wl_surface* surf )
|
||||
{
|
||||
if( s_dataOffer )
|
||||
{
|
||||
wl_data_offer_destroy( s_dataOffer );
|
||||
s_dataOffer = nullptr;
|
||||
}
|
||||
|
||||
ImGui::GetIO().AddFocusEvent( false );
|
||||
s_hasFocus = false;
|
||||
}
|
||||
@ -432,6 +450,7 @@ static void KeyboardKey( void*, struct wl_keyboard* kbd, uint32_t serial, uint32
|
||||
ImGui::GetIO().AddInputCharactersUTF8( txt );
|
||||
}
|
||||
}
|
||||
s_dataSerial = serial;
|
||||
}
|
||||
}
|
||||
|
||||
@ -551,6 +570,21 @@ constexpr struct zxdg_toplevel_decoration_v1_listener decorationListener = {
|
||||
};
|
||||
|
||||
|
||||
static void IconMgrSize( void*, struct xdg_toplevel_icon_manager_v1*, int32_t size )
|
||||
{
|
||||
s_iconSizes.push_back( size );
|
||||
}
|
||||
|
||||
static void IconMgrDone( void*, struct xdg_toplevel_icon_manager_v1* )
|
||||
{
|
||||
}
|
||||
|
||||
constexpr struct xdg_toplevel_icon_manager_v1_listener iconMgrListener = {
|
||||
.icon_size = IconMgrSize,
|
||||
.done = IconMgrDone
|
||||
};
|
||||
|
||||
|
||||
static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const char* interface, uint32_t version )
|
||||
{
|
||||
if( strcmp( interface, wl_compositor_interface.name ) == 0 )
|
||||
@ -600,6 +634,15 @@ static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const
|
||||
s_cursorShape = (wp_cursor_shape_manager_v1*)wl_registry_bind( reg, name, &wp_cursor_shape_manager_v1_interface, 1 );
|
||||
if( s_pointer ) s_cursorShapeDev = wp_cursor_shape_manager_v1_get_pointer( s_cursorShape, s_pointer );
|
||||
}
|
||||
else if( strcmp( interface, wl_data_device_manager_interface.name ) == 0 )
|
||||
{
|
||||
s_dataDevMgr = (wl_data_device_manager*)wl_registry_bind( reg, name, &wl_data_device_manager_interface, 2 );
|
||||
}
|
||||
else if( strcmp( interface, xdg_toplevel_icon_manager_v1_interface.name ) == 0 )
|
||||
{
|
||||
s_iconMgr = (xdg_toplevel_icon_manager_v1*)wl_registry_bind( reg, name, &xdg_toplevel_icon_manager_v1_interface, 1 );
|
||||
xdg_toplevel_icon_manager_v1_add_listener( s_iconMgr, &iconMgrListener, nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
static void RegistryGlobalRemove( void*, struct wl_registry* reg, uint32_t name )
|
||||
@ -713,6 +756,126 @@ constexpr struct wp_fractional_scale_v1_listener fractionalListener = {
|
||||
};
|
||||
|
||||
|
||||
static void DataOfferOffer( void*, struct wl_data_offer* offer, const char* mimeType )
|
||||
{
|
||||
assert( s_newDataOffer == offer );
|
||||
|
||||
if( strcmp( mimeType, "text/plain" ) == 0 )
|
||||
{
|
||||
wl_data_offer_accept( offer, 0, mimeType );
|
||||
s_newDataOfferValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
wl_data_offer_accept( offer, 0, nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
static void DataOfferSourceActions( void*, struct wl_data_offer* offer, uint32_t sourceActions )
|
||||
{
|
||||
}
|
||||
|
||||
static void DataOfferAction( void*, struct wl_data_offer* offer, uint32_t dndAction )
|
||||
{
|
||||
}
|
||||
|
||||
constexpr struct wl_data_offer_listener dataOfferListener = {
|
||||
.offer = DataOfferOffer,
|
||||
.source_actions = DataOfferSourceActions,
|
||||
.action = DataOfferAction
|
||||
};
|
||||
|
||||
|
||||
static void DataDeviceDataOffer( void*, struct wl_data_device* dataDevice, struct wl_data_offer* offer )
|
||||
{
|
||||
s_newDataOffer = offer;
|
||||
wl_data_offer_add_listener( offer, &dataOfferListener, nullptr );
|
||||
s_newDataOfferValid = false;
|
||||
}
|
||||
|
||||
static void DataDeviceEnter( void*, struct wl_data_device* dataDevice, uint32_t serial, struct wl_surface* surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer* offer )
|
||||
{
|
||||
if( s_newDataOffer )
|
||||
{
|
||||
wl_data_offer_destroy( s_newDataOffer );
|
||||
s_newDataOffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void DataDeviceLeave( void*, struct wl_data_device* dataDevice )
|
||||
{
|
||||
}
|
||||
|
||||
static void DataDeviceMotion( void*, struct wl_data_device* dataDevice, uint32_t time, wl_fixed_t x, wl_fixed_t y )
|
||||
{
|
||||
}
|
||||
|
||||
static void DataDeviceSelection( void*, struct wl_data_device* dataDevice, struct wl_data_offer* offer )
|
||||
{
|
||||
if( s_dataOffer ) wl_data_offer_destroy( s_dataOffer );
|
||||
if( offer )
|
||||
{
|
||||
if( s_newDataOfferValid )
|
||||
{
|
||||
s_dataOffer = s_newDataOffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( s_newDataOffer ) wl_data_offer_destroy( s_newDataOffer );
|
||||
s_dataOffer = nullptr;
|
||||
}
|
||||
s_newDataOffer = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_dataOffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr struct wl_data_device_listener dataDeviceListener = {
|
||||
.data_offer = DataDeviceDataOffer,
|
||||
.enter = DataDeviceEnter,
|
||||
.leave = DataDeviceLeave,
|
||||
.motion = DataDeviceMotion,
|
||||
.selection = DataDeviceSelection
|
||||
};
|
||||
|
||||
|
||||
void DataSourceTarget( void*, struct wl_data_source* dataSource, const char* mimeType )
|
||||
{
|
||||
}
|
||||
|
||||
void DataSourceSend( void*, struct wl_data_source* dataSource, const char* mimeType, int32_t fd )
|
||||
{
|
||||
if( !s_clipboard.empty() )
|
||||
{
|
||||
auto len = s_clipboard.size();
|
||||
auto ptr = s_clipboard.data();
|
||||
while( len > 0 )
|
||||
{
|
||||
auto sz = write( fd, ptr, len );
|
||||
if( sz < 0 ) break;
|
||||
len -= sz;
|
||||
ptr += sz;
|
||||
}
|
||||
}
|
||||
close( fd );
|
||||
}
|
||||
|
||||
void DataSourceCancelled( void*, struct wl_data_source* dataSource )
|
||||
{
|
||||
s_clipboard.clear();
|
||||
wl_data_source_destroy( s_dataSource );
|
||||
s_dataSource = nullptr;
|
||||
}
|
||||
|
||||
constexpr struct wl_data_source_listener dataSourceListener = {
|
||||
.target = DataSourceTarget,
|
||||
.send = DataSourceSend,
|
||||
.cancelled = DataSourceCancelled
|
||||
};
|
||||
|
||||
|
||||
static void SetupCursor()
|
||||
{
|
||||
if( s_cursorShape ) return;
|
||||
@ -736,6 +899,39 @@ static void SetupCursor()
|
||||
s_cursorY = cursor->images[0]->hotspot_y * 120 / s_maxScale;
|
||||
}
|
||||
|
||||
static void SetClipboard( void*, const char* text )
|
||||
{
|
||||
s_clipboard = text;
|
||||
|
||||
if( s_dataSource ) wl_data_source_destroy( s_dataSource );
|
||||
s_dataSource = wl_data_device_manager_create_data_source( s_dataDevMgr );
|
||||
wl_data_source_add_listener( s_dataSource, &dataSourceListener, nullptr );
|
||||
wl_data_source_offer( s_dataSource, "text/plain" );
|
||||
wl_data_device_set_selection( s_dataDev, s_dataSource, s_dataSerial );
|
||||
}
|
||||
|
||||
static const char* GetClipboard( void* )
|
||||
{
|
||||
if( !s_dataOffer ) return nullptr;
|
||||
int fd[2];
|
||||
if( pipe( fd ) != 0 ) return nullptr;
|
||||
wl_data_offer_receive( s_dataOffer, "text/plain", fd[1] );
|
||||
close( fd[1] );
|
||||
wl_display_roundtrip( s_dpy );
|
||||
|
||||
s_clipboardIncoming.clear();
|
||||
char buf[4096];
|
||||
while( true )
|
||||
{
|
||||
auto len = read( fd[0], buf, sizeof( buf ) );
|
||||
if( len <= 0 ) break;
|
||||
s_clipboardIncoming.append( buf, len );
|
||||
}
|
||||
|
||||
close( fd[0] );
|
||||
return s_clipboardIncoming.c_str();
|
||||
}
|
||||
|
||||
Backend::Backend( const char* title, const std::function<void()>& redraw, const std::function<void(float)>& scaleChanged, const std::function<int(void)>& isBusy, RunQueue* mainThreadTasks )
|
||||
{
|
||||
s_redraw = redraw;
|
||||
@ -818,6 +1014,16 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
||||
xdg_toplevel_set_title( s_toplevel, title );
|
||||
xdg_toplevel_set_app_id( s_toplevel, "tracy" );
|
||||
|
||||
if( s_activation )
|
||||
{
|
||||
const char* token = getenv( "XDG_ACTIVATION_TOKEN" );
|
||||
if( token )
|
||||
{
|
||||
xdg_activation_v1_activate( s_activation, token, s_surf );
|
||||
unsetenv( "XDG_ACTIVATION_TOKEN" );
|
||||
}
|
||||
}
|
||||
|
||||
if( s_decoration )
|
||||
{
|
||||
s_tldec = zxdg_decoration_manager_v1_get_toplevel_decoration( s_decoration, s_toplevel );
|
||||
@ -828,6 +1034,16 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, const
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendPlatformName = "wayland (tracy profiler)";
|
||||
|
||||
if( s_dataDevMgr )
|
||||
{
|
||||
s_dataDev = wl_data_device_manager_get_data_device( s_dataDevMgr, s_seat );
|
||||
wl_data_device_add_listener( s_dataDev, &dataDeviceListener, nullptr );
|
||||
|
||||
io.SetClipboardTextFn = SetClipboard;
|
||||
io.GetClipboardTextFn = GetClipboard;
|
||||
}
|
||||
|
||||
s_time = std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
|
||||
}
|
||||
|
||||
@ -835,6 +1051,11 @@ Backend::~Backend()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
|
||||
if( s_iconMgr ) xdg_toplevel_icon_manager_v1_destroy( s_iconMgr );
|
||||
if( s_dataOffer ) wl_data_offer_destroy( s_dataOffer );
|
||||
if( s_dataSource ) wl_data_source_destroy( s_dataSource );
|
||||
if( s_dataDev ) wl_data_device_destroy( s_dataDev );
|
||||
if( s_dataDevMgr ) wl_data_device_manager_destroy( s_dataDevMgr );
|
||||
if( s_cursorShapeDev ) wp_cursor_shape_device_v1_destroy( s_cursorShapeDev );
|
||||
if( s_cursorShape ) wp_cursor_shape_manager_v1_destroy( s_cursorShape );
|
||||
if( s_viewport ) wp_viewport_destroy( s_viewport );
|
||||
@ -995,6 +1216,7 @@ void Backend::NewFrame( int& w, int& h )
|
||||
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED;
|
||||
break;
|
||||
default:
|
||||
shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
|
||||
break;
|
||||
};
|
||||
|
||||
@ -1028,6 +1250,62 @@ void Backend::EndFrame()
|
||||
|
||||
void Backend::SetIcon( uint8_t* data, int w, int h )
|
||||
{
|
||||
if( !s_iconMgr ) return;
|
||||
if( s_iconSizes.empty() ) return;
|
||||
|
||||
size_t size = 0;
|
||||
for( auto sz : s_iconSizes )
|
||||
{
|
||||
size += sz * sz;
|
||||
}
|
||||
size *= 4;
|
||||
|
||||
auto path = getenv( "XDG_RUNTIME_DIR" );
|
||||
if( !path ) return;
|
||||
|
||||
std::string shmPath = path;
|
||||
shmPath += "/tracy_icon-XXXXXX";
|
||||
int fd = mkstemp( shmPath.data() );
|
||||
if( fd < 0 ) return;
|
||||
unlink( shmPath.data() );
|
||||
ftruncate( fd, size );
|
||||
auto membuf = (char*)mmap( nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
|
||||
if( membuf == MAP_FAILED )
|
||||
{
|
||||
close( fd );
|
||||
return;
|
||||
}
|
||||
|
||||
auto pool = wl_shm_create_pool( s_shm, fd, size );
|
||||
close( fd );
|
||||
auto icon = xdg_toplevel_icon_manager_v1_create_icon( s_iconMgr );
|
||||
|
||||
auto rgb = new uint32_t[w * h];
|
||||
auto bgr = (uint32_t*)data;
|
||||
for( int i=0; i<w*h; i++ )
|
||||
{
|
||||
rgb[i] = ( bgr[i] & 0xff00ff00 ) | ( ( bgr[i] & 0xff ) << 16 ) | ( ( bgr[i] >> 16 ) & 0xff );
|
||||
}
|
||||
|
||||
std::vector<wl_buffer*> bufs;
|
||||
int32_t offset = 0;
|
||||
for( auto sz : s_iconSizes )
|
||||
{
|
||||
auto buffer = wl_shm_pool_create_buffer( pool, offset, sz, sz, sz * 4, WL_SHM_FORMAT_ARGB8888 );
|
||||
bufs.push_back( buffer );
|
||||
|
||||
auto ptr = membuf + offset;
|
||||
offset += sz * sz * 4;
|
||||
|
||||
stbir_resize_uint8( (uint8_t*)rgb, w, h, 0, (uint8_t*)ptr, sz, sz, 0, 4 );
|
||||
xdg_toplevel_icon_v1_add_buffer( icon, buffer, sz );
|
||||
}
|
||||
|
||||
xdg_toplevel_icon_manager_v1_set_icon( s_iconMgr, s_toplevel, icon );
|
||||
xdg_toplevel_icon_v1_destroy( icon );
|
||||
for( auto buf : bufs ) wl_buffer_destroy( buf );
|
||||
munmap( membuf, size );
|
||||
wl_shm_pool_destroy( pool );
|
||||
}
|
||||
|
||||
void Backend::SetTitle( const char* title )
|
||||
|
@ -65,17 +65,16 @@ void ConnectionHistory::Rebuild()
|
||||
std::swap( m_connHistVec, vec );
|
||||
}
|
||||
|
||||
void ConnectionHistory::Count( const char* name )
|
||||
void ConnectionHistory::Count( const std::string& name )
|
||||
{
|
||||
std::string addr( name );
|
||||
auto it = m_connHistMap.find( addr );
|
||||
auto it = m_connHistMap.find( name );
|
||||
if( it != m_connHistMap.end() )
|
||||
{
|
||||
it->second++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_connHistMap.emplace( std::move( addr ), 1 );
|
||||
m_connHistMap.emplace( name, 1 );
|
||||
}
|
||||
Rebuild();
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ public:
|
||||
|
||||
const std::string& Name( size_t idx ) const { return m_connHistVec[idx]->first; }
|
||||
|
||||
void Count( const char* name );
|
||||
void Count( const std::string& name );
|
||||
void Erase( size_t idx );
|
||||
|
||||
bool empty() const { return m_connHistVec.empty(); }
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include <imgui.h>
|
||||
#include <math.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <misc/freetype/imgui_freetype.h>
|
||||
|
||||
#include "Fonts.hpp"
|
||||
#include "misc/freetype/imgui_freetype.h"
|
||||
#include "imgui/imgui_impl_opengl3.h"
|
||||
#include "profiler/IconsFontAwesome6.h"
|
||||
|
||||
#include "font/DroidSans.hpp"
|
||||
|
@ -5,11 +5,14 @@
|
||||
|
||||
#include "../public/common/TracySocket.hpp"
|
||||
#include "../public/common/TracyVersion.hpp"
|
||||
#include "GitRef.hpp"
|
||||
#include "HttpRequest.hpp"
|
||||
|
||||
#if defined _WIN32
|
||||
# include <windows.h>
|
||||
extern "C" typedef LONG (WINAPI *t_RtlGetVersion)( PRTL_OSVERSIONINFOW );
|
||||
extern "C" typedef char* (WINAPI *t_WineGetVersion)();
|
||||
extern "C" typedef char* (WINAPI *t_WineGetBuildId)();
|
||||
#elif defined __linux__
|
||||
# include <sys/utsname.h>
|
||||
#elif defined __APPLE__
|
||||
@ -39,7 +42,16 @@ static const char* GetOsInfo()
|
||||
# ifdef __MINGW32__
|
||||
sprintf( buf, "Windows %i.%i.%i (MingW)", (int)ver.dwMajorVersion, (int)ver.dwMinorVersion, (int)ver.dwBuildNumber );
|
||||
# else
|
||||
sprintf( buf, "Windows %i.%i.%i", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber );
|
||||
auto WineGetVersion = (t_WineGetVersion)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "wine_get_version" );
|
||||
auto WineGetBuildId = (t_WineGetBuildId)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "wine_get_build_id" );
|
||||
if( WineGetVersion && WineGetBuildId )
|
||||
{
|
||||
sprintf( buf, "Windows %i.%i.%i (Wine %s [%s])", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, WineGetVersion(), WineGetBuildId() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( buf, "Windows %i.%i.%i", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber );
|
||||
}
|
||||
# endif
|
||||
}
|
||||
#elif defined __linux__
|
||||
@ -79,7 +91,7 @@ void HttpRequest( const char* server, const char* resource, int port, const std:
|
||||
tracy::Socket sock;
|
||||
if( !sock.ConnectBlocking( server, port ) ) return;
|
||||
char request[4096];
|
||||
const auto len = sprintf( request, "GET %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Tracy Profiler %i.%i.%i (%s)\r\nConnection: close\r\nCache-Control: no-cache, no-store, must-revalidate\r\n\r\n", resource, server, tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, GetOsInfo() );
|
||||
const auto len = sprintf( request, "GET %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Tracy Profiler %i.%i.%i (%s) [%s]\r\nConnection: close\r\nCache-Control: no-cache, no-store, must-revalidate\r\n\r\n", resource, server, tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, GetOsInfo(), tracy::GitRef );
|
||||
sock.Send( request, len );
|
||||
char response[4096];
|
||||
const auto sz = sock.ReadUpTo( response, 4096 );
|
||||
|
@ -11,6 +11,7 @@ ImGuiTracyContext::ImGuiTracyContext()
|
||||
io.IniFilename = m_iniFilename.c_str();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_DockingEnable;
|
||||
io.ConfigInputTextCursorBlink = false;
|
||||
io.ConfigScrollbarScrollByPage = false;
|
||||
}
|
||||
|
||||
ImGuiTracyContext::~ImGuiTracyContext()
|
||||
|
@ -14,22 +14,28 @@
|
||||
ResolvService::ResolvService( uint16_t port )
|
||||
: m_exit( false )
|
||||
, m_port( port )
|
||||
#ifndef __EMSCRIPTEN__
|
||||
, m_thread( [this] { Worker(); } )
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
ResolvService::~ResolvService()
|
||||
{
|
||||
#ifndef __EMSCRIPTEN__
|
||||
m_exit.store( true, std::memory_order_relaxed );
|
||||
m_cv.notify_one();
|
||||
m_thread.join();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ResolvService::Query( uint32_t ip, const std::function<void(std::string&&)>& callback )
|
||||
{
|
||||
#ifndef __EMSCRIPTEN__
|
||||
std::lock_guard<std::mutex> lock( m_lock );
|
||||
m_queue.emplace_back( QueueItem { ip, callback } );
|
||||
m_cv.notify_one();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ResolvService::Worker()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,62 +0,0 @@
|
||||
// dear imgui: Platform Backend for GLFW
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
|
||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||
// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only).
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// Issues:
|
||||
// [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
struct GLFWwindow;
|
||||
struct GLFWmonitor;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
|
||||
|
||||
// Emscripten related initialization phase methods
|
||||
#ifdef __EMSCRIPTEN__
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_selector);
|
||||
#endif
|
||||
|
||||
// GLFW callbacks install
|
||||
// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any.
|
||||
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks.
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window);
|
||||
|
||||
// GFLW callbacks options:
|
||||
// - Set 'chain_for_all_windows=true' to enable chaining callbacks for all windows (including secondary viewports created by backends or by user)
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows);
|
||||
|
||||
// GLFW callbacks (individual callbacks to call yourself if you didn't install callbacks)
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
@ -1,996 +0,0 @@
|
||||
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
|
||||
// - Desktop GL: 2.x 3.x 4.x
|
||||
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// About WebGL/ES:
|
||||
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
|
||||
// - This is done automatically on iOS, Android and Emscripten targets.
|
||||
// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2024-05-07: OpenGL: Update loader for Linux to support EGL/GLVND. (#7562)
|
||||
// 2024-04-16: OpenGL: Detect ES3 contexts on desktop based on version string, to e.g. avoid calling glPolygonMode() on them. (#7447)
|
||||
// 2024-01-09: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" and variants, fixing regression on distros missing a symlink.
|
||||
// 2023-11-08: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" instead of "libGL.so.1", accommodating for NetBSD systems having only "libGL.so.3" available. (#6983)
|
||||
// 2023-10-05: OpenGL: Rename symbols in our internal loader so that LTO compilation with another copy of gl3w is possible. (#6875, #6668, #4445)
|
||||
// 2023-06-20: OpenGL: Fixed erroneous use glGetIntegerv(GL_CONTEXT_PROFILE_MASK) on contexts lower than 3.2. (#6539, #6333)
|
||||
// 2023-05-09: OpenGL: Support for glBindSampler() backup/restore on ES3. (#6375)
|
||||
// 2023-04-18: OpenGL: Restore front and back polygon mode separately when supported by context. (#6333)
|
||||
// 2023-03-23: OpenGL: Properly restoring "no shader program bound" if it was the case prior to running the rendering function. (#6267, #6220, #6224)
|
||||
// 2023-03-15: OpenGL: Fixed GL loader crash when GL_VERSION returns NULL. (#6154, #4445, #3530)
|
||||
// 2023-03-06: OpenGL: Fixed restoration of a potentially deleted OpenGL program, by calling glIsProgram(). (#6220, #6224)
|
||||
// 2022-11-09: OpenGL: Reverted use of glBufferSubData(), too many corruptions issues + old issues seemingly can't be reproed with Intel drivers nowadays (revert 2021-12-15 and 2022-05-23 changes).
|
||||
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||
// 2022-09-27: OpenGL: Added ability to '#define IMGUI_IMPL_OPENGL_DEBUG'.
|
||||
// 2022-05-23: OpenGL: Reworking 2021-12-15 "Using buffer orphaning" so it only happens on Intel GPU, seems to cause problems otherwise. (#4468, #4825, #4832, #5127).
|
||||
// 2022-05-13: OpenGL: Fixed state corruption on OpenGL ES 2.0 due to not preserving GL_ELEMENT_ARRAY_BUFFER_BINDING and vertex attribute states.
|
||||
// 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
|
||||
// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
|
||||
// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
|
||||
// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader.
|
||||
// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
|
||||
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
|
||||
// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
|
||||
// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
|
||||
// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
|
||||
// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
|
||||
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
|
||||
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
|
||||
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
|
||||
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
|
||||
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
|
||||
// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
|
||||
// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
|
||||
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
|
||||
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
|
||||
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
|
||||
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
|
||||
// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
|
||||
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
|
||||
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
|
||||
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
|
||||
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
|
||||
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
|
||||
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
|
||||
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
|
||||
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
|
||||
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a nullptr pointer.
|
||||
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
|
||||
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
|
||||
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
|
||||
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
|
||||
|
||||
//----------------------------------------
|
||||
// OpenGL GLSL GLSL
|
||||
// version version string
|
||||
//----------------------------------------
|
||||
// 2.0 110 "#version 110"
|
||||
// 2.1 120 "#version 120"
|
||||
// 3.0 130 "#version 130"
|
||||
// 3.1 140 "#version 140"
|
||||
// 3.2 150 "#version 150"
|
||||
// 3.3 330 "#version 330 core"
|
||||
// 4.0 400 "#version 400 core"
|
||||
// 4.1 410 "#version 410 core"
|
||||
// 4.2 420 "#version 410 core"
|
||||
// 4.3 430 "#version 430 core"
|
||||
// ES 2.0 100 "#version 100" = WebGL 1.0
|
||||
// ES 3.0 300 "#version 300 es" = WebGL 2.0
|
||||
//----------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h> // intptr_t
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
// Clang/GCC warnings with -Weverything
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used
|
||||
#pragma clang diagnostic ignored "-Wnonportable-system-include-path"
|
||||
#pragma clang diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx'
|
||||
#pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
|
||||
#endif
|
||||
|
||||
// GL includes
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||
#include <OpenGLES/ES2/gl.h> // Use GL ES 2
|
||||
#else
|
||||
#include <GLES2/gl2.h> // Use GL ES 2
|
||||
#endif
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#ifndef GL_GLEXT_PROTOTYPES
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#endif
|
||||
#include <GLES2/gl2ext.h>
|
||||
#endif
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
|
||||
#else
|
||||
#include <GLES3/gl3.h> // Use GL ES 3
|
||||
#endif
|
||||
#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||
// Helper libraries are often used for this purpose! Here we are using our own minimal custom loader based on gl3w.
|
||||
// In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.).
|
||||
// If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp):
|
||||
// - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped
|
||||
// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
|
||||
// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
|
||||
#define IMGL3W_IMPL
|
||||
#include "imgui_impl_opengl3_loader.h"
|
||||
#endif
|
||||
|
||||
// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
#define glBindVertexArray glBindVertexArrayOES
|
||||
#define glGenVertexArrays glGenVertexArraysOES
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysOES
|
||||
#define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES
|
||||
#endif
|
||||
|
||||
// Desktop GL 2.0+ has extension and glPolygonMode() which GL ES and WebGL don't have..
|
||||
// A desktop ES context can technically compile fine with our loader, so we also perform a runtime checks
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
#define IMGUI_IMPL_OPENGL_HAS_EXTENSIONS // has glGetIntegerv(GL_NUM_EXTENSIONS)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE // may have glPolygonMode()
|
||||
#endif
|
||||
|
||||
// Desktop GL 2.1+ and GL ES 3.0+ have glBindBuffer() with GL_PIXEL_UNPACK_BUFFER target.
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_BUFFER_PIXEL_UNPACK
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.3+ and GL ES 3.0+ have glBindSampler()
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && (defined(IMGUI_IMPL_OPENGL_ES3) || defined(GL_VERSION_3_3))
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
#endif
|
||||
|
||||
// [Debugging]
|
||||
//#define IMGUI_IMPL_OPENGL_DEBUG
|
||||
#ifdef IMGUI_IMPL_OPENGL_DEBUG
|
||||
#include <stdio.h>
|
||||
#define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check
|
||||
#else
|
||||
#define GL_CALL(_CALL) _CALL // Call without error check
|
||||
#endif
|
||||
|
||||
// OpenGL Data
|
||||
struct ImGui_ImplOpenGL3_Data
|
||||
{
|
||||
GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||
char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
|
||||
bool GlProfileIsES2;
|
||||
bool GlProfileIsES3;
|
||||
bool GlProfileIsCompat;
|
||||
GLint GlProfileMask;
|
||||
GLuint FontTexture;
|
||||
GLuint ShaderHandle;
|
||||
GLint AttribLocationTex; // Uniforms location
|
||||
GLint AttribLocationProjMtx;
|
||||
GLuint AttribLocationVtxPos; // Vertex attributes location
|
||||
GLuint AttribLocationVtxUV;
|
||||
GLuint AttribLocationVtxColor;
|
||||
unsigned int VboHandle, ElementsHandle;
|
||||
GLsizeiptr VertexBufferSize;
|
||||
GLsizeiptr IndexBufferSize;
|
||||
bool HasPolygonMode;
|
||||
bool HasClipOrigin;
|
||||
bool UseBufferSubData;
|
||||
|
||||
ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplOpenGL3_InitPlatformInterface();
|
||||
static void ImGui_ImplOpenGL3_ShutdownPlatformInterface();
|
||||
|
||||
// OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only)
|
||||
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
struct ImGui_ImplOpenGL3_VtxAttribState
|
||||
{
|
||||
GLint Enabled, Size, Type, Normalized, Stride;
|
||||
GLvoid* Ptr;
|
||||
|
||||
void GetState(GLint index)
|
||||
{
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &Enabled);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_SIZE, &Size);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_TYPE, &Type);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &Normalized);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &Stride);
|
||||
glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &Ptr);
|
||||
}
|
||||
void SetState(GLint index)
|
||||
{
|
||||
glVertexAttribPointer(index, Size, Type, (GLboolean)Normalized, Stride, Ptr);
|
||||
if (Enabled) glEnableVertexAttribArray(index); else glDisableVertexAttribArray(index);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IMGUI_CHECKVERSION();
|
||||
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||
|
||||
// Initialize our loader
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
if (imgl3wInit() != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to initialize OpenGL loader!\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_opengl3";
|
||||
|
||||
// Query for GL version (e.g. 320 for GL 3.2)
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
// GLES 2
|
||||
bd->GlVersion = 200;
|
||||
bd->GlProfileIsES2 = true;
|
||||
#else
|
||||
// Desktop or GLES 3
|
||||
const char* gl_version_str = (const char*)glGetString(GL_VERSION);
|
||||
GLint major = 0;
|
||||
GLint minor = 0;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||
if (major == 0 && minor == 0)
|
||||
sscanf(gl_version_str, "%d.%d", &major, &minor); // Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
|
||||
bd->GlVersion = (GLuint)(major * 100 + minor * 10);
|
||||
#if defined(GL_CONTEXT_PROFILE_MASK)
|
||||
if (bd->GlVersion >= 320)
|
||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask);
|
||||
bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0;
|
||||
#endif
|
||||
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
bd->GlProfileIsES3 = true;
|
||||
#else
|
||||
if (strncmp(gl_version_str, "OpenGL ES 3", 11) == 0)
|
||||
bd->GlProfileIsES3 = true;
|
||||
#endif
|
||||
|
||||
bd->UseBufferSubData = false;
|
||||
/*
|
||||
// Query vendor to enable glBufferSubData kludge
|
||||
#ifdef _WIN32
|
||||
if (const char* vendor = (const char*)glGetString(GL_VENDOR))
|
||||
if (strncmp(vendor, "Intel", 5) == 0)
|
||||
bd->UseBufferSubData = true;
|
||||
#endif
|
||||
*/
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_DEBUG
|
||||
printf("GlVersion = %d, \"%s\"\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2 = %d, GlProfileIsES3 = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, gl_version_str, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG]
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (bd->GlVersion >= 320)
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
#endif
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
// Store GLSL version string so we can refer to it later in case we recreate shaders.
|
||||
// Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure.
|
||||
if (glsl_version == nullptr)
|
||||
{
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
glsl_version = "#version 100";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
glsl_version = "#version 300 es";
|
||||
#elif defined(__APPLE__)
|
||||
glsl_version = "#version 150";
|
||||
#else
|
||||
glsl_version = "#version 130";
|
||||
#endif
|
||||
}
|
||||
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString));
|
||||
strcpy(bd->GlslVersionString, glsl_version);
|
||||
strcat(bd->GlslVersionString, "\n");
|
||||
|
||||
// Make an arbitrary GL call (we don't actually need the result)
|
||||
// IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
|
||||
GLint current_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
// Detect extensions we support
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
|
||||
bd->HasPolygonMode = (!bd->GlProfileIsES2 && !bd->GlProfileIsES3);
|
||||
#endif
|
||||
bd->HasClipOrigin = (bd->GlVersion >= 450);
|
||||
#ifdef IMGUI_IMPL_OPENGL_HAS_EXTENSIONS
|
||||
GLint num_extensions = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
||||
for (GLint i = 0; i < num_extensions; i++)
|
||||
{
|
||||
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||
if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0)
|
||||
bd->HasClipOrigin = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
ImGui_ImplOpenGL3_InitPlatformInterface();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_Shutdown()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplOpenGL3_ShutdownPlatformInterface();
|
||||
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasViewports);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_NewFrame()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplOpenGL3_Init()?");
|
||||
|
||||
if (!bd->ShaderHandle)
|
||||
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
if (bd->GlVersion >= 310)
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
|
||||
if (bd->HasPolygonMode)
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
#endif
|
||||
|
||||
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
|
||||
#if defined(GL_CLIP_ORIGIN)
|
||||
bool clip_origin_lower_left = true;
|
||||
if (bd->HasClipOrigin)
|
||||
{
|
||||
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin);
|
||||
if (current_clip_origin == GL_UPPER_LEFT)
|
||||
clip_origin_lower_left = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setup viewport, orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
GL_CALL(glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height));
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
#if defined(GL_CLIP_ORIGIN)
|
||||
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
|
||||
#endif
|
||||
const float ortho_projection[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
||||
};
|
||||
glUseProgram(bd->ShaderHandle);
|
||||
glUniform1i(bd->AttribLocationTex, 0);
|
||||
glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (bd->GlVersion >= 330 || bd->GlProfileIsES3)
|
||||
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
|
||||
#endif
|
||||
|
||||
(void)vertex_array_object;
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(vertex_array_object);
|
||||
#endif
|
||||
|
||||
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle));
|
||||
GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle));
|
||||
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxPos));
|
||||
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxUV));
|
||||
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxColor));
|
||||
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, pos)));
|
||||
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, uv)));
|
||||
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, col)));
|
||||
}
|
||||
|
||||
// OpenGL3 Render function.
|
||||
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
|
||||
// This is in order to be able to run within an OpenGL engine that doesn't do so.
|
||||
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||
if (fb_width <= 0 || fb_height <= 0)
|
||||
return;
|
||||
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Backup GL state
|
||||
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
|
||||
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
GLuint last_sampler; if (bd->GlVersion >= 330 || bd->GlProfileIsES3) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
|
||||
#endif
|
||||
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
// This is part of VAO on OpenGL 3.0+ and OpenGL ES 3.0+.
|
||||
GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
|
||||
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_pos; last_vtx_attrib_state_pos.GetState(bd->AttribLocationVtxPos);
|
||||
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_uv; last_vtx_attrib_state_uv.GetState(bd->AttribLocationVtxUV);
|
||||
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_color; last_vtx_attrib_state_color.GetState(bd->AttribLocationVtxColor);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
|
||||
GLint last_polygon_mode[2]; if (bd->HasPolygonMode) { glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); }
|
||||
#endif
|
||||
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
|
||||
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
|
||||
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
|
||||
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
|
||||
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
|
||||
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
|
||||
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
|
||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
|
||||
#endif
|
||||
|
||||
// Setup desired GL state
|
||||
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
|
||||
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
|
||||
GLuint vertex_array_object = 0;
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GL_CALL(glGenVertexArrays(1, &vertex_array_object));
|
||||
#endif
|
||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
|
||||
// Upload vertex/index buffers
|
||||
// - OpenGL drivers are in a very sorry state nowadays....
|
||||
// During 2021 we attempted to switch from glBufferData() to orphaning+glBufferSubData() following reports
|
||||
// of leaks on Intel GPU when using multi-viewports on Windows.
|
||||
// - After this we kept hearing of various display corruptions issues. We started disabling on non-Intel GPU, but issues still got reported on Intel.
|
||||
// - We are now back to using exclusively glBufferData(). So bd->UseBufferSubData IS ALWAYS FALSE in this code.
|
||||
// We are keeping the old code path for a while in case people finding new issues may want to test the bd->UseBufferSubData path.
|
||||
// - See https://github.com/ocornut/imgui/issues/4468 and please report any corruption issues.
|
||||
const GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert);
|
||||
const GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx);
|
||||
if (bd->UseBufferSubData)
|
||||
{
|
||||
if (bd->VertexBufferSize < vtx_buffer_size)
|
||||
{
|
||||
bd->VertexBufferSize = vtx_buffer_size;
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, nullptr, GL_STREAM_DRAW));
|
||||
}
|
||||
if (bd->IndexBufferSize < idx_buffer_size)
|
||||
{
|
||||
bd->IndexBufferSize = idx_buffer_size;
|
||||
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, nullptr, GL_STREAM_DRAW));
|
||||
}
|
||||
GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data));
|
||||
GL_CALL(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data));
|
||||
}
|
||||
else
|
||||
{
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW));
|
||||
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW));
|
||||
}
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != nullptr)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
|
||||
GL_CALL(glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)));
|
||||
|
||||
// Bind texture, Draw
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (bd->GlVersion >= 320)
|
||||
GL_CALL(glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset));
|
||||
else
|
||||
#endif
|
||||
GL_CALL(glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the temporary VAO
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GL_CALL(glDeleteVertexArrays(1, &vertex_array_object));
|
||||
#endif
|
||||
|
||||
// Restore modified GL state
|
||||
// This "glIsProgram()" check is required because if the program is "pending deletion" at the time of binding backup, it will have been deleted by now and will cause an OpenGL error. See #6220.
|
||||
if (last_program == 0 || glIsProgram(last_program)) glUseProgram(last_program);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (bd->GlVersion >= 330 || bd->GlProfileIsES3)
|
||||
glBindSampler(0, last_sampler);
|
||||
#endif
|
||||
glActiveTexture(last_active_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(last_vertex_array_object);
|
||||
#endif
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
|
||||
last_vtx_attrib_state_pos.SetState(bd->AttribLocationVtxPos);
|
||||
last_vtx_attrib_state_uv.SetState(bd->AttribLocationVtxUV);
|
||||
last_vtx_attrib_state_color.SetState(bd->AttribLocationVtxColor);
|
||||
#endif
|
||||
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
|
||||
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
|
||||
// Desktop OpenGL 3.0 and OpenGL 3.1 had separate polygon draw modes for front-facing and back-facing faces of polygons
|
||||
if (bd->HasPolygonMode) { if (bd->GlVersion <= 310 || bd->GlProfileIsCompat) { glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]); } else { glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); } }
|
||||
#endif // IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
|
||||
|
||||
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||
(void)bd; // Not all compilation paths use this
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Build texture atlas
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||
GLint last_texture;
|
||||
GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
|
||||
GL_CALL(glGenTextures(1, &bd->FontTexture));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, bd->FontTexture));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
|
||||
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
|
||||
#endif
|
||||
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
||||
// Restore state
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
if (bd->FontTexture)
|
||||
{
|
||||
glDeleteTextures(1, &bd->FontTexture);
|
||||
io.Fonts->SetTexID(0);
|
||||
bd->FontTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
|
||||
static bool CheckShader(GLuint handle, const char* desc)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
GLint status = 0, log_length = 0;
|
||||
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
||||
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if ((GLboolean)status == GL_FALSE)
|
||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s! With GLSL: %s\n", desc, bd->GlslVersionString);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetShaderInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin());
|
||||
fprintf(stderr, "%s\n", buf.begin());
|
||||
}
|
||||
return (GLboolean)status == GL_TRUE;
|
||||
}
|
||||
|
||||
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
|
||||
static bool CheckProgram(GLuint handle, const char* desc)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
GLint status = 0, log_length = 0;
|
||||
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
||||
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if ((GLboolean)status == GL_FALSE)
|
||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! With GLSL %s\n", desc, bd->GlslVersionString);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetProgramInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin());
|
||||
fprintf(stderr, "%s\n", buf.begin());
|
||||
}
|
||||
return (GLboolean)status == GL_TRUE;
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Backup GL state
|
||||
GLint last_texture, last_array_buffer;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_BUFFER_PIXEL_UNPACK
|
||||
GLint last_pixel_unpack_buffer = 0;
|
||||
if (bd->GlVersion >= 210) { glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &last_pixel_unpack_buffer); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); }
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GLint last_vertex_array;
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
#endif
|
||||
|
||||
// Parse GLSL version string
|
||||
int glsl_version = 130;
|
||||
sscanf(bd->GlslVersionString, "#version %d", &glsl_version);
|
||||
|
||||
const GLchar* vertex_shader_glsl_120 =
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"attribute vec2 Position;\n"
|
||||
"attribute vec2 UV;\n"
|
||||
"attribute vec4 Color;\n"
|
||||
"varying vec2 Frag_UV;\n"
|
||||
"varying vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_130 =
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"in vec2 Position;\n"
|
||||
"in vec2 UV;\n"
|
||||
"in vec4 Color;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_300_es =
|
||||
"precision highp float;\n"
|
||||
"layout (location = 0) in vec2 Position;\n"
|
||||
"layout (location = 1) in vec2 UV;\n"
|
||||
"layout (location = 2) in vec4 Color;\n"
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_410_core =
|
||||
"layout (location = 0) in vec2 Position;\n"
|
||||
"layout (location = 1) in vec2 UV;\n"
|
||||
"layout (location = 2) in vec4 Color;\n"
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_120 =
|
||||
"#ifdef GL_ES\n"
|
||||
" precision mediump float;\n"
|
||||
"#endif\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"varying vec2 Frag_UV;\n"
|
||||
"varying vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_130 =
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_300_es =
|
||||
"precision mediump float;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"layout (location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_410_core =
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"layout (location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
// Select shaders matching our GLSL versions
|
||||
const GLchar* vertex_shader = nullptr;
|
||||
const GLchar* fragment_shader = nullptr;
|
||||
if (glsl_version < 130)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_120;
|
||||
fragment_shader = fragment_shader_glsl_120;
|
||||
}
|
||||
else if (glsl_version >= 410)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_410_core;
|
||||
fragment_shader = fragment_shader_glsl_410_core;
|
||||
}
|
||||
else if (glsl_version == 300)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_300_es;
|
||||
fragment_shader = fragment_shader_glsl_300_es;
|
||||
}
|
||||
else
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_130;
|
||||
fragment_shader = fragment_shader_glsl_130;
|
||||
}
|
||||
|
||||
// Create shaders
|
||||
const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader };
|
||||
GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vert_handle, 2, vertex_shader_with_version, nullptr);
|
||||
glCompileShader(vert_handle);
|
||||
CheckShader(vert_handle, "vertex shader");
|
||||
|
||||
const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader };
|
||||
GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(frag_handle, 2, fragment_shader_with_version, nullptr);
|
||||
glCompileShader(frag_handle);
|
||||
CheckShader(frag_handle, "fragment shader");
|
||||
|
||||
// Link
|
||||
bd->ShaderHandle = glCreateProgram();
|
||||
glAttachShader(bd->ShaderHandle, vert_handle);
|
||||
glAttachShader(bd->ShaderHandle, frag_handle);
|
||||
glLinkProgram(bd->ShaderHandle);
|
||||
CheckProgram(bd->ShaderHandle, "shader program");
|
||||
|
||||
glDetachShader(bd->ShaderHandle, vert_handle);
|
||||
glDetachShader(bd->ShaderHandle, frag_handle);
|
||||
glDeleteShader(vert_handle);
|
||||
glDeleteShader(frag_handle);
|
||||
|
||||
bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture");
|
||||
bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx");
|
||||
bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position");
|
||||
bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV");
|
||||
bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color");
|
||||
|
||||
// Create buffers
|
||||
glGenBuffers(1, &bd->VboHandle);
|
||||
glGenBuffers(1, &bd->ElementsHandle);
|
||||
|
||||
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
|
||||
// Restore modified GL state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_BUFFER_PIXEL_UNPACK
|
||||
if (bd->GlVersion >= 210) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, last_pixel_unpack_buffer); }
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(last_vertex_array);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
|
||||
if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
|
||||
if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
|
||||
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
{
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData);
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_InitPlatformInterface()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL3_RenderWindow;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_ShutdownPlatformInterface()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
@ -1,67 +0,0 @@
|
||||
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
|
||||
// - Desktop GL: 2.x 3.x 4.x
|
||||
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// About WebGL/ES:
|
||||
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
|
||||
// - This is done automatically on iOS, Android and Emscripten targets.
|
||||
// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
// About GLSL version:
|
||||
// The 'glsl_version' initialization parameter should be nullptr (default) or a "#version XXX" string.
|
||||
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
|
||||
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
// Backend API
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr);
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// (Optional) Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
|
||||
// Configuration flags to add in your imconfig file:
|
||||
//#define IMGUI_IMPL_OPENGL_ES2 // Enable ES 2 (Auto-detected on Emscripten)
|
||||
//#define IMGUI_IMPL_OPENGL_ES3 // Enable ES 3 (Auto-detected on iOS/Android)
|
||||
|
||||
// You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
|
||||
// Try to detect GLES on matching platforms
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
|
||||
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
|
||||
#elif defined(__EMSCRIPTEN__) || defined(__amigaos4__)
|
||||
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
|
||||
#else
|
||||
// Otherwise imgui_impl_opengl3_loader.h will be used.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
@ -1,922 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// About imgui_impl_opengl3_loader.h:
|
||||
//
|
||||
// We embed our own OpenGL loader to not require user to provide their own or to have to use ours,
|
||||
// which proved to be endless problems for users.
|
||||
// Our loader is custom-generated, based on gl3w but automatically filtered to only include
|
||||
// enums/functions that we use in our imgui_impl_opengl3.cpp source file in order to be small.
|
||||
//
|
||||
// YOU SHOULD NOT NEED TO INCLUDE/USE THIS DIRECTLY. THIS IS USED BY imgui_impl_opengl3.cpp ONLY.
|
||||
// THE REST OF YOUR APP SHOULD USE A DIFFERENT GL LOADER: ANY GL LOADER OF YOUR CHOICE.
|
||||
//
|
||||
// IF YOU GET BUILD ERRORS IN THIS FILE (commonly macro redefinitions or function redefinitions):
|
||||
// IT LIKELY MEANS THAT YOU ARE BUILDING 'imgui_impl_opengl3.cpp' OR INCUDING 'imgui_impl_opengl3_loader.h'
|
||||
// IN THE SAME COMPILATION UNIT AS ONE OF YOUR FILE WHICH IS USING A THIRD-PARTY OPENGL LOADER.
|
||||
// (e.g. COULD HAPPEN IF YOU ARE DOING A UNITY/JUMBO BUILD, OR INCLUDING .CPP FILES FROM OTHERS)
|
||||
// YOU SHOULD NOT BUILD BOTH IN THE SAME COMPILATION UNIT.
|
||||
// BUT IF YOU REALLY WANT TO, you can '#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM' and imgui_impl_opengl3.cpp
|
||||
// WILL NOT BE USING OUR LOADER, AND INSTEAD EXPECT ANOTHER/YOUR LOADER TO BE AVAILABLE IN THE COMPILATION UNIT.
|
||||
//
|
||||
// Regenerate with:
|
||||
// python3 gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt
|
||||
//
|
||||
// More info:
|
||||
// https://github.com/dearimgui/gl3w_stripped
|
||||
// https://github.com/ocornut/imgui/issues/4445
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* This file was generated with gl3w_gen.py, part of imgl3w
|
||||
* (hosted at https://github.com/dearimgui/gl3w_stripped)
|
||||
*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*
|
||||
* Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
* distribute this software, either in source code form or as a compiled
|
||||
* binary, for any purpose, commercial or non-commercial, and by any
|
||||
* means.
|
||||
*
|
||||
* In jurisdictions that recognize copyright laws, the author or authors
|
||||
* of this software dedicate any and all copyright interest in the
|
||||
* software to the public domain. We make this dedication for the benefit
|
||||
* of the public at large and to the detriment of our heirs and
|
||||
* successors. We intend this dedication to be an overt act of
|
||||
* relinquishment in perpetuity of all present and future rights to this
|
||||
* software under copyright law.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __gl3w_h_
|
||||
#define __gl3w_h_
|
||||
|
||||
// Adapted from KHR/khrplatform.h to avoid including entire file.
|
||||
#ifndef __khrplatform_h_
|
||||
typedef float khronos_float_t;
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
#ifdef _WIN64
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef signed long int khronos_ssize_t;
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
typedef signed __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)
|
||||
#include <stdint.h>
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#else
|
||||
typedef signed long long khronos_int64_t;
|
||||
typedef unsigned long long khronos_uint64_t;
|
||||
#endif
|
||||
#endif // __khrplatform_h_
|
||||
|
||||
#ifndef __gl_glcorearb_h_
|
||||
#define __gl_glcorearb_h_ 1
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
** Copyright 2013-2020 The Khronos Group Inc.
|
||||
** SPDX-License-Identifier: MIT
|
||||
**
|
||||
** This header is generated from the Khronos OpenGL / OpenGL ES XML
|
||||
** API Registry. The current version of the Registry, generator scripts
|
||||
** used to make the header, and the header can be found at
|
||||
** https://github.com/KhronosGroup/OpenGL-Registry
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifndef APIENTRY
|
||||
#define APIENTRY
|
||||
#endif
|
||||
#ifndef APIENTRYP
|
||||
#define APIENTRYP APIENTRY *
|
||||
#endif
|
||||
#ifndef GLAPI
|
||||
#define GLAPI extern
|
||||
#endif
|
||||
/* glcorearb.h is for use with OpenGL core profile implementations.
|
||||
** It should should be placed in the same directory as gl.h and
|
||||
** included as <GL/glcorearb.h>.
|
||||
**
|
||||
** glcorearb.h includes only APIs in the latest OpenGL core profile
|
||||
** implementation together with APIs in newer ARB extensions which
|
||||
** can be supported by the core profile. It does not, and never will
|
||||
** include functionality removed from the core profile, such as
|
||||
** fixed-function vertex and fragment processing.
|
||||
**
|
||||
** Do not #include both <GL/glcorearb.h> and either of <GL/gl.h> or
|
||||
** <GL/glext.h> in the same source file.
|
||||
*/
|
||||
/* Generated C header for:
|
||||
* API: gl
|
||||
* Profile: core
|
||||
* Versions considered: .*
|
||||
* Versions emitted: .*
|
||||
* Default extensions included: glcore
|
||||
* Additional extensions included: _nomatch_^
|
||||
* Extensions removed: _nomatch_^
|
||||
*/
|
||||
#ifndef GL_VERSION_1_0
|
||||
typedef void GLvoid;
|
||||
typedef unsigned int GLenum;
|
||||
|
||||
typedef khronos_float_t GLfloat;
|
||||
typedef int GLint;
|
||||
typedef int GLsizei;
|
||||
typedef unsigned int GLbitfield;
|
||||
typedef double GLdouble;
|
||||
typedef unsigned int GLuint;
|
||||
typedef unsigned char GLboolean;
|
||||
typedef khronos_uint8_t GLubyte;
|
||||
#define GL_COLOR_BUFFER_BIT 0x00004000
|
||||
#define GL_FALSE 0
|
||||
#define GL_TRUE 1
|
||||
#define GL_TRIANGLES 0x0004
|
||||
#define GL_ONE 1
|
||||
#define GL_SRC_ALPHA 0x0302
|
||||
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
|
||||
#define GL_FRONT 0x0404
|
||||
#define GL_BACK 0x0405
|
||||
#define GL_FRONT_AND_BACK 0x0408
|
||||
#define GL_POLYGON_MODE 0x0B40
|
||||
#define GL_CULL_FACE 0x0B44
|
||||
#define GL_DEPTH_TEST 0x0B71
|
||||
#define GL_STENCIL_TEST 0x0B90
|
||||
#define GL_VIEWPORT 0x0BA2
|
||||
#define GL_BLEND 0x0BE2
|
||||
#define GL_SCISSOR_BOX 0x0C10
|
||||
#define GL_SCISSOR_TEST 0x0C11
|
||||
#define GL_UNPACK_ROW_LENGTH 0x0CF2
|
||||
#define GL_PACK_ALIGNMENT 0x0D05
|
||||
#define GL_TEXTURE_2D 0x0DE1
|
||||
#define GL_UNSIGNED_BYTE 0x1401
|
||||
#define GL_UNSIGNED_SHORT 0x1403
|
||||
#define GL_UNSIGNED_INT 0x1405
|
||||
#define GL_FLOAT 0x1406
|
||||
#define GL_RGBA 0x1908
|
||||
#define GL_FILL 0x1B02
|
||||
#define GL_VENDOR 0x1F00
|
||||
#define GL_RENDERER 0x1F01
|
||||
#define GL_VERSION 0x1F02
|
||||
#define GL_EXTENSIONS 0x1F03
|
||||
#define GL_LINEAR 0x2601
|
||||
#define GL_LINEAR_MIPMAP_LINEAR 0x2703
|
||||
#define GL_TEXTURE_MAG_FILTER 0x2800
|
||||
#define GL_TEXTURE_MIN_FILTER 0x2801
|
||||
#define GL_TEXTURE_WRAP_S 0x2802
|
||||
#define GL_TEXTURE_WRAP_T 0x2803
|
||||
#define GL_REPEAT 0x2901
|
||||
typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode);
|
||||
typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
|
||||
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
|
||||
typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask);
|
||||
typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
|
||||
typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
|
||||
typedef void (APIENTRYP PFNGLFLUSHPROC) (void);
|
||||
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
|
||||
typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
|
||||
typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
|
||||
typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data);
|
||||
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
|
||||
typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap);
|
||||
typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode);
|
||||
GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
|
||||
GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
|
||||
GLAPI void APIENTRY glClear (GLbitfield mask);
|
||||
GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
GLAPI void APIENTRY glDisable (GLenum cap);
|
||||
GLAPI void APIENTRY glEnable (GLenum cap);
|
||||
GLAPI void APIENTRY glFlush (void);
|
||||
GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);
|
||||
GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
|
||||
GLAPI GLenum APIENTRY glGetError (void);
|
||||
GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data);
|
||||
GLAPI const GLubyte *APIENTRY glGetString (GLenum name);
|
||||
GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap);
|
||||
GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_0 */
|
||||
#ifndef GL_VERSION_1_1
|
||||
typedef khronos_float_t GLclampf;
|
||||
typedef double GLclampd;
|
||||
#define GL_TEXTURE_BINDING_2D 0x8069
|
||||
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices);
|
||||
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
|
||||
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
|
||||
typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);
|
||||
GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture);
|
||||
GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
|
||||
GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_1 */
|
||||
#ifndef GL_VERSION_1_2
|
||||
#define GL_CLAMP_TO_EDGE 0x812F
|
||||
#endif /* GL_VERSION_1_2 */
|
||||
#ifndef GL_VERSION_1_3
|
||||
#define GL_TEXTURE0 0x84C0
|
||||
#define GL_ACTIVE_TEXTURE 0x84E0
|
||||
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
|
||||
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glActiveTexture (GLenum texture);
|
||||
GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_3 */
|
||||
#ifndef GL_VERSION_1_4
|
||||
#define GL_BLEND_DST_RGB 0x80C8
|
||||
#define GL_BLEND_SRC_RGB 0x80C9
|
||||
#define GL_BLEND_DST_ALPHA 0x80CA
|
||||
#define GL_BLEND_SRC_ALPHA 0x80CB
|
||||
#define GL_FUNC_ADD 0x8006
|
||||
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||
typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||
GLAPI void APIENTRY glBlendEquation (GLenum mode);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_4 */
|
||||
#ifndef GL_VERSION_1_5
|
||||
typedef khronos_ssize_t GLsizeiptr;
|
||||
typedef khronos_intptr_t GLintptr;
|
||||
#define GL_ARRAY_BUFFER 0x8892
|
||||
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
|
||||
#define GL_ARRAY_BUFFER_BINDING 0x8894
|
||||
#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
|
||||
#define GL_STREAM_DRAW 0x88E0
|
||||
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
|
||||
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
|
||||
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
|
||||
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
|
||||
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
|
||||
GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
|
||||
GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
|
||||
GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
|
||||
GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_5 */
|
||||
#ifndef GL_VERSION_2_0
|
||||
typedef char GLchar;
|
||||
typedef khronos_int16_t GLshort;
|
||||
typedef khronos_int8_t GLbyte;
|
||||
typedef khronos_uint16_t GLushort;
|
||||
#define GL_BLEND_EQUATION_RGB 0x8009
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
|
||||
#define GL_BLEND_EQUATION_ALPHA 0x883D
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
|
||||
#define GL_FRAGMENT_SHADER 0x8B30
|
||||
#define GL_VERTEX_SHADER 0x8B31
|
||||
#define GL_COMPILE_STATUS 0x8B81
|
||||
#define GL_LINK_STATUS 0x8B82
|
||||
#define GL_INFO_LOG_LENGTH 0x8B84
|
||||
#define GL_CURRENT_PROGRAM 0x8B8D
|
||||
#define GL_UPPER_LEFT 0x8CA2
|
||||
typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
|
||||
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
|
||||
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
|
||||
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
|
||||
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
|
||||
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
|
||||
typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
|
||||
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
|
||||
typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
|
||||
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
|
||||
GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);
|
||||
GLAPI void APIENTRY glCompileShader (GLuint shader);
|
||||
GLAPI GLuint APIENTRY glCreateProgram (void);
|
||||
GLAPI GLuint APIENTRY glCreateShader (GLenum type);
|
||||
GLAPI void APIENTRY glDeleteProgram (GLuint program);
|
||||
GLAPI void APIENTRY glDeleteShader (GLuint shader);
|
||||
GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);
|
||||
GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index);
|
||||
GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);
|
||||
GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);
|
||||
GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
|
||||
GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer);
|
||||
GLAPI GLboolean APIENTRY glIsProgram (GLuint program);
|
||||
GLAPI void APIENTRY glLinkProgram (GLuint program);
|
||||
GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||
GLAPI void APIENTRY glUseProgram (GLuint program);
|
||||
GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
|
||||
GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||
GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||
#endif
|
||||
#endif /* GL_VERSION_2_0 */
|
||||
#ifndef GL_VERSION_2_1
|
||||
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
|
||||
#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
|
||||
#endif /* GL_VERSION_2_1 */
|
||||
#ifndef GL_VERSION_3_0
|
||||
typedef khronos_uint16_t GLhalf;
|
||||
#define GL_MAJOR_VERSION 0x821B
|
||||
#define GL_MINOR_VERSION 0x821C
|
||||
#define GL_NUM_EXTENSIONS 0x821D
|
||||
#define GL_FRAMEBUFFER_SRGB 0x8DB9
|
||||
#define GL_VERTEX_ARRAY_BINDING 0x85B5
|
||||
typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
|
||||
typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
|
||||
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
|
||||
typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
|
||||
typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
|
||||
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);
|
||||
GLAPI void APIENTRY glBindVertexArray (GLuint array);
|
||||
GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
|
||||
GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);
|
||||
#endif
|
||||
#endif /* GL_VERSION_3_0 */
|
||||
#ifndef GL_VERSION_3_1
|
||||
#define GL_VERSION_3_1 1
|
||||
#define GL_PRIMITIVE_RESTART 0x8F9D
|
||||
#endif /* GL_VERSION_3_1 */
|
||||
#ifndef GL_VERSION_3_2
|
||||
#define GL_VERSION_3_2 1
|
||||
typedef struct __GLsync *GLsync;
|
||||
typedef khronos_uint64_t GLuint64;
|
||||
typedef khronos_int64_t GLint64;
|
||||
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
|
||||
#define GL_CONTEXT_PROFILE_MASK 0x9126
|
||||
typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
|
||||
typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
|
||||
#endif
|
||||
#endif /* GL_VERSION_3_2 */
|
||||
#ifndef GL_VERSION_3_3
|
||||
#define GL_VERSION_3_3 1
|
||||
#define GL_SAMPLER_BINDING 0x8919
|
||||
typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);
|
||||
#endif
|
||||
#endif /* GL_VERSION_3_3 */
|
||||
#ifndef GL_VERSION_4_1
|
||||
typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
|
||||
typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
|
||||
#endif /* GL_VERSION_4_1 */
|
||||
#ifndef GL_VERSION_4_3
|
||||
typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
|
||||
#endif /* GL_VERSION_4_3 */
|
||||
#ifndef GL_VERSION_4_5
|
||||
#define GL_CLIP_ORIGIN 0x935C
|
||||
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param);
|
||||
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
|
||||
#endif /* GL_VERSION_4_5 */
|
||||
#ifndef GL_ARB_bindless_texture
|
||||
typedef khronos_uint64_t GLuint64EXT;
|
||||
#endif /* GL_ARB_bindless_texture */
|
||||
#ifndef GL_ARB_cl_event
|
||||
struct _cl_context;
|
||||
struct _cl_event;
|
||||
#endif /* GL_ARB_cl_event */
|
||||
#ifndef GL_ARB_clip_control
|
||||
#define GL_ARB_clip_control 1
|
||||
#endif /* GL_ARB_clip_control */
|
||||
#ifndef GL_ARB_debug_output
|
||||
typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
|
||||
#endif /* GL_ARB_debug_output */
|
||||
#ifndef GL_EXT_EGL_image_storage
|
||||
typedef void *GLeglImageOES;
|
||||
#endif /* GL_EXT_EGL_image_storage */
|
||||
#ifndef GL_EXT_direct_state_access
|
||||
typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);
|
||||
typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);
|
||||
typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);
|
||||
#endif /* GL_EXT_direct_state_access */
|
||||
#ifndef GL_NV_draw_vulkan_image
|
||||
typedef void (APIENTRY *GLVULKANPROCNV)(void);
|
||||
#endif /* GL_NV_draw_vulkan_image */
|
||||
#ifndef GL_NV_gpu_shader5
|
||||
typedef khronos_int64_t GLint64EXT;
|
||||
#endif /* GL_NV_gpu_shader5 */
|
||||
#ifndef GL_NV_vertex_buffer_unified_memory
|
||||
typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);
|
||||
#endif /* GL_NV_vertex_buffer_unified_memory */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GL3W_API
|
||||
#define GL3W_API
|
||||
#endif
|
||||
|
||||
#ifndef __gl_h_
|
||||
#define __gl_h_
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GL3W_OK 0
|
||||
#define GL3W_ERROR_INIT -1
|
||||
#define GL3W_ERROR_LIBRARY_OPEN -2
|
||||
#define GL3W_ERROR_OPENGL_VERSION -3
|
||||
|
||||
typedef void (*GL3WglProc)(void);
|
||||
typedef GL3WglProc (*GL3WGetProcAddressProc)(const char *proc);
|
||||
|
||||
/* gl3w api */
|
||||
GL3W_API int imgl3wInit(void);
|
||||
GL3W_API int imgl3wInit2(GL3WGetProcAddressProc proc);
|
||||
GL3W_API int imgl3wIsSupported(int major, int minor);
|
||||
GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
|
||||
|
||||
/* gl3w internal state */
|
||||
union ImGL3WProcs {
|
||||
GL3WglProc ptr[60];
|
||||
struct {
|
||||
PFNGLACTIVETEXTUREPROC ActiveTexture;
|
||||
PFNGLATTACHSHADERPROC AttachShader;
|
||||
PFNGLBINDBUFFERPROC BindBuffer;
|
||||
PFNGLBINDSAMPLERPROC BindSampler;
|
||||
PFNGLBINDTEXTUREPROC BindTexture;
|
||||
PFNGLBINDVERTEXARRAYPROC BindVertexArray;
|
||||
PFNGLBLENDEQUATIONPROC BlendEquation;
|
||||
PFNGLBLENDEQUATIONSEPARATEPROC BlendEquationSeparate;
|
||||
PFNGLBLENDFUNCSEPARATEPROC BlendFuncSeparate;
|
||||
PFNGLBUFFERDATAPROC BufferData;
|
||||
PFNGLBUFFERSUBDATAPROC BufferSubData;
|
||||
PFNGLCLEARPROC Clear;
|
||||
PFNGLCLEARCOLORPROC ClearColor;
|
||||
PFNGLCOMPILESHADERPROC CompileShader;
|
||||
PFNGLCOMPRESSEDTEXIMAGE2DPROC CompressedTexImage2D;
|
||||
PFNGLCREATEPROGRAMPROC CreateProgram;
|
||||
PFNGLCREATESHADERPROC CreateShader;
|
||||
PFNGLDELETEBUFFERSPROC DeleteBuffers;
|
||||
PFNGLDELETEPROGRAMPROC DeleteProgram;
|
||||
PFNGLDELETESHADERPROC DeleteShader;
|
||||
PFNGLDELETETEXTURESPROC DeleteTextures;
|
||||
PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
|
||||
PFNGLDETACHSHADERPROC DetachShader;
|
||||
PFNGLDISABLEPROC Disable;
|
||||
PFNGLDISABLEVERTEXATTRIBARRAYPROC DisableVertexAttribArray;
|
||||
PFNGLDRAWELEMENTSPROC DrawElements;
|
||||
PFNGLDRAWELEMENTSBASEVERTEXPROC DrawElementsBaseVertex;
|
||||
PFNGLENABLEPROC Enable;
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
|
||||
PFNGLFLUSHPROC Flush;
|
||||
PFNGLGENBUFFERSPROC GenBuffers;
|
||||
PFNGLGENTEXTURESPROC GenTextures;
|
||||
PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
|
||||
PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
|
||||
PFNGLGETERRORPROC GetError;
|
||||
PFNGLGETINTEGERVPROC GetIntegerv;
|
||||
PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
|
||||
PFNGLGETPROGRAMIVPROC GetProgramiv;
|
||||
PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
|
||||
PFNGLGETSHADERIVPROC GetShaderiv;
|
||||
PFNGLGETSTRINGPROC GetString;
|
||||
PFNGLGETSTRINGIPROC GetStringi;
|
||||
PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
|
||||
PFNGLGETVERTEXATTRIBPOINTERVPROC GetVertexAttribPointerv;
|
||||
PFNGLGETVERTEXATTRIBIVPROC GetVertexAttribiv;
|
||||
PFNGLISENABLEDPROC IsEnabled;
|
||||
PFNGLISPROGRAMPROC IsProgram;
|
||||
PFNGLLINKPROGRAMPROC LinkProgram;
|
||||
PFNGLPIXELSTOREIPROC PixelStorei;
|
||||
PFNGLPOLYGONMODEPROC PolygonMode;
|
||||
PFNGLREADPIXELSPROC ReadPixels;
|
||||
PFNGLSCISSORPROC Scissor;
|
||||
PFNGLSHADERSOURCEPROC ShaderSource;
|
||||
PFNGLTEXIMAGE2DPROC TexImage2D;
|
||||
PFNGLTEXPARAMETERIPROC TexParameteri;
|
||||
PFNGLUNIFORM1IPROC Uniform1i;
|
||||
PFNGLUNIFORMMATRIX4FVPROC UniformMatrix4fv;
|
||||
PFNGLUSEPROGRAMPROC UseProgram;
|
||||
PFNGLVERTEXATTRIBPOINTERPROC VertexAttribPointer;
|
||||
PFNGLVIEWPORTPROC Viewport;
|
||||
} gl;
|
||||
};
|
||||
|
||||
GL3W_API extern union ImGL3WProcs imgl3wProcs;
|
||||
|
||||
/* OpenGL functions */
|
||||
#define glActiveTexture imgl3wProcs.gl.ActiveTexture
|
||||
#define glAttachShader imgl3wProcs.gl.AttachShader
|
||||
#define glBindBuffer imgl3wProcs.gl.BindBuffer
|
||||
#define glBindSampler imgl3wProcs.gl.BindSampler
|
||||
#define glBindTexture imgl3wProcs.gl.BindTexture
|
||||
#define glBindVertexArray imgl3wProcs.gl.BindVertexArray
|
||||
#define glBlendEquation imgl3wProcs.gl.BlendEquation
|
||||
#define glBlendEquationSeparate imgl3wProcs.gl.BlendEquationSeparate
|
||||
#define glBlendFuncSeparate imgl3wProcs.gl.BlendFuncSeparate
|
||||
#define glBufferData imgl3wProcs.gl.BufferData
|
||||
#define glBufferSubData imgl3wProcs.gl.BufferSubData
|
||||
#define glClear imgl3wProcs.gl.Clear
|
||||
#define glClearColor imgl3wProcs.gl.ClearColor
|
||||
#define glCompileShader imgl3wProcs.gl.CompileShader
|
||||
#define glCompressedTexImage2D imgl3wProcs.gl.CompressedTexImage2D
|
||||
#define glCreateProgram imgl3wProcs.gl.CreateProgram
|
||||
#define glCreateShader imgl3wProcs.gl.CreateShader
|
||||
#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
|
||||
#define glDeleteProgram imgl3wProcs.gl.DeleteProgram
|
||||
#define glDeleteShader imgl3wProcs.gl.DeleteShader
|
||||
#define glDeleteTextures imgl3wProcs.gl.DeleteTextures
|
||||
#define glDeleteVertexArrays imgl3wProcs.gl.DeleteVertexArrays
|
||||
#define glDetachShader imgl3wProcs.gl.DetachShader
|
||||
#define glDisable imgl3wProcs.gl.Disable
|
||||
#define glDisableVertexAttribArray imgl3wProcs.gl.DisableVertexAttribArray
|
||||
#define glDrawElements imgl3wProcs.gl.DrawElements
|
||||
#define glDrawElementsBaseVertex imgl3wProcs.gl.DrawElementsBaseVertex
|
||||
#define glEnable imgl3wProcs.gl.Enable
|
||||
#define glEnableVertexAttribArray imgl3wProcs.gl.EnableVertexAttribArray
|
||||
#define glFlush imgl3wProcs.gl.Flush
|
||||
#define glGenBuffers imgl3wProcs.gl.GenBuffers
|
||||
#define glGenTextures imgl3wProcs.gl.GenTextures
|
||||
#define glGenVertexArrays imgl3wProcs.gl.GenVertexArrays
|
||||
#define glGetAttribLocation imgl3wProcs.gl.GetAttribLocation
|
||||
#define glGetError imgl3wProcs.gl.GetError
|
||||
#define glGetIntegerv imgl3wProcs.gl.GetIntegerv
|
||||
#define glGetProgramInfoLog imgl3wProcs.gl.GetProgramInfoLog
|
||||
#define glGetProgramiv imgl3wProcs.gl.GetProgramiv
|
||||
#define glGetShaderInfoLog imgl3wProcs.gl.GetShaderInfoLog
|
||||
#define glGetShaderiv imgl3wProcs.gl.GetShaderiv
|
||||
#define glGetString imgl3wProcs.gl.GetString
|
||||
#define glGetStringi imgl3wProcs.gl.GetStringi
|
||||
#define glGetUniformLocation imgl3wProcs.gl.GetUniformLocation
|
||||
#define glGetVertexAttribPointerv imgl3wProcs.gl.GetVertexAttribPointerv
|
||||
#define glGetVertexAttribiv imgl3wProcs.gl.GetVertexAttribiv
|
||||
#define glIsEnabled imgl3wProcs.gl.IsEnabled
|
||||
#define glIsProgram imgl3wProcs.gl.IsProgram
|
||||
#define glLinkProgram imgl3wProcs.gl.LinkProgram
|
||||
#define glPixelStorei imgl3wProcs.gl.PixelStorei
|
||||
#define glPolygonMode imgl3wProcs.gl.PolygonMode
|
||||
#define glReadPixels imgl3wProcs.gl.ReadPixels
|
||||
#define glScissor imgl3wProcs.gl.Scissor
|
||||
#define glShaderSource imgl3wProcs.gl.ShaderSource
|
||||
#define glTexImage2D imgl3wProcs.gl.TexImage2D
|
||||
#define glTexParameteri imgl3wProcs.gl.TexParameteri
|
||||
#define glUniform1i imgl3wProcs.gl.Uniform1i
|
||||
#define glUniformMatrix4fv imgl3wProcs.gl.UniformMatrix4fv
|
||||
#define glUseProgram imgl3wProcs.gl.UseProgram
|
||||
#define glVertexAttribPointer imgl3wProcs.gl.VertexAttribPointer
|
||||
#define glViewport imgl3wProcs.gl.Viewport
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef IMGL3W_IMPL
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define GL3W_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
static HMODULE libgl;
|
||||
typedef PROC(__stdcall* GL3WglGetProcAddr)(LPCSTR);
|
||||
static GL3WglGetProcAddr wgl_get_proc_address;
|
||||
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = LoadLibraryA("opengl32.dll");
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
wgl_get_proc_address = (GL3WglGetProcAddr)GetProcAddress(libgl, "wglGetProcAddress");
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void) { FreeLibrary(libgl); }
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
res = (GL3WglProc)wgl_get_proc_address(proc);
|
||||
if (!res)
|
||||
res = (GL3WglProc)GetProcAddress(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void *libgl;
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void) { dlclose(libgl); }
|
||||
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
*(void **)(&res) = dlsym(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void* libgl; // OpenGL library
|
||||
static void* libglx; // GLX library
|
||||
static void* libegl; // EGL library
|
||||
static GL3WGetProcAddressProc gl_get_proc_address;
|
||||
|
||||
static void close_libgl(void)
|
||||
{
|
||||
if (libgl) {
|
||||
dlclose(libgl);
|
||||
libgl = NULL;
|
||||
}
|
||||
if (libegl) {
|
||||
dlclose(libegl);
|
||||
libegl = NULL;
|
||||
}
|
||||
if (libglx) {
|
||||
dlclose(libglx);
|
||||
libglx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int is_library_loaded(const char* name, void** lib)
|
||||
{
|
||||
*lib = dlopen(name, RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
|
||||
return *lib != NULL;
|
||||
}
|
||||
|
||||
static int open_libs(void)
|
||||
{
|
||||
// On Linux we have two APIs to get process addresses: EGL and GLX.
|
||||
// EGL is supported under both X11 and Wayland, whereas GLX is X11-specific.
|
||||
|
||||
libgl = NULL;
|
||||
libegl = NULL;
|
||||
libglx = NULL;
|
||||
|
||||
// First check what's already loaded, the windowing library might have
|
||||
// already loaded either EGL or GLX and we want to use the same one.
|
||||
|
||||
if (is_library_loaded("libEGL.so.1", &libegl) ||
|
||||
is_library_loaded("libGLX.so.0", &libglx)) {
|
||||
libgl = dlopen("libOpenGL.so.0", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (libgl)
|
||||
return GL3W_OK;
|
||||
else
|
||||
close_libgl();
|
||||
}
|
||||
|
||||
if (is_library_loaded("libGL.so", &libgl))
|
||||
return GL3W_OK;
|
||||
if (is_library_loaded("libGL.so.1", &libgl))
|
||||
return GL3W_OK;
|
||||
if (is_library_loaded("libGL.so.3", &libgl))
|
||||
return GL3W_OK;
|
||||
|
||||
// Neither is already loaded, so we have to load one. Try EGL first
|
||||
// because it is supported under both X11 and Wayland.
|
||||
|
||||
// Load OpenGL + EGL
|
||||
libgl = dlopen("libOpenGL.so.0", RTLD_LAZY | RTLD_LOCAL);
|
||||
libegl = dlopen("libEGL.so.1", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (libgl && libegl)
|
||||
return GL3W_OK;
|
||||
else
|
||||
close_libgl();
|
||||
|
||||
// Fall back to legacy libGL, which includes GLX
|
||||
// While most systems use libGL.so.1, NetBSD seems to use that libGL.so.3. See https://github.com/ocornut/imgui/issues/6983
|
||||
libgl = dlopen("libGL.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
libgl = dlopen("libGL.so.3", RTLD_LAZY | RTLD_LOCAL);
|
||||
|
||||
if (libgl)
|
||||
return GL3W_OK;
|
||||
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
}
|
||||
|
||||
static int open_libgl(void)
|
||||
{
|
||||
int res = open_libs();
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (libegl)
|
||||
*(void**)(&gl_get_proc_address) = dlsym(libegl, "eglGetProcAddress");
|
||||
else if (libglx)
|
||||
*(void**)(&gl_get_proc_address) = dlsym(libglx, "glXGetProcAddressARB");
|
||||
else
|
||||
*(void**)(&gl_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
|
||||
|
||||
if (!gl_get_proc_address) {
|
||||
close_libgl();
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
}
|
||||
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static GL3WglProc get_proc(const char* proc)
|
||||
{
|
||||
GL3WglProc res = NULL;
|
||||
|
||||
// Before EGL version 1.5, eglGetProcAddress doesn't support querying core
|
||||
// functions and may return a dummy function if we try, so try to load the
|
||||
// function from the GL library directly first.
|
||||
if (libegl)
|
||||
*(void**)(&res) = dlsym(libgl, proc);
|
||||
|
||||
if (!res)
|
||||
res = gl_get_proc_address(proc);
|
||||
|
||||
if (!libegl && !res)
|
||||
*(void**)(&res) = dlsym(libgl, proc);
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct { int major, minor; } version;
|
||||
|
||||
static int parse_version(void)
|
||||
{
|
||||
if (!glGetIntegerv)
|
||||
return GL3W_ERROR_INIT;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &version.major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &version.minor);
|
||||
if (version.major == 0 && version.minor == 0)
|
||||
{
|
||||
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
|
||||
if (const char* gl_version = (const char*)glGetString(GL_VERSION))
|
||||
sscanf(gl_version, "%d.%d", &version.major, &version.minor);
|
||||
}
|
||||
if (version.major < 2)
|
||||
return GL3W_ERROR_OPENGL_VERSION;
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void load_procs(GL3WGetProcAddressProc proc);
|
||||
|
||||
int imgl3wInit(void)
|
||||
{
|
||||
int res = open_libgl();
|
||||
if (res)
|
||||
return res;
|
||||
atexit(close_libgl);
|
||||
return imgl3wInit2(get_proc);
|
||||
}
|
||||
|
||||
int imgl3wInit2(GL3WGetProcAddressProc proc)
|
||||
{
|
||||
load_procs(proc);
|
||||
return parse_version();
|
||||
}
|
||||
|
||||
int imgl3wIsSupported(int major, int minor)
|
||||
{
|
||||
if (major < 2)
|
||||
return 0;
|
||||
if (version.major == major)
|
||||
return version.minor >= minor;
|
||||
return version.major >= major;
|
||||
}
|
||||
|
||||
GL3WglProc imgl3wGetProcAddress(const char *proc) { return get_proc(proc); }
|
||||
|
||||
static const char *proc_names[] = {
|
||||
"glActiveTexture",
|
||||
"glAttachShader",
|
||||
"glBindBuffer",
|
||||
"glBindSampler",
|
||||
"glBindTexture",
|
||||
"glBindVertexArray",
|
||||
"glBlendEquation",
|
||||
"glBlendEquationSeparate",
|
||||
"glBlendFuncSeparate",
|
||||
"glBufferData",
|
||||
"glBufferSubData",
|
||||
"glClear",
|
||||
"glClearColor",
|
||||
"glCompileShader",
|
||||
"glCompressedTexImage2D",
|
||||
"glCreateProgram",
|
||||
"glCreateShader",
|
||||
"glDeleteBuffers",
|
||||
"glDeleteProgram",
|
||||
"glDeleteShader",
|
||||
"glDeleteTextures",
|
||||
"glDeleteVertexArrays",
|
||||
"glDetachShader",
|
||||
"glDisable",
|
||||
"glDisableVertexAttribArray",
|
||||
"glDrawElements",
|
||||
"glDrawElementsBaseVertex",
|
||||
"glEnable",
|
||||
"glEnableVertexAttribArray",
|
||||
"glFlush",
|
||||
"glGenBuffers",
|
||||
"glGenTextures",
|
||||
"glGenVertexArrays",
|
||||
"glGetAttribLocation",
|
||||
"glGetError",
|
||||
"glGetIntegerv",
|
||||
"glGetProgramInfoLog",
|
||||
"glGetProgramiv",
|
||||
"glGetShaderInfoLog",
|
||||
"glGetShaderiv",
|
||||
"glGetString",
|
||||
"glGetStringi",
|
||||
"glGetUniformLocation",
|
||||
"glGetVertexAttribPointerv",
|
||||
"glGetVertexAttribiv",
|
||||
"glIsEnabled",
|
||||
"glIsProgram",
|
||||
"glLinkProgram",
|
||||
"glPixelStorei",
|
||||
"glPolygonMode",
|
||||
"glReadPixels",
|
||||
"glScissor",
|
||||
"glShaderSource",
|
||||
"glTexImage2D",
|
||||
"glTexParameteri",
|
||||
"glUniform1i",
|
||||
"glUniformMatrix4fv",
|
||||
"glUseProgram",
|
||||
"glVertexAttribPointer",
|
||||
"glViewport",
|
||||
};
|
||||
|
||||
GL3W_API union ImGL3WProcs imgl3wProcs;
|
||||
|
||||
static void load_procs(GL3WGetProcAddressProc proc)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < GL3W_ARRAY_SIZE(proc_names); i++)
|
||||
imgl3wProcs.ptr[i] = proc(proc_names[i]);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -68,6 +68,8 @@
|
||||
#include "ResolvService.hpp"
|
||||
#include "RunQueue.hpp"
|
||||
|
||||
#include "GitRef.hpp"
|
||||
|
||||
|
||||
struct ClientData
|
||||
{
|
||||
@ -97,9 +99,8 @@ static char addr[1024] = { "127.0.0.1" };
|
||||
static ConnectionHistory* connHist;
|
||||
static std::atomic<ViewShutdown> viewShutdown { ViewShutdown::False };
|
||||
static double animTime = 0;
|
||||
static float dpiScale = 1.f;
|
||||
static float dpiScale = -1.f;
|
||||
static bool dpiScaleOverriddenFromEnv = false;
|
||||
static float userScale = 1.f;
|
||||
static float prevScale = 1.f;
|
||||
static int dpiChanged = 0;
|
||||
static bool dpiFirstSetup = true;
|
||||
@ -110,11 +111,11 @@ static bool showReleaseNotes = false;
|
||||
static std::string releaseNotes;
|
||||
static uint8_t* iconPx;
|
||||
static int iconX, iconY;
|
||||
static void* iconTex;
|
||||
static ImTextureID iconTex;
|
||||
static int iconTexSz;
|
||||
static uint8_t* zigzagPx[6];
|
||||
static int zigzagX[6], zigzagY[6];
|
||||
void* zigzagTex;
|
||||
ImTextureID zigzagTex;
|
||||
static Backend* bptr;
|
||||
static bool s_customTitle = false;
|
||||
static bool s_isElevated = false;
|
||||
@ -160,7 +161,7 @@ static void ScaleWindow(ImGuiWindow* window, float scale)
|
||||
|
||||
static void SetupDPIScale()
|
||||
{
|
||||
auto scale = dpiScale * userScale;
|
||||
auto scale = dpiScale * s_config.userScale;
|
||||
|
||||
if( !dpiFirstSetup && prevScale == scale ) return;
|
||||
dpiFirstSetup = false;
|
||||
@ -186,6 +187,7 @@ static void SetupDPIScale()
|
||||
style.Colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
|
||||
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
||||
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.45f);
|
||||
style.Colors[ImGuiCol_TitleBgCollapsed] = style.Colors[ImGuiCol_TitleBg];
|
||||
style.ScaleAllSizes( scale );
|
||||
|
||||
const auto ty = int( 80 * scale );
|
||||
@ -201,12 +203,6 @@ static void SetupDPIScale()
|
||||
for( auto& w : ctx->Windows ) ScaleWindow( w, ratio );
|
||||
}
|
||||
|
||||
static void SetupScaleCallback( float scale )
|
||||
{
|
||||
userScale = scale;
|
||||
RunOnMainThread( []{ SetupDPIScale(); }, true );
|
||||
}
|
||||
|
||||
static int IsBusy()
|
||||
{
|
||||
if( loadThread.joinable() ) return 2;
|
||||
@ -221,16 +217,22 @@ static void LoadConfig()
|
||||
if( !ini ) return;
|
||||
|
||||
int v;
|
||||
double v1;
|
||||
if( ini_sget( ini, "core", "threadedRendering", "%d", &v ) ) s_config.threadedRendering = v;
|
||||
if( ini_sget( ini, "core", "focusLostLimit", "%d", &v ) ) s_config.focusLostLimit = v;
|
||||
if( ini_sget( ini, "timeline", "targetFps", "%d", &v ) && v >= 1 && v < 10000 ) s_config.targetFps = v;
|
||||
if( ini_sget( ini, "timeline", "dynamicColors", "%d", &v ) ) s_config.dynamicColors = v;
|
||||
if( ini_sget( ini, "timeline", "forceColors", "%d", &v ) ) s_config.forceColors = v;
|
||||
if( ini_sget( ini, "timeline", "shortenName", "%d", &v ) ) s_config.shortenName = v;
|
||||
if( ini_sget( ini, "timeline", "horizontalScrollMultiplier", "%lf", &v1 ) && v1 > 0.0 ) s_config.horizontalScrollMultiplier = v1;
|
||||
if( ini_sget( ini, "timeline", "verticalScrollMultiplier", "%lf", &v1 ) && v1 > 0.0 ) s_config.verticalScrollMultiplier = v1;
|
||||
if( ini_sget( ini, "memory", "limit", "%d", &v ) ) s_config.memoryLimit = v;
|
||||
if( ini_sget( ini, "memory", "percent", "%d", &v ) && v >= 1 && v < 1000 ) s_config.memoryLimitPercent = v;
|
||||
if( ini_sget( ini, "achievements", "enabled", "%d", &v ) ) s_config.achievements = v;
|
||||
if( ini_sget( ini, "achievements", "asked", "%d", &v ) ) s_config.achievementsAsked = v;
|
||||
if( ini_sget( ini, "ui", "saveUserScale", "%d", &v ) ) s_config.saveUserScale = v;
|
||||
if( ini_sget( ini, "ui", "userScale", "%lf", &v1 ) && v1 > 0.0 && s_config.saveUserScale ) s_config.userScale = v1;
|
||||
|
||||
|
||||
ini_free( ini );
|
||||
}
|
||||
@ -250,6 +252,8 @@ static bool SaveConfig()
|
||||
fprintf( f, "dynamicColors = %i\n", s_config.dynamicColors );
|
||||
fprintf( f, "forceColors = %i\n", (int)s_config.forceColors );
|
||||
fprintf( f, "shortenName = %i\n", s_config.shortenName );
|
||||
fprintf( f, "horizontalScrollMultiplier = %lf\n", s_config.horizontalScrollMultiplier );
|
||||
fprintf( f, "verticalScrollMultiplier = %lf\n", s_config.verticalScrollMultiplier );
|
||||
|
||||
fprintf( f, "\n[memory]\n" );
|
||||
fprintf( f, "limit = %i\n", (int)s_config.memoryLimit );
|
||||
@ -259,14 +263,25 @@ static bool SaveConfig()
|
||||
fprintf( f, "enabled = %i\n", (int)s_config.achievements );
|
||||
fprintf( f, "asked = %i\n", (int)s_config.achievementsAsked );
|
||||
|
||||
fprintf( f, "\n[ui]\n" );
|
||||
fprintf( f, "saveUserScale = %i\n", (int)s_config.saveUserScale );
|
||||
fprintf( f, "userScale = %lf\n", s_config.userScale );
|
||||
|
||||
fclose( f );
|
||||
return true;
|
||||
}
|
||||
|
||||
static void SetupScaleCallback( float scale )
|
||||
{
|
||||
s_config.userScale = scale;
|
||||
if ( s_config.saveUserScale ) SaveConfig();
|
||||
RunOnMainThread( []{ SetupDPIScale(); }, true );
|
||||
}
|
||||
|
||||
static void ScaleChanged( float scale )
|
||||
{
|
||||
if ( dpiScaleOverriddenFromEnv ) return;
|
||||
if ( dpiScale == scale ) return;
|
||||
if( dpiScaleOverriddenFromEnv ) return;
|
||||
if( dpiScale == scale ) return;
|
||||
|
||||
dpiScale = scale;
|
||||
SetupDPIScale();
|
||||
@ -382,7 +397,6 @@ int main( int argc, char** argv )
|
||||
backend.SetIcon( iconPx, iconX, iconY );
|
||||
bptr = &backend;
|
||||
|
||||
dpiScale = backend.GetDpiScale();
|
||||
const auto envDpiScale = getenv( "TRACY_DPI_SCALE" );
|
||||
if( envDpiScale )
|
||||
{
|
||||
@ -391,13 +405,12 @@ int main( int argc, char** argv )
|
||||
{
|
||||
dpiScale = cnv;
|
||||
dpiScaleOverriddenFromEnv = true;
|
||||
SetupDPIScale();
|
||||
}
|
||||
}
|
||||
|
||||
s_achievements->Achieve( "achievementsIntro" );
|
||||
|
||||
SetupDPIScale();
|
||||
|
||||
tracy::UpdateTextureRGBAMips( zigzagTex, (void**)zigzagPx, zigzagX, zigzagY, 6 );
|
||||
for( auto& v : zigzagPx ) free( v );
|
||||
|
||||
@ -691,7 +704,7 @@ static void DrawContents()
|
||||
|
||||
auto& style = ImGui::GetStyle();
|
||||
style.Colors[ImGuiCol_WindowBg] = ImVec4( 0.129f, 0.137f, 0.11f, 1.f );
|
||||
ImGui::Begin( "Get started", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse );
|
||||
ImGui::Begin( "Get started", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings );
|
||||
char buf[128];
|
||||
sprintf( buf, "Tracy Profiler %i.%i.%i", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch );
|
||||
ImGui::PushFont( s_bigFont );
|
||||
@ -713,6 +726,28 @@ static void DrawContents()
|
||||
ImGui::PushFont( s_bigFont );
|
||||
tracy::TextCentered( buf );
|
||||
ImGui::PopFont();
|
||||
ImGui::PushFont( s_smallFont );
|
||||
ImGui::PushStyleColor( ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled] );
|
||||
tracy::TextCentered( tracy::GitRef );
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopFont();
|
||||
if( ImGui::IsItemHovered() )
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted( "Click to copy git reference to clipboard" );
|
||||
ImGui::EndTooltip();
|
||||
if( ImGui::IsItemClicked() )
|
||||
{
|
||||
ImGui::SetClipboardText( tracy::GitRef );
|
||||
}
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
ImGui::PushFont( s_smallFont );
|
||||
ImGui::PushStyleColor( ImGuiCol_Text, ImVec4( 1.f, 0.5f, 0.5f, 1.f ) );
|
||||
tracy::TextCentered( "Debug build" );
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopFont();
|
||||
#endif
|
||||
ImGui::Spacing();
|
||||
ImGui::TextUnformatted( "A real time, nanosecond resolution, remote telemetry, hybrid\nframe and sampling profiler for games and other applications." );
|
||||
ImGui::Spacing();
|
||||
@ -771,6 +806,19 @@ static void DrawContents()
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Unindent();
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::TextUnformatted( "Scroll Multipliers" );
|
||||
ImGui::SameLine();
|
||||
tracy::DrawHelpMarker( "The multipliers to the amount to scroll by horizontally and vertically. This is used in the timeline and setting this value can help compensate for scroll wheel sensitivity." );
|
||||
ImGui::SameLine();
|
||||
double tmpScroll = s_config.horizontalScrollMultiplier;
|
||||
ImGui::SetNextItemWidth( 45 * dpiScale );
|
||||
if( ImGui::InputDouble( "##horizontalscrollmultiplier", &tmpScroll ) ) { s_config.horizontalScrollMultiplier = std::max( tmpScroll, 0.01 ); SaveConfig(); }
|
||||
tmpScroll = s_config.verticalScrollMultiplier;
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth( 45 * dpiScale );
|
||||
if( ImGui::InputDouble( "##verticalscrollmultiplier", &tmpScroll ) ) { s_config.verticalScrollMultiplier = std::max( tmpScroll, 0.01 ); SaveConfig(); }
|
||||
|
||||
if( s_totalMem == 0 )
|
||||
{
|
||||
ImGui::BeginDisabled();
|
||||
@ -798,6 +846,7 @@ static void DrawContents()
|
||||
|
||||
ImGui::Spacing();
|
||||
if( ImGui::Checkbox( "Enable achievements", &s_config.achievements ) ) SaveConfig();
|
||||
if( ImGui::Checkbox( "Save UI scale", &s_config.saveUserScale) ) SaveConfig();
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::TreePop();
|
||||
@ -908,13 +957,15 @@ static void DrawContents()
|
||||
if( s_isElevated )
|
||||
{
|
||||
ImGui::Separator();
|
||||
ImGui::TextColored( ImVec4( 1, 0.25f, 0.25f, 1 ), ICON_FA_TRIANGLE_EXCLAMATION " Profiler has elevated privileges! " ICON_FA_TRIANGLE_EXCLAMATION );
|
||||
ImGui::PushStyleColor( ImGuiCol_Text, ImVec4( 1.f, 0.25f, 0.25f, 1.f ) );
|
||||
tracy::TextCentered( ICON_FA_TRIANGLE_EXCLAMATION " Profiler has elevated privileges! " ICON_FA_TRIANGLE_EXCLAMATION );
|
||||
ImGui::PushFont( s_smallFont );
|
||||
ImGui::TextColored( ImVec4( 1, 0.25f, 0.25f, 1 ), "You are running the profiler interface with admin privileges. This is" );
|
||||
ImGui::TextColored( ImVec4( 1, 0.25f, 0.25f, 1 ), "most likely a mistake, as there is no reason to do so. Instead, you" );
|
||||
ImGui::TextColored( ImVec4( 1, 0.25f, 0.25f, 1 ), "probably wanted to run the client (the application you are profiling)" );
|
||||
ImGui::TextColored( ImVec4( 1, 0.25f, 0.25f, 1 ), "with elevated privileges." );
|
||||
tracy::TextCentered( "You are running the profiler interface with admin privileges. This is" );
|
||||
tracy::TextCentered( "most likely a mistake, as there is no reason to do so. Instead, you" );
|
||||
tracy::TextCentered( "probably wanted to run the client (the application you are profiling)" );
|
||||
tracy::TextCentered( "with elevated privileges." );
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::Separator();
|
||||
ImGui::TextUnformatted( "Client address" );
|
||||
@ -934,7 +985,7 @@ static void DrawContents()
|
||||
{
|
||||
memcpy( addr, str.c_str(), str.size() + 1 );
|
||||
}
|
||||
if( ImGui::IsItemHovered() && ImGui::IsKeyPressed( ImGui::GetKeyIndex( ImGuiKey_Delete ), false ) )
|
||||
if( ImGui::IsItemHovered() && ImGui::IsKeyPressed( ImGuiKey_Delete, false ) )
|
||||
{
|
||||
idxRemove = (int)i;
|
||||
}
|
||||
@ -946,23 +997,39 @@ static void DrawContents()
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
#ifdef __EMSCRIPTEN__
|
||||
ImGui::BeginDisabled();
|
||||
#endif
|
||||
connectClicked |= ImGui::Button( ICON_FA_WIFI " Connect" );
|
||||
#ifdef __EMSCRIPTEN__
|
||||
ImGui::EndDisabled();
|
||||
connectClicked = false;
|
||||
#endif
|
||||
if( connectClicked && *addr && !loadThread.joinable() )
|
||||
{
|
||||
connHist->Count( addr );
|
||||
auto aptr = addr;
|
||||
while( *aptr == ' ' || *aptr == '\t' ) aptr++;
|
||||
auto aend = aptr;
|
||||
while( *aend && *aend != ' ' && *aend != '\t' ) aend++;
|
||||
|
||||
const auto addrLen = strlen( addr );
|
||||
auto ptr = addr + addrLen - 1;
|
||||
while( ptr > addr && *ptr != ':' ) ptr--;
|
||||
if( *ptr == ':' )
|
||||
if( aptr != aend )
|
||||
{
|
||||
std::string addrPart = std::string( addr, ptr );
|
||||
uint16_t portPart = (uint16_t)atoi( ptr+1 );
|
||||
view = std::make_unique<tracy::View>( RunOnMainThread, addrPart.c_str(), portPart, s_fixedWidth, s_smallFont, s_bigFont, SetWindowTitleCallback, SetupScaleCallback, AttentionCallback, s_config, s_achievements );
|
||||
}
|
||||
else
|
||||
{
|
||||
view = std::make_unique<tracy::View>( RunOnMainThread, addr, port, s_fixedWidth, s_smallFont, s_bigFont, SetWindowTitleCallback, SetupScaleCallback, AttentionCallback, s_config, s_achievements );
|
||||
std::string address( aptr, aend );
|
||||
connHist->Count( address );
|
||||
|
||||
auto adata = address.data();
|
||||
auto ptr = adata + address.size() - 1;
|
||||
while( ptr > adata && *ptr != ':' ) ptr--;
|
||||
if( *ptr == ':' )
|
||||
{
|
||||
std::string addrPart = std::string( adata, ptr );
|
||||
uint16_t portPart = (uint16_t)atoi( ptr+1 );
|
||||
view = std::make_unique<tracy::View>( RunOnMainThread, addrPart.c_str(), portPart, s_fixedWidth, s_smallFont, s_bigFont, SetWindowTitleCallback, SetupScaleCallback, AttentionCallback, s_config, s_achievements );
|
||||
}
|
||||
else
|
||||
{
|
||||
view = std::make_unique<tracy::View>( RunOnMainThread, address.c_str(), port, s_fixedWidth, s_smallFont, s_bigFont, SetWindowTitleCallback, SetupScaleCallback, AttentionCallback, s_config, s_achievements );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( s_config.memoryLimit )
|
||||
@ -1208,7 +1275,7 @@ static void DrawContents()
|
||||
{
|
||||
ImGui::OpenPopup( "Loading trace..." );
|
||||
}
|
||||
if( ImGui::BeginPopupModal( "Loading trace...", nullptr, ImGuiWindowFlags_AlwaysAutoResize ) )
|
||||
if( ImGui::BeginPopupModal( "Loading trace...", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings) )
|
||||
{
|
||||
ImGui::PushFont( s_bigFont );
|
||||
tracy::TextCentered( ICON_FA_HOURGLASS_HALF );
|
||||
|
@ -20,6 +20,14 @@ static tracy_force_inline uint32_t HighlightColor( uint32_t color )
|
||||
( std::min<int>( 0xFF, ( ( ( color & 0x000000FF ) ) + V ) ) );
|
||||
}
|
||||
|
||||
static tracy_force_inline uint32_t DarkenColorSlightly( uint32_t color )
|
||||
{
|
||||
return 0xFF000000 |
|
||||
( ( ( ( color & 0x00FF0000 ) >> 16 ) * 4 / 5 ) << 16 ) |
|
||||
( ( ( ( color & 0x0000FF00 ) >> 8 ) * 4 / 5 ) << 8 ) |
|
||||
( ( ( ( color & 0x000000FF ) ) * 4 / 5 ) );
|
||||
}
|
||||
|
||||
static tracy_force_inline uint32_t DarkenColor( uint32_t color )
|
||||
{
|
||||
return 0xFF000000 |
|
||||
@ -28,6 +36,14 @@ static tracy_force_inline uint32_t DarkenColor( uint32_t color )
|
||||
( ( ( ( color & 0x000000FF ) ) * 2 / 3 ) );
|
||||
}
|
||||
|
||||
static tracy_force_inline uint32_t DarkenColorHalf( uint32_t color )
|
||||
{
|
||||
return 0xFF000000 |
|
||||
( ( ( ( color & 0x00FF0000 ) >> 16 ) / 2 ) << 16 ) |
|
||||
( ( ( ( color & 0x0000FF00 ) >> 8 ) / 2 ) << 8 ) |
|
||||
( ( ( ( color & 0x000000FF ) ) / 2 ) );
|
||||
}
|
||||
|
||||
static tracy_force_inline uint32_t DarkenColorMore( uint32_t color )
|
||||
{
|
||||
return 0xFF000000 |
|
||||
|
@ -11,6 +11,8 @@ struct Config
|
||||
bool threadedRendering = true;
|
||||
bool focusLostLimit = true;
|
||||
int targetFps = 60;
|
||||
double horizontalScrollMultiplier = 1.0;
|
||||
double verticalScrollMultiplier = 1.0;
|
||||
bool memoryLimit = false;
|
||||
int memoryLimitPercent = 80;
|
||||
bool achievements = false;
|
||||
@ -18,6 +20,8 @@ struct Config
|
||||
int dynamicColors = 1;
|
||||
bool forceColors = false;
|
||||
int shortenName = (int)ShortenName::NoSpaceAndNormalize;
|
||||
bool saveUserScale = false;
|
||||
float userScale = 1.0f;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "TracyPrint.hpp"
|
||||
#include "TracyImGui.hpp"
|
||||
|
||||
extern void* zigzagTex;
|
||||
extern ImTextureID zigzagTex;
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
|
@ -83,6 +83,13 @@ static constexpr const uint32_t AsmSyntaxColors[] = {
|
||||
ImGui::TextUnformatted( text );
|
||||
}
|
||||
|
||||
[[maybe_unused]] static inline bool ButtonCentered( const char* text )
|
||||
{
|
||||
const auto tw = ImGui::CalcTextSize( text ).x + ImGui::GetStyle().FramePadding.x * 2;
|
||||
ImGui::SetCursorPosX( ( ImGui::GetWindowWidth() - tw ) * 0.5f );
|
||||
return ImGui::Button( text );
|
||||
}
|
||||
|
||||
[[maybe_unused]] static inline void TextColoredUnformatted( uint32_t col, const char* text, const char* end = nullptr )
|
||||
{
|
||||
ImGui::PushStyleColor( ImGuiCol_Text, col );
|
||||
|
@ -5,6 +5,7 @@ namespace tracy
|
||||
{
|
||||
|
||||
constexpr ProtocolHistory_t ProtocolHistoryArr[] = {
|
||||
{ 69, FileVersion( 0, 11, 1 ) },
|
||||
{ 66, FileVersion( 0, 11, 0 ) },
|
||||
{ 64, FileVersion( 0, 10, 0 ) },
|
||||
{ 63, FileVersion( 0, 9, 0 ), FileVersion( 0, 9, 1 ) },
|
||||
|
@ -9,8 +9,9 @@ SourceContents::SourceContents()
|
||||
: m_file( nullptr )
|
||||
, m_fileStringIdx( 0 )
|
||||
, m_data( nullptr )
|
||||
, m_dataBuf( nullptr )
|
||||
, m_dataSize( 0 )
|
||||
, m_dataBuf( nullptr )
|
||||
, m_dataBufSize( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
@ -44,14 +45,15 @@ void SourceContents::Parse( const char* fileName, const Worker& worker, const Vi
|
||||
fseek( f, 0, SEEK_END );
|
||||
sz = ftell( f );
|
||||
fseek( f, 0, SEEK_SET );
|
||||
if( sz > m_dataSize )
|
||||
if( sz > m_dataBufSize )
|
||||
{
|
||||
delete[] m_dataBuf;
|
||||
m_dataBuf = new char[sz];
|
||||
m_dataSize = sz;
|
||||
m_dataBufSize = sz;
|
||||
}
|
||||
fread( m_dataBuf, 1, sz, f );
|
||||
m_data = m_dataBuf;
|
||||
m_dataSize = sz;
|
||||
fclose( f );
|
||||
}
|
||||
else
|
||||
@ -73,7 +75,6 @@ void SourceContents::Parse( const char* source )
|
||||
m_file = nullptr;
|
||||
m_fileStringIdx = 0;
|
||||
m_data = source;
|
||||
m_dataBuf = nullptr;
|
||||
m_dataSize = len;
|
||||
Tokenize( source, len );
|
||||
}
|
||||
|
@ -38,9 +38,11 @@ private:
|
||||
uint32_t m_fileStringIdx;
|
||||
|
||||
const char* m_data;
|
||||
char* m_dataBuf;
|
||||
size_t m_dataSize;
|
||||
|
||||
char* m_dataBuf;
|
||||
size_t m_dataBufSize;
|
||||
|
||||
std::vector<Tokenizer::Line> m_lines;
|
||||
};
|
||||
|
||||
|
@ -13,11 +13,11 @@
|
||||
#include "TracyImGui.hpp"
|
||||
#include "TracyMicroArchitecture.hpp"
|
||||
#include "TracyPrint.hpp"
|
||||
#include "TracySort.hpp"
|
||||
#include "TracySourceView.hpp"
|
||||
#include "TracyUtility.hpp"
|
||||
#include "TracyView.hpp"
|
||||
#include "TracyWorker.hpp"
|
||||
#include "tracy_pdqsort.h"
|
||||
|
||||
#include "IconsFontAwesome6.h"
|
||||
|
||||
@ -712,7 +712,7 @@ bool SourceView::Disassemble( uint64_t symAddr, const Worker& worker )
|
||||
rval = cs_open( CS_ARCH_ARM, CS_MODE_ARM, &handle );
|
||||
break;
|
||||
case CpuArchArm64:
|
||||
rval = cs_open( CS_ARCH_ARM64, CS_MODE_ARM, &handle );
|
||||
rval = cs_open( CS_ARCH_AARCH64, CS_MODE_ARM, &handle );
|
||||
break;
|
||||
default:
|
||||
assert( false );
|
||||
@ -777,9 +777,9 @@ bool SourceView::Disassemble( uint64_t symAddr, const Worker& worker )
|
||||
}
|
||||
break;
|
||||
case CpuArchArm64:
|
||||
if( detail.arm64.op_count == 1 && detail.arm64.operands[0].type == ARM64_OP_IMM )
|
||||
if( detail.aarch64.op_count == 1 && detail.aarch64.operands[0].type == AARCH64_OP_IMM )
|
||||
{
|
||||
jumpAddr = (uint64_t)detail.arm64.operands[0].imm;
|
||||
jumpAddr = (uint64_t)detail.aarch64.operands[0].imm;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -864,18 +864,18 @@ bool SourceView::Disassemble( uint64_t symAddr, const Worker& worker )
|
||||
}
|
||||
break;
|
||||
case CpuArchArm64:
|
||||
for( uint8_t i=0; i<detail.arm64.op_count; i++ )
|
||||
for( uint8_t i=0; i<detail.aarch64.op_count; i++ )
|
||||
{
|
||||
uint8_t type = 0;
|
||||
switch( detail.arm64.operands[i].type )
|
||||
switch( detail.aarch64.operands[i].type )
|
||||
{
|
||||
case ARM64_OP_IMM:
|
||||
case AARCH64_OP_IMM:
|
||||
type = 0;
|
||||
break;
|
||||
case ARM64_OP_REG:
|
||||
case AARCH64_OP_REG:
|
||||
type = 1;
|
||||
break;
|
||||
case ARM64_OP_MEM:
|
||||
case AARCH64_OP_MEM:
|
||||
type = 2;
|
||||
break;
|
||||
default:
|
||||
@ -1233,12 +1233,18 @@ void SourceView::RenderSymbolView( Worker& worker, View& view )
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::TextDisabled( "(+%s inlined functions)", RealToString( inlineCount ) );
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
if( ImGui::SmallButton( ICON_FA_ARROW_DOWN_SHORT_WIDE " Entry stacks" ) ) view.ShowSampleParents( m_symAddr, !m_calcInlineStats );
|
||||
if( inlineList )
|
||||
{
|
||||
if( m_calcInlineStats )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
TextColoredUnformatted( ImVec4( 1.f, 1.f, 0.2f, 1.f ), ICON_FA_TRIANGLE_EXCLAMATION );
|
||||
TooltipIfHovered( "Context is limited to an inline function" );
|
||||
ImGui::SameLine();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
TextColoredUnformatted( ImVec4( 1.f, 1.f, 0.2f, 1.f ), ICON_FA_TRIANGLE_EXCLAMATION );
|
||||
TooltipIfHovered( "Context is limited to an inline function" );
|
||||
}
|
||||
}
|
||||
|
||||
@ -1848,7 +1854,7 @@ static uint32_t GetGoodnessColor( float inRatio )
|
||||
void SourceView::RenderSymbolSourceView( const AddrStatData& as, Worker& worker, const View& view, bool hasInlines )
|
||||
{
|
||||
const auto scale = GetScale();
|
||||
if( hasInlines && !m_calcInlineStats && ( as.ipTotalAsm.local + as.ipTotalAsm.ext ) > 0 || ( view.m_statRange.active && worker.GetSamplesForSymbol( m_baseAddr ) ) )
|
||||
if( hasInlines && !m_calcInlineStats && ( ( as.ipTotalAsm.local + as.ipTotalAsm.ext ) > 0 || ( view.m_statRange.active && worker.GetSamplesForSymbol( m_baseAddr ) ) ) )
|
||||
{
|
||||
const auto samplesReady = worker.AreSymbolSamplesReady();
|
||||
if( !samplesReady )
|
||||
@ -1990,10 +1996,8 @@ void SourceView::RenderSymbolSourceView( const AddrStatData& as, Worker& worker,
|
||||
if( !widthSet )
|
||||
{
|
||||
widthSet = true;
|
||||
const auto w = ImGui::GetWindowWidth();
|
||||
const auto c0 = ImGui::CalcTextSize( "12345678901234567890" ).x;
|
||||
ImGui::SetColumnWidth( 0, c0 );
|
||||
ImGui::SetColumnWidth( 1, w - c0 );
|
||||
}
|
||||
}
|
||||
for( auto& v : fileCountsVec )
|
||||
@ -2872,6 +2876,9 @@ uint64_t SourceView::RenderSymbolAsmView( const AddrStatData& as, Worker& worker
|
||||
}
|
||||
if( ImGui::BeginPopup( "localCallstackPopup" ) )
|
||||
{
|
||||
ImGui::PushFont( m_smallFont );
|
||||
TextDisabledUnformatted( "Local call stack:" );
|
||||
ImGui::PopFont();
|
||||
const auto lcs = m_localCallstackPopup;
|
||||
for( uint8_t i=0; i<lcs->size; i++ )
|
||||
{
|
||||
@ -3952,14 +3959,15 @@ void SourceView::RenderAsmLine( AsmLine& line, const AddrStat& ipcnt, const Addr
|
||||
SetFont();
|
||||
if( ImGui::IsItemClicked( 0 ) )
|
||||
{
|
||||
m_targetLine = srcline;
|
||||
if( m_source.filename() == fileName )
|
||||
{
|
||||
m_targetLine = srcline;
|
||||
SelectLine( srcline, &worker, false );
|
||||
m_displayMode = DisplayMixed;
|
||||
}
|
||||
else if( SourceFileValid( fileName, worker.GetCaptureTime(), view, worker ) )
|
||||
{
|
||||
m_targetLine = srcline;
|
||||
ParseSource( fileName, worker, view );
|
||||
SelectLine( srcline, &worker, false );
|
||||
SelectViewMode();
|
||||
|
@ -72,11 +72,11 @@ private:
|
||||
rd
|
||||
};
|
||||
|
||||
enum { ReadBit = 0x100 };
|
||||
enum { WriteBit = 0x200 };
|
||||
enum { ReuseBit = 0x400 };
|
||||
enum { RegMask = 0x0FF };
|
||||
enum { FlagMask = 0xF00 };
|
||||
static constexpr int ReadBit = 0x100;
|
||||
static constexpr int WriteBit = 0x200;
|
||||
static constexpr int ReuseBit = 0x400;
|
||||
static constexpr int RegMask = 0x0FF;
|
||||
static constexpr int FlagMask = 0xF00;
|
||||
|
||||
enum class OpType : uint8_t
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
# include <emscripten/html5.h>
|
||||
# include <GLES2/gl2.h>
|
||||
#else
|
||||
# include "../profiler/src/imgui/imgui_impl_opengl3_loader.h"
|
||||
# include <backends/imgui_impl_opengl3_loader.h>
|
||||
#endif
|
||||
#include "TracyTexture.hpp"
|
||||
#include "../public/common/TracyForceInline.hpp"
|
||||
@ -39,7 +39,7 @@ void InitTexture()
|
||||
#endif
|
||||
}
|
||||
|
||||
void* MakeTexture( bool zigzag )
|
||||
ImTextureID MakeTexture( bool zigzag )
|
||||
{
|
||||
GLuint tex;
|
||||
glGenTextures( 1, &tex );
|
||||
@ -48,12 +48,12 @@ void* MakeTexture( bool zigzag )
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, zigzag ? GL_REPEAT : GL_CLAMP_TO_EDGE );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
|
||||
return (void*)(intptr_t)tex;
|
||||
return tex;
|
||||
}
|
||||
|
||||
void FreeTexture( void* _tex, void(*runOnMainThread)(const std::function<void()>&, bool) )
|
||||
void FreeTexture( ImTextureID _tex, void(*runOnMainThread)(const std::function<void()>&, bool) )
|
||||
{
|
||||
auto tex = (GLuint)(intptr_t)_tex;
|
||||
auto tex = (GLuint)_tex;
|
||||
runOnMainThread( [tex] { glDeleteTextures( 1, &tex ); }, false );
|
||||
}
|
||||
|
||||
@ -139,9 +139,9 @@ static tracy_force_inline void DecodeDxt1Part( uint64_t d, uint32_t* dst, uint32
|
||||
memcpy( dst+3, dict + (idx & 0x3), 4 );
|
||||
}
|
||||
|
||||
void UpdateTexture( void* _tex, const char* data, int w, int h )
|
||||
void UpdateTexture( ImTextureID _tex, const char* data, int w, int h )
|
||||
{
|
||||
auto tex = (GLuint)(intptr_t)_tex;
|
||||
auto tex = (GLuint)_tex;
|
||||
glBindTexture( GL_TEXTURE_2D, tex );
|
||||
if( s_hardwareS3tc )
|
||||
{
|
||||
@ -167,16 +167,16 @@ void UpdateTexture( void* _tex, const char* data, int w, int h )
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateTextureRGBA( void* _tex, void* data, int w, int h )
|
||||
void UpdateTextureRGBA( ImTextureID _tex, void* data, int w, int h )
|
||||
{
|
||||
auto tex = (GLuint)(intptr_t)_tex;
|
||||
auto tex = (GLuint)_tex;
|
||||
glBindTexture( GL_TEXTURE_2D, tex );
|
||||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
|
||||
}
|
||||
|
||||
void UpdateTextureRGBAMips( void* _tex, void** data, int* w, int* h, size_t mips )
|
||||
void UpdateTextureRGBAMips( ImTextureID _tex, void** data, int* w, int* h, size_t mips )
|
||||
{
|
||||
auto tex = (GLuint)(intptr_t)_tex;
|
||||
auto tex = (GLuint)_tex;
|
||||
glBindTexture( GL_TEXTURE_2D, tex );
|
||||
for( size_t i=0; i<mips; i++ )
|
||||
{
|
||||
|
@ -2,16 +2,17 @@
|
||||
#define __TRACYTEXTURE_HPP__
|
||||
|
||||
#include <functional>
|
||||
#include <imgui.h>
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
|
||||
void InitTexture();
|
||||
void* MakeTexture( bool zigzag = false );
|
||||
void FreeTexture( void* tex, void(*runOnMainThread)(const std::function<void()>&, bool) );
|
||||
void UpdateTexture( void* tex, const char* data, int w, int h );
|
||||
void UpdateTextureRGBA( void* tex, void* data, int w, int h );
|
||||
void UpdateTextureRGBAMips( void* tex, void** data, int* w, int* h, size_t mips );
|
||||
ImTextureID MakeTexture( bool zigzag = false );
|
||||
void FreeTexture( ImTextureID tex, void(*runOnMainThread)(const std::function<void()>&, bool) );
|
||||
void UpdateTexture( ImTextureID tex, const char* data, int w, int h );
|
||||
void UpdateTextureRGBA( ImTextureID tex, void* data, int w, int h );
|
||||
void UpdateTextureRGBAMips( ImTextureID tex, void** data, int* w, int* h, size_t mips );
|
||||
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ TimelineController::TimelineController( View& view, Worker& worker, bool threadi
|
||||
, m_view( view )
|
||||
, m_worker( worker )
|
||||
#ifdef __EMSCRIPTEN__
|
||||
, m_td( 0, "Render" )
|
||||
, m_td( threading ? 2 : 0, "Render" )
|
||||
#else
|
||||
, m_td( threading ? (size_t)std::max( 0, ( (int)std::thread::hardware_concurrency() - 2 ) / 2 ) : 0, "Render" )
|
||||
#endif
|
||||
|
@ -24,6 +24,7 @@ struct TimelineDraw
|
||||
short_ptr<void*> ev;
|
||||
Int48 rend;
|
||||
uint32_t num;
|
||||
uint32_t inheritedColor;
|
||||
};
|
||||
|
||||
|
||||
|
@ -42,7 +42,8 @@ void TimelineItemGpu::HeaderTooltip( const char* label ) const
|
||||
const bool isMultithreaded =
|
||||
( m_gpu->type == GpuContextType::Vulkan ) ||
|
||||
( m_gpu->type == GpuContextType::OpenCL ) ||
|
||||
( m_gpu->type == GpuContextType::Direct3D12 );
|
||||
( m_gpu->type == GpuContextType::Direct3D12 ) ||
|
||||
( m_gpu->type == GpuContextType::Metal );
|
||||
|
||||
char buf[64];
|
||||
sprintf( buf, "%s context %i", GpuContextNames[(int)m_gpu->type], m_idx );
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "TracyUtility.hpp"
|
||||
#include "TracyView.hpp"
|
||||
#include "TracyWorker.hpp"
|
||||
#include "tracy_pdqsort.h"
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
@ -111,7 +112,7 @@ int64_t TimelineItemPlot::RangeEnd() const
|
||||
|
||||
bool TimelineItemPlot::DrawContents( const TimelineContext& ctx, int& offset )
|
||||
{
|
||||
return m_view.DrawPlot( ctx, *m_plot, m_draw, offset );
|
||||
return m_view.DrawPlot( ctx, *m_plot, m_draw, offset, m_rightEnd );
|
||||
}
|
||||
|
||||
void TimelineItemPlot::DrawFinished()
|
||||
@ -137,17 +138,30 @@ void TimelineItemPlot::Preprocess( const TimelineContext& ctx, TaskDispatch& td,
|
||||
|
||||
auto& vec = m_plot->data;
|
||||
vec.ensure_sorted();
|
||||
if( vec.front().time.Val() > vEnd || vec.back().time.Val() < vStart )
|
||||
if( vec.front().time.Val() > vEnd )
|
||||
{
|
||||
m_plot->rMin = 0;
|
||||
m_plot->rMax = 0;
|
||||
m_plot->num = 0;
|
||||
m_rightEnd = false;
|
||||
return;
|
||||
}
|
||||
else if( vec.back().time.Val() < vStart )
|
||||
{
|
||||
const auto lastTime = m_worker.GetLastTime();
|
||||
const auto val = vec.back().val;
|
||||
m_plot->rMin = val - 1;
|
||||
m_plot->rMax = val + 1;
|
||||
m_plot->num = lastTime < vStart ? 0 : 1;
|
||||
m_rightEnd = vec.back().time.Val() < lastTime;
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = std::lower_bound( vec.begin(), vec.end(), vStart, [] ( const auto& l, const auto& r ) { return l.time.Val() < r; } );
|
||||
auto end = std::lower_bound( it, vec.end(), vEnd, [] ( const auto& l, const auto& r ) { return l.time.Val() < r; } );
|
||||
|
||||
m_rightEnd = end == vec.end() && vec.back().time.Val() < m_worker.GetLastTime();
|
||||
|
||||
if( end != vec.end() ) end++;
|
||||
if( it != vec.begin() ) it--;
|
||||
|
||||
|
@ -36,6 +36,7 @@ private:
|
||||
PlotData* m_plot;
|
||||
|
||||
std::vector<uint32_t> m_draw;
|
||||
bool m_rightEnd;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "TracyColor.hpp"
|
||||
#include "TracyImGui.hpp"
|
||||
#include "TracyLockHelpers.hpp"
|
||||
#include "TracyMouse.hpp"
|
||||
@ -300,7 +301,7 @@ void TimelineItemThread::Preprocess( const TimelineContext& ctx, TaskDispatch& t
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_depth = PreprocessZoneLevel( ctx, m_thread->timeline, 0, visible );
|
||||
m_depth = PreprocessZoneLevel( ctx, m_thread->timeline, 0, visible, 0 );
|
||||
}
|
||||
} );
|
||||
|
||||
@ -399,20 +400,20 @@ int TimelineItemThread::PreprocessGhostLevel( const TimelineContext& ctx, const
|
||||
}
|
||||
#endif
|
||||
|
||||
int TimelineItemThread::PreprocessZoneLevel( const TimelineContext& ctx, const Vector<short_ptr<ZoneEvent>>& vec, int depth, bool visible )
|
||||
int TimelineItemThread::PreprocessZoneLevel( const TimelineContext& ctx, const Vector<short_ptr<ZoneEvent>>& vec, int depth, bool visible, const uint32_t inheritedColor )
|
||||
{
|
||||
if( vec.is_magic() )
|
||||
{
|
||||
return PreprocessZoneLevel<VectorAdapterDirect<ZoneEvent>>( ctx, *(Vector<ZoneEvent>*)( &vec ), depth, visible );
|
||||
return PreprocessZoneLevel<VectorAdapterDirect<ZoneEvent>>( ctx, *(Vector<ZoneEvent>*)( &vec ), depth, visible, inheritedColor );
|
||||
}
|
||||
else
|
||||
{
|
||||
return PreprocessZoneLevel<VectorAdapterPointer<ZoneEvent>>( ctx, vec, depth, visible );
|
||||
return PreprocessZoneLevel<VectorAdapterPointer<ZoneEvent>>( ctx, vec, depth, visible, inheritedColor );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Adapter, typename V>
|
||||
int TimelineItemThread::PreprocessZoneLevel( const TimelineContext& ctx, const V& vec, int depth, bool visible )
|
||||
int TimelineItemThread::PreprocessZoneLevel( const TimelineContext& ctx, const V& vec, int depth, bool visible, const uint32_t inheritedColor )
|
||||
{
|
||||
const auto vStart = ctx.vStart;
|
||||
const auto vEnd = ctx.vEnd;
|
||||
@ -450,17 +451,39 @@ int TimelineItemThread::PreprocessZoneLevel( const TimelineContext& ctx, const V
|
||||
if( nt - pt >= MinVisNs ) break;
|
||||
nextTime = nt + MinVisNs;
|
||||
}
|
||||
if( visible ) m_draw.emplace_back( TimelineDraw { TimelineDrawType::Folded, uint16_t( depth ), (void**)&ev, m_worker.GetZoneEnd( a(*(next-1)) ), uint32_t( next - it ) } );
|
||||
if( visible ) m_draw.emplace_back( TimelineDraw { TimelineDrawType::Folded, uint16_t( depth ), (void**)&ev, m_worker.GetZoneEnd( a(*(next-1)) ), uint32_t( next - it ), inheritedColor } );
|
||||
it = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ev.HasChildren() )
|
||||
const auto hasChildren = ev.HasChildren();
|
||||
auto currentInherited = inheritedColor;
|
||||
auto childrenInherited = inheritedColor;
|
||||
if( m_view.GetViewData().inheritParentColors )
|
||||
{
|
||||
const auto d = PreprocessZoneLevel( ctx, m_worker.GetZoneChildren( ev.Child() ), depth + 1, visible );
|
||||
uint32_t color = 0;
|
||||
if( m_worker.HasZoneExtra( ev ) )
|
||||
{
|
||||
const auto& extra = m_worker.GetZoneExtra( ev );
|
||||
color = extra.color.Val();
|
||||
}
|
||||
if( color == 0 )
|
||||
{
|
||||
auto& srcloc = m_worker.GetSourceLocation( ev.SrcLoc() );
|
||||
color = srcloc.color;
|
||||
}
|
||||
if( color != 0 )
|
||||
{
|
||||
currentInherited = color | 0xFF000000;
|
||||
if( hasChildren ) childrenInherited = DarkenColorSlightly( color );
|
||||
}
|
||||
}
|
||||
if( hasChildren )
|
||||
{
|
||||
const auto d = PreprocessZoneLevel( ctx, m_worker.GetZoneChildren( ev.Child() ), depth + 1, visible, childrenInherited );
|
||||
if( d > maxdepth ) maxdepth = d;
|
||||
}
|
||||
if( visible ) m_draw.emplace_back( TimelineDraw { TimelineDrawType::Zone, uint16_t( depth ), (void**)&ev } );
|
||||
if( visible ) m_draw.emplace_back( TimelineDraw { TimelineDrawType::Zone, uint16_t( depth ), (void**)&ev, 0, 0, currentInherited } );
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
@ -37,10 +37,10 @@ private:
|
||||
#ifndef TRACY_NO_STATISTICS
|
||||
int PreprocessGhostLevel( const TimelineContext& ctx, const Vector<GhostZone>& vec, int depth, bool visible );
|
||||
#endif
|
||||
int PreprocessZoneLevel( const TimelineContext& ctx, const Vector<short_ptr<ZoneEvent>>& vec, int depth, bool visible );
|
||||
int PreprocessZoneLevel( const TimelineContext& ctx, const Vector<short_ptr<ZoneEvent>>& vec, int depth, bool visible, const uint32_t inheritedColor );
|
||||
|
||||
template<typename Adapter, typename V>
|
||||
int PreprocessZoneLevel( const TimelineContext& ctx, const V& vec, int depth, bool visible );
|
||||
int PreprocessZoneLevel( const TimelineContext& ctx, const V& vec, int depth, bool visible, const uint32_t inheritedColor );
|
||||
|
||||
void PreprocessContextSwitches( const TimelineContext& ctx, const ContextSwitch& ctxSwitch, bool visible );
|
||||
void PreprocessSamples( const TimelineContext& ctx, const Vector<SampleData>& vec, bool visible, int yPos );
|
||||
|
@ -145,6 +145,7 @@ void UserData::LoadState( ViewData& data )
|
||||
if( ini_sget( ini, "options", "drawCpuUsageGraph", "%d", &v ) ) data.drawCpuUsageGraph = v;
|
||||
if( ini_sget( ini, "options", "drawSamples", "%d", &v ) ) data.drawSamples = v;
|
||||
if( ini_sget( ini, "options", "dynamicColors", "%d", &v ) ) data.dynamicColors = v;
|
||||
if( ini_sget( ini, "options", "inheritParentColors", "%d", &v ) ) data.inheritParentColors = v;
|
||||
if( ini_sget( ini, "options", "forceColors", "%d", &v ) ) data.forceColors = v;
|
||||
if( ini_sget( ini, "options", "ghostZones", "%d", &v ) ) data.ghostZones = v;
|
||||
if( ini_sget( ini, "options", "frameTarget", "%d", &v ) ) data.frameTarget = v;
|
||||
@ -194,6 +195,7 @@ void UserData::SaveState( const ViewData& data )
|
||||
fprintf( f, "drawCpuUsageGraph = %d\n", data.drawCpuUsageGraph );
|
||||
fprintf( f, "drawSamples = %d\n", data.drawSamples );
|
||||
fprintf( f, "dynamicColors = %d\n", data.dynamicColors );
|
||||
fprintf( f, "inheritParentColors = %d\n", data.inheritParentColors );
|
||||
fprintf( f, "forceColors = %d\n", data.forceColors );
|
||||
fprintf( f, "ghostZones = %d\n", data.ghostZones );
|
||||
fprintf( f, "frameTarget = %d\n", data.frameTarget );
|
||||
|
@ -56,6 +56,13 @@ View::View( void(*cbMainThread)(const std::function<void()>&, bool), const char*
|
||||
, m_cbMainThread( cbMainThread )
|
||||
, m_achievementsMgr( amgr )
|
||||
, m_achievements( config.achievements )
|
||||
, m_horizontalScrollMultiplier( config.horizontalScrollMultiplier )
|
||||
, m_verticalScrollMultiplier( config.verticalScrollMultiplier )
|
||||
#ifdef __EMSCRIPTEN__
|
||||
, m_td( 2, "ViewMt" )
|
||||
#else
|
||||
, m_td( std::thread::hardware_concurrency(), "ViewMt" )
|
||||
#endif
|
||||
{
|
||||
InitTextEditor();
|
||||
SetupConfig( config );
|
||||
@ -80,6 +87,13 @@ View::View( void(*cbMainThread)(const std::function<void()>&, bool), FileRead& f
|
||||
, m_cbMainThread( cbMainThread )
|
||||
, m_achievementsMgr( amgr )
|
||||
, m_achievements( config.achievements )
|
||||
, m_horizontalScrollMultiplier( config.horizontalScrollMultiplier )
|
||||
, m_verticalScrollMultiplier( config.verticalScrollMultiplier )
|
||||
#ifdef __EMSCRIPTEN__
|
||||
, m_td( 2, "ViewMt" )
|
||||
#else
|
||||
, m_td( std::thread::hardware_concurrency(), "ViewMt" )
|
||||
#endif
|
||||
{
|
||||
m_notificationTime = 4;
|
||||
m_notificationText = std::string( "Trace loaded in " ) + TimeToString( m_worker.GetLoadTime() );
|
||||
@ -555,6 +569,11 @@ bool View::Draw()
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
static FileCompression comp = FileCompression::Zstd;
|
||||
static int zlvl = 3;
|
||||
static bool buildDict = false;
|
||||
static int streams = 4;
|
||||
|
||||
bool saveFailed = false;
|
||||
if( !m_filenameStaging.empty() )
|
||||
{
|
||||
@ -569,46 +588,44 @@ bool View::Draw()
|
||||
ImGui::PopFont();
|
||||
ImGui::Separator();
|
||||
|
||||
static FileCompression comp = FileCompression::Zstd;
|
||||
static int zlvl = 3;
|
||||
ImGui::TextUnformatted( ICON_FA_FILE_ZIPPER " Trace compression" );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( "Can be changed later with the upgrade utility" );
|
||||
ImGui::Indent();
|
||||
int idx = 0;
|
||||
while( CompressionName[idx] )
|
||||
if( ImGui::TreeNode( ICON_FA_FILE_ZIPPER " Trace compression" ) )
|
||||
{
|
||||
if( ImGui::RadioButton( CompressionName[idx], (int)comp == idx ) ) comp = (FileCompression)idx;
|
||||
TextDisabledUnformatted( "Can be changed later with the upgrade utility" );
|
||||
ImGui::Indent();
|
||||
int idx = 0;
|
||||
while( CompressionName[idx] )
|
||||
{
|
||||
if( ImGui::RadioButton( CompressionName[idx], (int)comp == idx ) ) comp = (FileCompression)idx;
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( CompressionDesc[idx] );
|
||||
idx++;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
ImGui::TextUnformatted( "Zstd level" );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( CompressionDesc[idx] );
|
||||
idx++;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
ImGui::TextUnformatted( "Zstd level" );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( "Increasing level decreases file size, but increases save and load times" );
|
||||
ImGui::Indent();
|
||||
if( ImGui::SliderInt( "##zstd", &zlvl, 1, 22, "%d", ImGuiSliderFlags_AlwaysClamp ) )
|
||||
{
|
||||
comp = FileCompression::Zstd;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
TextDisabledUnformatted( "Increasing level decreases file size, but increases save and load times" );
|
||||
ImGui::Indent();
|
||||
if( ImGui::SliderInt( "##zstd", &zlvl, 1, 22, "%d", ImGuiSliderFlags_AlwaysClamp ) )
|
||||
{
|
||||
comp = FileCompression::Zstd;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
|
||||
static int streams = 4;
|
||||
ImGui::TextUnformatted( ICON_FA_SHUFFLE " Compression streams" );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( "Parallelize save and load at the cost of file size" );
|
||||
ImGui::Indent();
|
||||
ImGui::SliderInt( "##streams", &streams, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp );
|
||||
ImGui::Unindent();
|
||||
|
||||
static bool buildDict = false;
|
||||
if( m_worker.GetFrameImageCount() != 0 )
|
||||
{
|
||||
ImGui::Separator();
|
||||
ImGui::Checkbox( "Build frame images dictionary", &buildDict );
|
||||
ImGui::TextUnformatted( ICON_FA_SHUFFLE " Compression streams" );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( "Decreases run-time memory requirements" );
|
||||
TextDisabledUnformatted( "Parallelize save and load at the cost of file size" );
|
||||
ImGui::Indent();
|
||||
ImGui::SliderInt( "##streams", &streams, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp );
|
||||
ImGui::Unindent();
|
||||
|
||||
if( m_worker.GetFrameImageCount() != 0 )
|
||||
{
|
||||
ImGui::Separator();
|
||||
ImGui::Checkbox( "Build frame images dictionary", &buildDict );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( "Decreases run-time memory requirements" );
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
@ -712,10 +729,17 @@ bool View::DrawImpl()
|
||||
auto& threadHints = m_worker.GetPendingThreadHints();
|
||||
if( !threadHints.empty() )
|
||||
{
|
||||
m_threadReinsert.reserve( threadHints.size() );
|
||||
for( auto v : threadHints )
|
||||
{
|
||||
auto it = std::find_if( m_threadOrder.begin(), m_threadOrder.end(), [v]( const auto& t ) { return t->id == v; } );
|
||||
if( it != m_threadOrder.end() ) m_threadOrder.erase( it ); // Will be added in the correct place later, like any newly appearing thread
|
||||
if( it != m_threadOrder.end() )
|
||||
{
|
||||
// Will be reinserted in the correct place later.
|
||||
// A separate list is kept of threads that were already known to avoid having to figure out which one is missing in m_threadOrder.
|
||||
m_threadReinsert.push_back( *it );
|
||||
m_threadOrder.erase( it );
|
||||
}
|
||||
}
|
||||
m_worker.ClearPendingThreadHints();
|
||||
}
|
||||
@ -872,14 +896,16 @@ bool View::DrawImpl()
|
||||
ImGui::PopStyleColor( 3 );
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ToggleButton( ICON_FA_GEAR " Options", m_showOptions );
|
||||
ToggleButton( ICON_FA_GEAR, m_showOptions );
|
||||
ImGui::SameLine();
|
||||
ToggleButton( ICON_FA_TAGS " Messages", m_showMessages );
|
||||
ImGui::SameLine();
|
||||
ToggleButton( ICON_FA_MAGNIFYING_GLASS " Find zone", m_findZone.show );
|
||||
ToggleButton( ICON_FA_MAGNIFYING_GLASS " Find", m_findZone.show );
|
||||
ImGui::SameLine();
|
||||
ToggleButton( ICON_FA_ARROW_UP_WIDE_SHORT " Statistics", m_showStatistics );
|
||||
ImGui::SameLine();
|
||||
ToggleButton( ICON_FA_FIRE_FLAME_CURVED " Flame", m_showFlameGraph );
|
||||
ImGui::SameLine();
|
||||
ToggleButton( ICON_FA_MEMORY " Memory", m_memInfo.show );
|
||||
ImGui::SameLine();
|
||||
ToggleButton( ICON_FA_SCALE_BALANCED " Compare", m_compare.show );
|
||||
@ -1072,7 +1098,7 @@ bool View::DrawImpl()
|
||||
DrawFrames();
|
||||
|
||||
const auto dockspaceId = ImGui::GetID( "tracyDockspace" );
|
||||
ImGui::DockSpace( dockspaceId, ImVec2( 0, 0 ), ImGuiDockNodeFlags_NoDockingInCentralNode );
|
||||
ImGui::DockSpace( dockspaceId, ImVec2( 0, 0 ), ImGuiDockNodeFlags_NoDockingOverCentralNode );
|
||||
if( ImGuiDockNode* node = ImGui::DockBuilderGetCentralNode( dockspaceId ) )
|
||||
{
|
||||
node->LocalFlags |= ImGuiDockNodeFlags_NoTabBar;
|
||||
@ -1106,6 +1132,7 @@ bool View::DrawImpl()
|
||||
|
||||
if( m_showOptions ) DrawOptions();
|
||||
if( m_showMessages ) DrawMessages();
|
||||
if( m_showFlameGraph ) DrawFlameGraph();
|
||||
if( m_findZone.show ) DrawFindZone();
|
||||
if( m_showStatistics ) DrawStatistics();
|
||||
if( m_memInfo.show ) DrawMemory();
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@ -22,6 +23,7 @@
|
||||
#include "TracyUtility.hpp"
|
||||
#include "TracyViewData.hpp"
|
||||
#include "../server/TracyFileWrite.hpp"
|
||||
#include "../server/TracyTaskDispatch.hpp"
|
||||
#include "../server/TracyShortPtr.hpp"
|
||||
#include "../server/TracyWorker.hpp"
|
||||
#include "../server/tracy_robin_hood.h"
|
||||
@ -36,7 +38,9 @@ constexpr const char* GpuContextNames[] = {
|
||||
"Vulkan",
|
||||
"OpenCL",
|
||||
"Direct3D 12",
|
||||
"Direct3D 11"
|
||||
"Direct3D 11",
|
||||
"Metal",
|
||||
"Custom"
|
||||
};
|
||||
|
||||
struct MemoryPage;
|
||||
@ -51,6 +55,7 @@ struct CpuUsageDraw;
|
||||
struct CpuCtxDraw;
|
||||
struct LockDraw;
|
||||
struct PlotDraw;
|
||||
struct FlameGraphContext;
|
||||
|
||||
|
||||
class View
|
||||
@ -147,7 +152,7 @@ public:
|
||||
|
||||
void HighlightThread( uint64_t thread );
|
||||
void ZoomToRange( int64_t start, int64_t end, bool pause = true );
|
||||
bool DrawPlot( const TimelineContext& ctx, PlotData& plot, const std::vector<uint32_t>& plotDraw, int& offset );
|
||||
bool DrawPlot( const TimelineContext& ctx, PlotData& plot, const std::vector<uint32_t>& plotDraw, int& offset, bool rightEnd );
|
||||
void DrawThread( const TimelineContext& ctx, const ThreadData& thread, const std::vector<TimelineDraw>& draw, const std::vector<ContextSwitchDraw>& ctxDraw, const std::vector<SamplesDraw>& samplesDraw, const std::vector<std::unique_ptr<LockDraw>>& lockDraw, int& offset, int depth, bool hasCtxSwitches, bool hasSamples );
|
||||
void DrawThreadMessagesList( const TimelineContext& ctx, const std::vector<MessagesDraw>& drawList, int offset, uint64_t tid );
|
||||
void DrawThreadOverlays( const ThreadData& thread, const ImVec2& ul, const ImVec2& dr );
|
||||
@ -271,6 +276,13 @@ private:
|
||||
void DrawRangeEntry( Range& range, const char* label, uint32_t color, const char* popupLabel, int id );
|
||||
void DrawSourceTooltip( const char* filename, uint32_t line, int before = 3, int after = 3, bool separateTooltip = true );
|
||||
void DrawWaitStacks();
|
||||
void DrawFlameGraph();
|
||||
void DrawFlameGraphHeader( uint64_t timespan );
|
||||
void DrawFlameGraphLevel( const std::vector<FlameGraphItem>& data, FlameGraphContext& ctx, int depth, bool samples );
|
||||
void DrawFlameGraphItem( const FlameGraphItem& item, FlameGraphContext& ctx, int depth, bool samples );
|
||||
void BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& data, const Vector<short_ptr<ZoneEvent>>& zones );
|
||||
void BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& data, const Vector<short_ptr<ZoneEvent>>& zones, const ContextSwitch* ctx );
|
||||
void BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& data, const Vector<SampleData>& samples );
|
||||
|
||||
void ListMemData( std::vector<const MemEvent*>& vec, const std::function<void(const MemEvent*)>& DrawAddress, int64_t startTime = -1, uint64_t pool = 0 );
|
||||
|
||||
@ -303,12 +315,13 @@ private:
|
||||
|
||||
void AddAnnotation( int64_t start, int64_t end );
|
||||
|
||||
bool IsFrameExternal( const char* filename, const char* image );
|
||||
uint32_t GetThreadColor( uint64_t thread, int depth );
|
||||
uint32_t GetSrcLocColor( const SourceLocation& srcloc, int depth );
|
||||
uint32_t GetRawSrcLocColor( const SourceLocation& srcloc, int depth );
|
||||
uint32_t GetZoneColor( const ZoneEvent& ev, uint64_t thread, int depth );
|
||||
uint32_t GetZoneColor( const GpuEvent& ev );
|
||||
ZoneColorData GetZoneColorData( const ZoneEvent& ev, uint64_t thread, int depth );
|
||||
ZoneColorData GetZoneColorData( const ZoneEvent& ev, uint64_t thread, int depth, uint32_t inheritedColor );
|
||||
ZoneColorData GetZoneColorData( const GpuEvent& ev );
|
||||
|
||||
void ZoomToZone( const ZoneEvent& ev );
|
||||
@ -377,9 +390,11 @@ private:
|
||||
|
||||
unordered_flat_map<uint64_t, bool> m_visibleMsgThread;
|
||||
unordered_flat_map<uint64_t, bool> m_waitStackThread;
|
||||
unordered_flat_map<uint64_t, bool> m_flameGraphThread;
|
||||
unordered_flat_map<const void*, int> m_gpuDrift;
|
||||
unordered_flat_map<const PlotData*, PlotView> m_plotView;
|
||||
Vector<const ThreadData*> m_threadOrder;
|
||||
Vector<const ThreadData*> m_threadReinsert;
|
||||
Vector<float> m_threadDnd;
|
||||
|
||||
tracy_force_inline bool& VisibleMsgThread( uint64_t thread )
|
||||
@ -402,6 +417,16 @@ private:
|
||||
return it->second;
|
||||
}
|
||||
|
||||
tracy_force_inline bool& FlameGraphThread( uint64_t thread )
|
||||
{
|
||||
auto it = m_flameGraphThread.find( thread );
|
||||
if( it == m_flameGraphThread.end() )
|
||||
{
|
||||
it = m_flameGraphThread.emplace( thread, true ).first;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
tracy_force_inline int& GpuDrift( const void* ptr )
|
||||
{
|
||||
auto it = m_gpuDrift.find( ptr );
|
||||
@ -488,10 +513,17 @@ private:
|
||||
bool m_showCpuDataWindow = false;
|
||||
bool m_showAnnotationList = false;
|
||||
bool m_showWaitStacks = false;
|
||||
bool m_showFlameGraph = false;
|
||||
|
||||
AccumulationMode m_statAccumulationMode = AccumulationMode::SelfOnly;
|
||||
bool m_statSampleTime = true;
|
||||
int m_statMode = 0;
|
||||
bool m_shortImageNames = false;
|
||||
int m_flameMode = 0;
|
||||
bool m_flameSort = false;
|
||||
bool m_flameRunningTime = false;
|
||||
bool m_flameExternal = true;
|
||||
bool m_flameExternalTail = true;
|
||||
int m_statSampleLocation = 2;
|
||||
bool m_statHideUnknown = true;
|
||||
bool m_showAllSymbols = false;
|
||||
@ -501,6 +533,7 @@ private:
|
||||
bool m_statSeparateInlines = false;
|
||||
bool m_mergeInlines = false;
|
||||
bool m_relativeInlines = false;
|
||||
bool m_topInline = false;
|
||||
bool m_statShowAddress = false;
|
||||
bool m_statShowKernel = true;
|
||||
bool m_groupChildrenLocations = false;
|
||||
@ -570,10 +603,10 @@ private:
|
||||
std::atomic<size_t> m_srcFileBytes { 0 };
|
||||
std::atomic<size_t> m_dstFileBytes { 0 };
|
||||
|
||||
void* m_frameTexture = nullptr;
|
||||
ImTextureID m_frameTexture = 0;
|
||||
const void* m_frameTexturePtr = nullptr;
|
||||
|
||||
void* m_frameTextureConn = nullptr;
|
||||
ImTextureID m_frameTextureConn = 0;
|
||||
const void* m_frameTextureConnPtr = nullptr;
|
||||
|
||||
std::vector<std::unique_ptr<Annotation>> m_annotations;
|
||||
@ -614,6 +647,7 @@ private:
|
||||
int64_t time = 0;
|
||||
};
|
||||
|
||||
bool hasResults = false;
|
||||
bool show = false;
|
||||
bool ignoreCase = false;
|
||||
std::vector<int16_t> match;
|
||||
@ -638,6 +672,7 @@ private:
|
||||
size_t sortedNum = 0, selSortNum, selSortActive;
|
||||
float average, selAverage;
|
||||
float median, selMedian;
|
||||
float p75, p90;
|
||||
int64_t total, selTotal;
|
||||
int64_t selTime;
|
||||
bool drawAvgMed = true;
|
||||
@ -671,6 +706,7 @@ private:
|
||||
selGroup = Unselected;
|
||||
highlight.active = false;
|
||||
samples.counts.clear();
|
||||
hasResults = false;
|
||||
}
|
||||
|
||||
void ResetMatch()
|
||||
@ -680,6 +716,8 @@ private:
|
||||
sortedNum = 0;
|
||||
average = 0;
|
||||
median = 0;
|
||||
p75 = 0;
|
||||
p90 = 0;
|
||||
total = 0;
|
||||
tmin = std::numeric_limits<int64_t>::max();
|
||||
tmax = std::numeric_limits<int64_t>::min();
|
||||
@ -830,7 +868,7 @@ private:
|
||||
} m_cache;
|
||||
|
||||
struct {
|
||||
void* texture = nullptr;
|
||||
ImTextureID texture = 0;
|
||||
float timeLeft = 0;
|
||||
float speed = 1;
|
||||
uint32_t frame = 0;
|
||||
@ -873,6 +911,23 @@ private:
|
||||
|
||||
AchievementsMgr* m_achievementsMgr;
|
||||
bool m_achievements = false;
|
||||
|
||||
double m_horizontalScrollMultiplier = 1.0;
|
||||
double m_verticalScrollMultiplier = 1.0;
|
||||
|
||||
TaskDispatch m_td;
|
||||
std::vector<FlameGraphItem> m_flameGraphData;
|
||||
struct
|
||||
{
|
||||
uint64_t count = 0;
|
||||
uint64_t lastTime = 0;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
count = 0;
|
||||
lastTime = 0;
|
||||
}
|
||||
} m_flameGraphInvariant;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ struct ViewData
|
||||
uint8_t drawCpuUsageGraph = true;
|
||||
uint8_t drawSamples = true;
|
||||
uint8_t dynamicColors = 1;
|
||||
uint8_t inheritParentColors = true;
|
||||
uint8_t forceColors = false;
|
||||
uint8_t ghostZones = true;
|
||||
ShortenName shortenName = ShortenName::NoSpaceAndNormalize;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "TracyImGui.hpp"
|
||||
#include "TracyPrint.hpp"
|
||||
#include "TracyView.hpp"
|
||||
#include "tracy_pdqsort.h"
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
@ -79,17 +80,23 @@ void View::DrawAnnotationList()
|
||||
AddAnnotation( m_vd.zvStart, m_vd.zvEnd );
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx( ImGuiSeparatorFlags_Vertical );
|
||||
ImGui::SameLine();
|
||||
|
||||
if( m_annotations.empty() )
|
||||
{
|
||||
ImGui::TextWrapped( "No annotations." );
|
||||
ImGui::Separator();
|
||||
ImGui::PushFont( m_bigFont );
|
||||
ImGui::Dummy( ImVec2( 0, ( ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeight() * 2 ) * 0.5f ) );
|
||||
TextCentered( ICON_FA_HORSE );
|
||||
TextCentered( "No annotations" );
|
||||
ImGui::PopFont();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx( ImGuiSeparatorFlags_Vertical );
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
TextFocused( "Annotations:", RealToString( m_annotations.size() ) );
|
||||
ImGui::Separator();
|
||||
|
@ -10,14 +10,6 @@
|
||||
namespace tracy
|
||||
{
|
||||
|
||||
static bool IsFrameExternal( const char* filename, const char* image )
|
||||
{
|
||||
if( strncmp( filename, "/usr/", 5 ) == 0 || strncmp( filename, "/lib/", 5 ) == 0 || strcmp( filename, "[unknown]" ) == 0 ) return true;
|
||||
if( strncmp( filename, "C:\\Program Files\\", 17 ) == 0 || strncmp( filename, "d:\\a01\\_work\\", 13 ) == 0 ) return true;
|
||||
if( !image ) return false;
|
||||
return strncmp( image, "/usr/", 5 ) == 0 || strncmp( image, "/lib/", 5 ) == 0 || strncmp( image, "/lib64/", 7 ) == 0 || strcmp( image, "<kernel>" ) == 0;
|
||||
}
|
||||
|
||||
void View::DrawCallstackWindow()
|
||||
{
|
||||
bool show = true;
|
||||
@ -107,7 +99,11 @@ void View::DrawCallstackTable( uint32_t callstack, bool globalEntriesButton )
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
SmallCheckbox( "External frames", &m_showExternalFrames );
|
||||
SmallCheckbox( ICON_FA_SHIELD_HALVED " External frames", &m_showExternalFrames );
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
SmallCheckbox( ICON_FA_SCISSORS " Short images", &m_shortImageNames );
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
@ -152,7 +148,7 @@ void View::DrawCallstackTable( uint32_t callstack, bool globalEntriesButton )
|
||||
ImGui::TableSetupColumn( "Image" );
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
bool external = false;
|
||||
int external = 0;
|
||||
int fidx = 0;
|
||||
int bidx = 0;
|
||||
for( auto& entry : cs )
|
||||
@ -162,7 +158,7 @@ void View::DrawCallstackTable( uint32_t callstack, bool globalEntriesButton )
|
||||
{
|
||||
if( !m_showExternalFrames )
|
||||
{
|
||||
external = true;
|
||||
external++;
|
||||
continue;
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
@ -209,23 +205,27 @@ void View::DrawCallstackTable( uint32_t callstack, bool globalEntriesButton )
|
||||
if( !m_showExternalFrames )
|
||||
{
|
||||
if( f == fsz-1 ) fidx++;
|
||||
external = true;
|
||||
external++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if( external != 0 )
|
||||
{
|
||||
if( external )
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushFont( m_smallFont );
|
||||
TextDisabledUnformatted( "external" );
|
||||
ImGui::TableNextColumn();
|
||||
if( external == 1 )
|
||||
{
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushFont( m_smallFont );
|
||||
TextDisabledUnformatted( "external" );
|
||||
ImGui::PopFont();
|
||||
ImGui::TableNextColumn();
|
||||
TextDisabledUnformatted( "\xe2\x80\xa6" );
|
||||
external = false;
|
||||
TextDisabledUnformatted( "1 frame" );
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextDisabled( "%i frames", external );
|
||||
}
|
||||
ImGui::PopFont();
|
||||
external = 0;
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
@ -389,19 +389,47 @@ void View::DrawCallstackTable( uint32_t callstack, bool globalEntriesButton )
|
||||
}
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::TableNextColumn();
|
||||
if( image ) TextDisabledUnformatted( image );
|
||||
if( image )
|
||||
{
|
||||
const char* end = image + strlen( image );
|
||||
|
||||
if( m_shortImageNames )
|
||||
{
|
||||
const char* ptr = end - 1;
|
||||
while( ptr > image && *ptr != '/' && *ptr != '\\' ) ptr--;
|
||||
if( *ptr == '/' || *ptr == '\\' ) ptr++;
|
||||
const auto cw = ImGui::GetContentRegionAvail().x;
|
||||
const auto tw = ImGui::CalcTextSize( image, end ).x;
|
||||
TextDisabledUnformatted( ptr );
|
||||
if( ptr != image || tw > cw ) TooltipIfHovered( image );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto cw = ImGui::GetContentRegionAvail().x;
|
||||
const auto tw = ImGui::CalcTextSize( image, end ).x;
|
||||
TextDisabledUnformatted( image );
|
||||
if( tw > cw ) TooltipIfHovered( image );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( external )
|
||||
if( external != 0 )
|
||||
{
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushFont( m_smallFont );
|
||||
TextDisabledUnformatted( "external" );
|
||||
ImGui::PopFont();
|
||||
ImGui::TableNextColumn();
|
||||
TextDisabledUnformatted( "\xe2\x80\xa6" );
|
||||
if( external == 1 )
|
||||
{
|
||||
TextDisabledUnformatted( "1 frame" );
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextDisabled( "%i frames", external );
|
||||
}
|
||||
ImGui::PopFont();
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "TracyFileselector.hpp"
|
||||
#include "TracyPrint.hpp"
|
||||
#include "TracyView.hpp"
|
||||
#include "tracy_pdqsort.h"
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
@ -236,8 +237,14 @@ void View::DrawCompare()
|
||||
#else
|
||||
if( !m_compare.second )
|
||||
{
|
||||
ImGui::TextWrapped( "Please load a second trace to compare results." );
|
||||
if( ImGui::Button( ICON_FA_FOLDER_OPEN " Open second trace" ) && !m_compare.loadThread.joinable() )
|
||||
const auto ty = ImGui::GetTextLineHeight();
|
||||
ImGui::PushFont( m_bigFont );
|
||||
ImGui::Dummy( ImVec2( 0, ( ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeight() * 5 ) * 0.5f ) );
|
||||
TextCentered( ICON_FA_SCALE_BALANCED );
|
||||
TextCentered( "Please load a second trace to compare results" );
|
||||
ImGui::PopFont();
|
||||
ImGui::TextUnformatted( "" );
|
||||
if( ButtonCentered( ICON_FA_FOLDER_OPEN " Open second trace" ) && !m_compare.loadThread.joinable() )
|
||||
{
|
||||
Fileselector::OpenFile( "tracy", "Tracy Profiler trace file", [this]( const char* fn ) {
|
||||
try
|
||||
@ -279,7 +286,12 @@ void View::DrawCompare()
|
||||
|
||||
if( !m_worker.AreSourceLocationZonesReady() || !m_compare.second->AreSourceLocationZonesReady() )
|
||||
{
|
||||
ImGui::TextWrapped( "Please wait, computing data..." );
|
||||
const auto ty = ImGui::GetTextLineHeight();
|
||||
ImGui::PushFont( m_bigFont );
|
||||
ImGui::Dummy( ImVec2( 0, ( ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeight() * 2 - ty ) * 0.5f ) );
|
||||
TextCentered( ICON_FA_FROG );
|
||||
TextCentered( "Please wait, computing data..." );
|
||||
ImGui::PopFont();
|
||||
DrawWaitingDots( s_time );
|
||||
ImGui::End();
|
||||
return;
|
||||
@ -400,9 +412,9 @@ void View::DrawCompare()
|
||||
}
|
||||
}
|
||||
|
||||
std::sort( m_compare.thisUnique.begin(), m_compare.thisUnique.end(), []( const auto& lhs, const auto& rhs ) { return strcmp( lhs, rhs ) < 0; } );
|
||||
std::sort( m_compare.secondUnique.begin(), m_compare.secondUnique.end(), []( const auto& lhs, const auto& rhs ) { return strcmp( lhs, rhs ) < 0; } );
|
||||
std::sort( m_compare.diffs.begin(), m_compare.diffs.end(), []( const auto& lhs, const auto& rhs ) { return strcmp( lhs.first, rhs.first ) < 0; } );
|
||||
pdqsort_branchless( m_compare.thisUnique.begin(), m_compare.thisUnique.end(), []( const auto& lhs, const auto& rhs ) { return strcmp( lhs, rhs ) < 0; } );
|
||||
pdqsort_branchless( m_compare.secondUnique.begin(), m_compare.secondUnique.end(), []( const auto& lhs, const auto& rhs ) { return strcmp( lhs, rhs ) < 0; } );
|
||||
pdqsort_branchless( m_compare.diffs.begin(), m_compare.diffs.end(), []( const auto& lhs, const auto& rhs ) { return strcmp( lhs.first, rhs.first ) < 0; } );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "TracyTimelineContext.hpp"
|
||||
#include "TracyTimelineDraw.hpp"
|
||||
#include "TracyView.hpp"
|
||||
#include "tracy_pdqsort.h"
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
@ -440,7 +441,16 @@ void View::DrawWaitStacks()
|
||||
bool threadsChanged = false;
|
||||
auto expand = ImGui::TreeNode( ICON_FA_SHUFFLE " Visible threads:" );
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "(%zu)", m_threadOrder.size() );
|
||||
size_t visibleThreads = 0;
|
||||
for( const auto& t : m_threadOrder ) if( WaitStackThread( t->id ) ) visibleThreads++;
|
||||
if( visibleThreads == m_threadOrder.size() )
|
||||
{
|
||||
ImGui::TextDisabled( "(%zu)", m_threadOrder.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextDisabled( "(%zi/%zu)", visibleThreads, m_threadOrder.size() );
|
||||
}
|
||||
if( expand )
|
||||
{
|
||||
auto& crash = m_worker.GetCrashEvent();
|
||||
@ -498,7 +508,11 @@ void View::DrawWaitStacks()
|
||||
ImGui::BeginChild( "##waitstacks" );
|
||||
if( stacks.empty() )
|
||||
{
|
||||
ImGui::TextUnformatted( "No wait stacks to display." );
|
||||
ImGui::PushFont( m_bigFont );
|
||||
ImGui::Dummy( ImVec2( 0, ( ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeight() * 2 ) * 0.5f ) );
|
||||
TextCentered( ICON_FA_KIWI_BIRD );
|
||||
TextCentered( "No wait stacks to display" );
|
||||
ImGui::PopFont();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "TracyTimelineItem.hpp"
|
||||
#include "TracyTimelineContext.hpp"
|
||||
#include "TracyView.hpp"
|
||||
#include "tracy_pdqsort.h"
|
||||
|
||||
constexpr float MinVisSize = 3;
|
||||
|
||||
@ -80,6 +81,7 @@ bool View::DrawCpuData( const TimelineContext& ctx, const std::vector<CpuUsageDr
|
||||
TextFocused( "Number of cores:", RealToString( cpuCnt ) );
|
||||
if( usage.own + usage.other != 0 )
|
||||
{
|
||||
auto& topo = m_worker.GetCpuTopology();
|
||||
const auto mt = m_vd.zvStart + ( ImGui::GetIO().MousePos.x - wpos.x ) * nspx;
|
||||
ImGui::Separator();
|
||||
for( int i=0; i<cpuCnt; i++ )
|
||||
@ -93,7 +95,14 @@ bool View::DrawCpuData( const TimelineContext& ctx, const std::vector<CpuUsageDr
|
||||
auto tt = m_worker.GetThreadTopology( i );
|
||||
if( tt )
|
||||
{
|
||||
ImGui::TextDisabled( "[%i:%i] CPU %i:", tt->package, tt->core, i );
|
||||
if( topo.size() > 1 )
|
||||
{
|
||||
ImGui::TextDisabled( "[%i:%i:%i] CPU %i:", tt->package, tt->die, tt->core, i );
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextDisabled( "[%i:%i] CPU %i:", tt->die, tt->core, i );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -175,6 +184,8 @@ bool View::DrawCpuData( const TimelineContext& ctx, const std::vector<CpuUsageDr
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Package:", RealToString( tt->package ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Die:", RealToString( tt->die ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Core:", RealToString( tt->core ) );
|
||||
}
|
||||
TextFocused( "Context switch regions:", RealToString( v.num ) );
|
||||
@ -264,6 +275,8 @@ bool View::DrawCpuData( const TimelineContext& ctx, const std::vector<CpuUsageDr
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Package:", RealToString( tt->package ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Die:", RealToString( tt->die ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Core:", RealToString( tt->core ) );
|
||||
}
|
||||
if( local )
|
||||
@ -327,7 +340,15 @@ bool View::DrawCpuData( const TimelineContext& ctx, const std::vector<CpuUsageDr
|
||||
char buf[64];
|
||||
if( tt )
|
||||
{
|
||||
sprintf( buf, "[%i:%i] CPU %i", tt->package, tt->core, i );
|
||||
auto& topo = m_worker.GetCpuTopology();
|
||||
if( topo.size() > 1 )
|
||||
{
|
||||
sprintf( buf, "[%i:%i:%i] CPU %i", tt->package, tt->die, tt->core, i );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( buf, "[%i:%i] CPU %i", tt->die, tt->core, i );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -347,6 +368,8 @@ bool View::DrawCpuData( const TimelineContext& ctx, const std::vector<CpuUsageDr
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Package:", RealToString( tt->package ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Die:", RealToString( tt->die ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Core:", RealToString( tt->core ) );
|
||||
}
|
||||
TextFocused( "Context switch regions:", RealToString( cpuData[i].cs.size() ) );
|
||||
|
@ -7,7 +7,9 @@
|
||||
#include "TracyImGui.hpp"
|
||||
#include "TracyMouse.hpp"
|
||||
#include "TracyPrint.hpp"
|
||||
#include "TracySort.hpp"
|
||||
#include "TracyView.hpp"
|
||||
#include "tracy_pdqsort.h"
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
@ -17,6 +19,7 @@ extern double s_time;
|
||||
#ifndef TRACY_NO_STATISTICS
|
||||
void View::FindZones()
|
||||
{
|
||||
m_findZone.hasResults = true;
|
||||
m_findZone.match = m_worker.GetMatchingSourceLocation( m_findZone.pattern, m_findZone.ignoreCase );
|
||||
if( m_findZone.match.empty() ) return;
|
||||
|
||||
@ -263,11 +266,26 @@ void View::DrawFindZone()
|
||||
#else
|
||||
if( !m_worker.AreSourceLocationZonesReady() )
|
||||
{
|
||||
ImGui::TextWrapped( "Please wait, computing data..." );
|
||||
const auto ty = ImGui::GetTextLineHeight();
|
||||
ImGui::PushFont( m_bigFont );
|
||||
ImGui::Dummy( ImVec2( 0, ( ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeight() * 2 - ty ) * 0.5f ) );
|
||||
TextCentered( ICON_FA_CROW );
|
||||
TextCentered( "Please wait, computing data..." );
|
||||
ImGui::PopFont();
|
||||
DrawWaitingDots( s_time );
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
if( m_worker.GetZoneCount() == 0 )
|
||||
{
|
||||
ImGui::PushFont( m_bigFont );
|
||||
ImGui::Dummy( ImVec2( 0, ( ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeight() * 2 ) * 0.5f ) );
|
||||
TextCentered( ICON_FA_CROW );
|
||||
TextCentered( "No zones were collected" );
|
||||
ImGui::PopFont();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
bool findClicked = false;
|
||||
|
||||
@ -324,15 +342,31 @@ void View::DrawFindZone()
|
||||
FindZones();
|
||||
}
|
||||
|
||||
if( !m_findZone.match.empty() )
|
||||
ImGui::Separator();
|
||||
ImGui::BeginChild( "##findzone" );
|
||||
|
||||
if( m_findZone.match.empty() )
|
||||
{
|
||||
ImGui::PushFont( m_bigFont );
|
||||
ImGui::Dummy( ImVec2( 0, ( ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeight() * 2 ) * 0.5f ) );
|
||||
TextCentered( ICON_FA_CROW );
|
||||
if( m_findZone.hasResults )
|
||||
{
|
||||
TextCentered( "No matching zones found" );
|
||||
}
|
||||
else
|
||||
{
|
||||
TextCentered( "Please enter search pattern" );
|
||||
}
|
||||
ImGui::PopFont();
|
||||
}
|
||||
else
|
||||
{
|
||||
Achieve( "findZone" );
|
||||
|
||||
const auto rangeMin = m_findZone.range.min;
|
||||
const auto rangeMax = m_findZone.range.max;
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::BeginChild( "##findzone" );
|
||||
bool expand = ImGui::TreeNodeEx( "Matched source locations", ImGuiTreeNodeFlags_DefaultOpen );
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "(%zu)", m_findZone.match.size() );
|
||||
@ -507,10 +541,10 @@ void View::DrawFindZone()
|
||||
}
|
||||
}
|
||||
auto mid = vec.begin() + vszorig;
|
||||
#ifdef NO_PARALLEL_SORT
|
||||
#ifdef __EMSCRIPTEN__
|
||||
pdqsort_branchless( mid, vec.end() );
|
||||
#else
|
||||
std::sort( std::execution::par_unseq, mid, vec.end() );
|
||||
ppqsort::sort( ppqsort::execution::par, mid, vec.end() );
|
||||
#endif
|
||||
std::inplace_merge( vec.begin(), mid, vec.end() );
|
||||
|
||||
@ -519,6 +553,8 @@ void View::DrawFindZone()
|
||||
{
|
||||
m_findZone.average = float( total ) / vsz;
|
||||
m_findZone.median = vec[vsz/2];
|
||||
m_findZone.p75 = vec[3 * (vsz / 4)];
|
||||
m_findZone.p90 = vec[vsz / 10 * 9];
|
||||
m_findZone.total = total;
|
||||
m_findZone.sortedNum = i;
|
||||
m_findZone.tmin = tmin;
|
||||
@ -939,6 +975,14 @@ void View::DrawFindZone()
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
TextFocused( "P75:", TimeToString( m_findZone.p75 ) );
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
TextFocused( "P90:", TimeToString( m_findZone.p90 ) );
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
{
|
||||
int64_t t0, t1;
|
||||
if( m_findZone.logTime )
|
||||
@ -1976,14 +2020,13 @@ void View::DrawFindZone()
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
if( changeZone != 0 )
|
||||
{
|
||||
auto& srcloc = m_worker.GetSourceLocation( changeZone );
|
||||
m_findZone.ShowZone( changeZone, m_worker.GetString( srcloc.name.active ? srcloc.name : srcloc.function ) );
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
#endif
|
||||
|
||||
ImGui::End();
|
||||
|
901
profiler/src/profiler/TracyView_FlameGraph.cpp
Normal file
901
profiler/src/profiler/TracyView_FlameGraph.cpp
Normal file
@ -0,0 +1,901 @@
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "TracyColor.hpp"
|
||||
#include "TracyEvent.hpp"
|
||||
#include "TracyImGui.hpp"
|
||||
#include "TracyMouse.hpp"
|
||||
#include "TracyPrint.hpp"
|
||||
#include "TracyVector.hpp"
|
||||
#include "TracyView.hpp"
|
||||
#include "tracy_pdqsort.h"
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
|
||||
constexpr float MinVisSize = 3;
|
||||
|
||||
void View::BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& data, const Vector<short_ptr<ZoneEvent>>& zones )
|
||||
{
|
||||
FlameGraphItem* cache;
|
||||
int16_t last = 0;
|
||||
|
||||
if( zones.is_magic() )
|
||||
{
|
||||
auto& vec = *(Vector<ZoneEvent>*)&zones;
|
||||
for( auto& v : vec )
|
||||
{
|
||||
if( !v.IsEndValid() ) break;
|
||||
const auto srcloc = v.SrcLoc();
|
||||
const auto duration = v.End() - v.Start();
|
||||
if( srcloc == last )
|
||||
{
|
||||
cache->time += duration;
|
||||
if( v.HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v.Child() );
|
||||
BuildFlameGraph( worker, cache->children, children );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = std::find_if( data.begin(), data.end(), [srcloc]( const auto& v ) { return v.srcloc == srcloc; } );
|
||||
if( it == data.end() )
|
||||
{
|
||||
data.emplace_back( FlameGraphItem { srcloc, duration } );
|
||||
if( v.HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v.Child() );
|
||||
BuildFlameGraph( worker, data.back().children, children );
|
||||
}
|
||||
cache = &data.back();
|
||||
}
|
||||
else
|
||||
{
|
||||
it->time += duration;
|
||||
if( v.HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v.Child() );
|
||||
BuildFlameGraph( worker, it->children, children );
|
||||
}
|
||||
cache = &*it;
|
||||
}
|
||||
last = srcloc;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( auto& v : zones )
|
||||
{
|
||||
if( !v->IsEndValid() ) break;
|
||||
const auto srcloc = v->SrcLoc();
|
||||
const auto duration = v->End() - v->Start();
|
||||
if( srcloc == last )
|
||||
{
|
||||
cache->time += duration;
|
||||
if( v->HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v->Child() );
|
||||
BuildFlameGraph( worker, cache->children, children );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = std::find_if( data.begin(), data.end(), [srcloc]( const auto& v ) { return v.srcloc == srcloc; } );
|
||||
if( it == data.end() )
|
||||
{
|
||||
data.emplace_back( FlameGraphItem { srcloc, duration } );
|
||||
if( v->HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v->Child() );
|
||||
BuildFlameGraph( worker, data.back().children, children );
|
||||
}
|
||||
cache = &data.back();
|
||||
}
|
||||
else
|
||||
{
|
||||
it->time += duration;
|
||||
if( v->HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v->Child() );
|
||||
BuildFlameGraph( worker, it->children, children );
|
||||
}
|
||||
cache = &*it;
|
||||
}
|
||||
last = srcloc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void View::BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& data, const Vector<short_ptr<ZoneEvent>>& zones, const ContextSwitch* ctx )
|
||||
{
|
||||
assert( ctx );
|
||||
FlameGraphItem* cache;
|
||||
int16_t last = 0;
|
||||
|
||||
if( zones.is_magic() )
|
||||
{
|
||||
auto& vec = *(Vector<ZoneEvent>*)&zones;
|
||||
for( auto& v : vec )
|
||||
{
|
||||
if( !v.IsEndValid() ) break;
|
||||
const auto srcloc = v.SrcLoc();
|
||||
int64_t duration;
|
||||
uint64_t cnt;
|
||||
if( !GetZoneRunningTime( ctx, v, duration, cnt ) ) break;
|
||||
if( srcloc == last )
|
||||
{
|
||||
cache->time += duration;
|
||||
if( v.HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v.Child() );
|
||||
BuildFlameGraph( worker, cache->children, children, ctx );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = std::find_if( data.begin(), data.end(), [srcloc]( const auto& v ) { return v.srcloc == srcloc; } );
|
||||
if( it == data.end() )
|
||||
{
|
||||
data.emplace_back( FlameGraphItem { srcloc, duration } );
|
||||
if( v.HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v.Child() );
|
||||
BuildFlameGraph( worker, data.back().children, children, ctx );
|
||||
}
|
||||
cache = &data.back();
|
||||
}
|
||||
else
|
||||
{
|
||||
it->time += duration;
|
||||
if( v.HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v.Child() );
|
||||
BuildFlameGraph( worker, it->children, children, ctx );
|
||||
}
|
||||
cache = &*it;
|
||||
}
|
||||
last = srcloc;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( auto& v : zones )
|
||||
{
|
||||
if( !v->IsEndValid() ) break;
|
||||
const auto srcloc = v->SrcLoc();
|
||||
int64_t duration;
|
||||
uint64_t cnt;
|
||||
if( !GetZoneRunningTime( ctx, *v, duration, cnt ) ) break;
|
||||
if( srcloc == last )
|
||||
{
|
||||
cache->time += duration;
|
||||
if( v->HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v->Child() );
|
||||
BuildFlameGraph( worker, cache->children, children, ctx );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = std::find_if( data.begin(), data.end(), [srcloc]( const auto& v ) { return v.srcloc == srcloc; } );
|
||||
if( it == data.end() )
|
||||
{
|
||||
data.emplace_back( FlameGraphItem { srcloc, duration } );
|
||||
if( v->HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v->Child() );
|
||||
BuildFlameGraph( worker, data.back().children, children, ctx );
|
||||
}
|
||||
cache = &data.back();
|
||||
}
|
||||
else
|
||||
{
|
||||
it->time += duration;
|
||||
if( v->HasChildren() )
|
||||
{
|
||||
auto& children = worker.GetZoneChildren( v->Child() );
|
||||
BuildFlameGraph( worker, it->children, children, ctx );
|
||||
}
|
||||
cache = &*it;
|
||||
}
|
||||
last = srcloc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void View::BuildFlameGraph( const Worker& worker, std::vector<FlameGraphItem>& data, const Vector<SampleData>& samples )
|
||||
{
|
||||
struct FrameCache
|
||||
{
|
||||
uint64_t symaddr;
|
||||
StringIdx name;
|
||||
bool external;
|
||||
};
|
||||
|
||||
std::vector<FrameCache> cache;
|
||||
|
||||
for( auto& v : samples )
|
||||
{
|
||||
cache.clear();
|
||||
|
||||
const auto cs = v.callstack.Val();
|
||||
const auto& callstack = worker.GetCallstack( cs );
|
||||
const auto csz = callstack.size();
|
||||
if( m_flameExternal )
|
||||
{
|
||||
for( size_t i=csz; i>0; i-- )
|
||||
{
|
||||
auto frameData = worker.GetCallstackFrame( callstack[i-1] );
|
||||
if( frameData )
|
||||
{
|
||||
for( uint8_t j=frameData->size; j>0; j-- )
|
||||
{
|
||||
const auto frame = frameData->data[j-1];
|
||||
const auto symaddr = frame.symAddr;
|
||||
if( symaddr != 0 )
|
||||
{
|
||||
cache.emplace_back( FrameCache { symaddr, frame.name } );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( !m_flameExternalTail )
|
||||
{
|
||||
for( size_t i=csz; i>0; i-- )
|
||||
{
|
||||
auto frameData = worker.GetCallstackFrame( callstack[i-1] );
|
||||
if( frameData )
|
||||
{
|
||||
for( uint8_t j=frameData->size; j>0; j-- )
|
||||
{
|
||||
const auto frame = frameData->data[j-1];
|
||||
const auto symaddr = frame.symAddr;
|
||||
if( symaddr != 0 )
|
||||
{
|
||||
auto filename = m_worker.GetString( frame.file );
|
||||
auto image = frameData->imageName.Active() ? m_worker.GetString( frameData->imageName ) : nullptr;
|
||||
if( !IsFrameExternal( filename, image ) )
|
||||
{
|
||||
cache.emplace_back( FrameCache { symaddr, frame.name } );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( size_t i=csz; i>0; i-- )
|
||||
{
|
||||
auto frameData = worker.GetCallstackFrame( callstack[i-1] );
|
||||
if( frameData )
|
||||
{
|
||||
for( uint8_t j=frameData->size; j>0; j-- )
|
||||
{
|
||||
const auto frame = frameData->data[j-1];
|
||||
const auto symaddr = frame.symAddr;
|
||||
if( symaddr != 0 )
|
||||
{
|
||||
auto filename = m_worker.GetString( frame.file );
|
||||
auto image = frameData->imageName.Active() ? m_worker.GetString( frameData->imageName ) : nullptr;
|
||||
cache.emplace_back( FrameCache { symaddr, frame.name, IsFrameExternal( filename, image ) } );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool tail = true;
|
||||
for( size_t i=cache.size(); i>0; i-- )
|
||||
{
|
||||
const auto idx = i-1;
|
||||
if( !cache[idx].external )
|
||||
{
|
||||
tail = false;
|
||||
}
|
||||
else if( !tail )
|
||||
{
|
||||
cache.erase( cache.begin() + idx );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto vec = &data;
|
||||
for( auto& v : cache )
|
||||
{
|
||||
auto it = std::find_if( vec->begin(), vec->end(), [symaddr = v.symaddr]( const auto& v ) { return v.srcloc == symaddr; } );
|
||||
if( it == vec->end() )
|
||||
{
|
||||
vec->emplace_back( FlameGraphItem { (int64_t)v.symaddr, 1, v.name } );
|
||||
vec = &vec->back().children;
|
||||
}
|
||||
else
|
||||
{
|
||||
it->time++;
|
||||
vec = &it->children;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SortFlameGraph( std::vector<FlameGraphItem>& data )
|
||||
{
|
||||
pdqsort_branchless( data.begin(), data.end(), []( const FlameGraphItem& lhs, const FlameGraphItem& rhs ) { return lhs.time > rhs.time; } );
|
||||
for( auto& v : data ) SortFlameGraph( v.children );
|
||||
}
|
||||
|
||||
struct FlameGraphContext
|
||||
{
|
||||
ImDrawList* draw;
|
||||
ImVec2 wpos;
|
||||
ImVec2 dpos;
|
||||
float ty;
|
||||
float ostep;
|
||||
double pxns;
|
||||
double nspx;
|
||||
int64_t vStart;
|
||||
int64_t vEnd;
|
||||
};
|
||||
|
||||
void View::DrawFlameGraphLevel( const std::vector<FlameGraphItem>& data, FlameGraphContext& ctx, int depth, bool samples )
|
||||
{
|
||||
const auto vStart = ctx.vStart;
|
||||
const auto vEnd = ctx.vEnd;
|
||||
const auto nspx = ctx.nspx;
|
||||
const auto pxns = ctx.pxns;
|
||||
const auto draw = ctx.draw;
|
||||
const auto ostep = ctx.ostep;
|
||||
const auto& wpos = ctx.wpos;
|
||||
|
||||
const auto MinVisNs = int64_t( round( GetScale() * MinVisSize * nspx ) );
|
||||
|
||||
auto it = std::lower_bound( data.begin(), data.end(), vStart, [] ( const auto& l, const auto& r ) { return l.begin + l.time < r; } );
|
||||
if( it == data.end() ) return;
|
||||
|
||||
const auto zitend = std::lower_bound( it, data.end(), vEnd, [] ( const auto& l, const auto& r ) { return l.begin < r; } );
|
||||
if( it == zitend ) return;
|
||||
|
||||
while( it < zitend )
|
||||
{
|
||||
const auto end = it->begin + it->time;
|
||||
const auto zsz = it->time;
|
||||
if( zsz < MinVisNs )
|
||||
{
|
||||
auto nextTime = end + MinVisNs;
|
||||
auto next = it + 1;
|
||||
for(;;)
|
||||
{
|
||||
next = std::lower_bound( next, zitend, nextTime, [] ( const auto& l, const auto& r ) { return l.begin + l.time < r; } );
|
||||
if( next == zitend ) break;
|
||||
if( next->time >= MinVisNs ) break;
|
||||
nextTime = next->begin + next->time + MinVisNs;
|
||||
}
|
||||
const auto px0 = ( it->begin - vStart ) * pxns;
|
||||
const auto px1 = ( (next-1)->begin + (next-1)->time - vStart ) * pxns;
|
||||
draw->AddRectFilled( ImVec2( wpos.x + px0, wpos.y + depth * ostep ), ImVec2( wpos.x + std::max( px1, px0 + MinVisSize ), wpos.y + ( depth + 1 ) * ostep ), 0xFF666666 );
|
||||
DrawZigZag( draw, ImVec2( wpos.x, wpos.y + ( depth + 0.5f ) * ostep ), px0, std::max( px1, px0 + MinVisSize ), ctx.ty / 4, 0xFF444444 );
|
||||
it = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawFlameGraphItem( *it, ctx, depth, samples );
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void View::DrawFlameGraphItem( const FlameGraphItem& item, FlameGraphContext& ctx, int depth, bool samples )
|
||||
{
|
||||
const auto x0 = ctx.dpos.x + item.begin * ctx.pxns;
|
||||
const auto x1 = x0 + item.time * ctx.pxns;
|
||||
const auto y0 = ctx.dpos.y + depth * ctx.ostep;
|
||||
const auto y1 = y0 + ctx.ty;
|
||||
|
||||
const SourceLocation* srcloc;
|
||||
uint32_t color;
|
||||
const char* name;
|
||||
const char* normalized;
|
||||
const char* slName;
|
||||
|
||||
uint32_t textColor = 0xFFFFFFFF;
|
||||
|
||||
if( !samples )
|
||||
{
|
||||
srcloc = &m_worker.GetSourceLocation( item.srcloc );
|
||||
color = GetSrcLocColor( *srcloc, depth );
|
||||
name = slName = m_worker.GetString( srcloc->name.active ? srcloc->name : srcloc->function );
|
||||
}
|
||||
else
|
||||
{
|
||||
name = m_worker.GetString( item.name );
|
||||
const auto symAddr = (uint64_t)item.srcloc;
|
||||
auto sym = m_worker.GetSymbolData( symAddr );
|
||||
if( sym )
|
||||
{
|
||||
auto namehash = charutil::hash( name );
|
||||
if( namehash == 0 ) namehash++;
|
||||
color = GetHsvColor( namehash, depth );
|
||||
if( sym->isInline )
|
||||
{
|
||||
color = DarkenColorHalf( color );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = 0xFF888888;
|
||||
}
|
||||
if( symAddr >> 63 != 0 )
|
||||
{
|
||||
textColor = 0xFF8888FF;
|
||||
}
|
||||
}
|
||||
|
||||
const auto hiColor = HighlightColor( color );
|
||||
const auto darkColor = DarkenColor( color );
|
||||
|
||||
const auto zsz = x1 - x0;
|
||||
|
||||
auto tsz = ImGui::CalcTextSize( name );
|
||||
if( m_vd.shortenName == ShortenName::Never )
|
||||
{
|
||||
normalized = name;
|
||||
}
|
||||
else if( samples )
|
||||
{
|
||||
normalized = ShortenZoneName( ShortenName::OnlyNormalize, name );
|
||||
tsz = ImGui::CalcTextSize( normalized );
|
||||
if( tsz.x > zsz && ( m_vd.shortenName == ShortenName::NoSpace || m_vd.shortenName == ShortenName::NoSpaceAndNormalize ) )
|
||||
{
|
||||
normalized = ShortenZoneName( m_vd.shortenName, normalized, tsz, zsz );
|
||||
}
|
||||
}
|
||||
else if( m_vd.shortenName == ShortenName::Always || ( ( m_vd.shortenName == ShortenName::NoSpace || m_vd.shortenName == ShortenName::NoSpaceAndNormalize ) && tsz.x > zsz ) )
|
||||
{
|
||||
normalized = ShortenZoneName( m_vd.shortenName, name, tsz, zsz );
|
||||
}
|
||||
else
|
||||
{
|
||||
normalized = name;
|
||||
}
|
||||
|
||||
const bool hover = ImGui::IsWindowHovered() && ImGui::IsMouseHoveringRect( ImVec2( x0, y0 ), ImVec2( x1, y1 ) );
|
||||
|
||||
ctx.draw->AddRectFilled( ImVec2( x0, y0 ), ImVec2( x1, y1 ), color );
|
||||
if( hover )
|
||||
{
|
||||
ctx.draw->AddRect( ImVec2( x0 - 0.5f, y0 - 0.5f ), ImVec2( x1 - 0.5f, y1 - 0.5f ), 0xFFEEEEEE );
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawLine( ctx.draw, ImVec2( x0, y1 ), ImVec2( x0, y0 ), ImVec2( x1-1, y0 ), hiColor );
|
||||
DrawLine( ctx.draw, ImVec2( x0, y1 ), ImVec2( x1-1, y1), ImVec2( x1-1, y0 ), darkColor );
|
||||
}
|
||||
|
||||
if( tsz.x < zsz )
|
||||
{
|
||||
const auto x = ( x1 + x0 - tsz.x ) * 0.5;
|
||||
DrawTextContrast( ctx.draw, ImVec2( x, y0 ), textColor, normalized );
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushClipRect( ImVec2( x0, y0 ), ImVec2( x1, y1 ), true );
|
||||
DrawTextContrast( ctx.draw, ImVec2( x0, y0 ), textColor, normalized );
|
||||
ImGui::PopClipRect();
|
||||
}
|
||||
|
||||
if( hover )
|
||||
{
|
||||
uint64_t self = item.time;
|
||||
for( auto& v : item.children ) self -= v.time;
|
||||
|
||||
ImGui::BeginTooltip();
|
||||
if( samples )
|
||||
{
|
||||
const auto symAddr = (uint64_t)item.srcloc;
|
||||
auto sym = m_worker.GetSymbolData( symAddr );
|
||||
if( sym )
|
||||
{
|
||||
TextFocused( "Name:", normalized );
|
||||
if( sym->isInline )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( "[inline]" );
|
||||
}
|
||||
const bool isKernel = symAddr >> 63 != 0;
|
||||
if( isKernel )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( ICON_FA_HAT_WIZARD " kernel" );
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::PushFont( m_smallFont );
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::TextDisabled( "0x%" PRIx64, symAddr );
|
||||
ImGui::PopFont();
|
||||
if( normalized != name && strcmp( normalized, name ) != 0 )
|
||||
{
|
||||
ImGui::PushFont( m_smallFont );
|
||||
TextDisabledUnformatted( name );
|
||||
ImGui::PopFont();
|
||||
}
|
||||
ImGui::Separator();
|
||||
const char* file;
|
||||
uint32_t line;
|
||||
if( sym->isInline )
|
||||
{
|
||||
file = m_worker.GetString( sym->callFile );
|
||||
line = sym->callLine;
|
||||
}
|
||||
else
|
||||
{
|
||||
file = m_worker.GetString( sym->file );
|
||||
line = sym->line;
|
||||
}
|
||||
if( file[0] != '[' )
|
||||
{
|
||||
ImGui::TextDisabled( "Location:" );
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted( LocationToString( file, line ) );
|
||||
}
|
||||
TextFocused( "Image:", m_worker.GetString( sym->imageName ) );
|
||||
ImGui::Separator();
|
||||
const auto period = m_worker.GetSamplingPeriod();
|
||||
TextFocused( "Execution time:", TimeToString( item.time * period ) );
|
||||
if( !item.children.empty() )
|
||||
{
|
||||
TextFocused( "Self time:", TimeToString( self * period ) );
|
||||
char buf[64];
|
||||
PrintStringPercent( buf, 100.f * self / item.time );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( buf );
|
||||
}
|
||||
|
||||
if( IsMouseClicked( 0 ) )
|
||||
{
|
||||
ViewDispatch( file, line, symAddr );
|
||||
}
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( srcloc->name.active )
|
||||
{
|
||||
ImGui::TextUnformatted( m_worker.GetString( srcloc->name ) );
|
||||
}
|
||||
ImGui::TextUnformatted( m_worker.GetString( srcloc->function ) );
|
||||
ImGui::Separator();
|
||||
SmallColorBox( GetSrcLocColor( *srcloc, 0 ) );
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted( LocationToString( m_worker.GetString( srcloc->file ), srcloc->line ) );
|
||||
ImGui::Separator();
|
||||
TextFocused( "Execution time:", TimeToString( item.time ) );
|
||||
if( !item.children.empty() )
|
||||
{
|
||||
TextFocused( "Self time:", TimeToString( self ) );
|
||||
char buf[64];
|
||||
PrintStringPercent( buf, 100.f * self / item.time );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( buf );
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
|
||||
if( IsMouseClicked( 0 ) )
|
||||
{
|
||||
m_findZone.ShowZone( item.srcloc, slName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawFlameGraphLevel( item.children, ctx, depth+1, samples );
|
||||
}
|
||||
|
||||
void View::DrawFlameGraphHeader( uint64_t timespan )
|
||||
{
|
||||
const auto wpos = ImGui::GetCursorScreenPos();
|
||||
const auto dpos = wpos + ImVec2( 0.5f, 0.5f );
|
||||
const auto w = ImGui::GetContentRegionAvail().x;// - ImGui::GetStyle().ScrollbarSize;
|
||||
auto draw = ImGui::GetWindowDrawList();
|
||||
const auto ty = ImGui::GetTextLineHeight();
|
||||
const auto ty025 = round( ty * 0.25f );
|
||||
const auto ty0375 = round( ty * 0.375f );
|
||||
const auto ty05 = round( ty * 0.5f );
|
||||
|
||||
const auto pxns = w / double( timespan );
|
||||
const auto nspx = 1.0 / pxns;
|
||||
const auto scale = std::max( 0.0, round( log10( nspx ) + 2 ) );
|
||||
const auto step = pow( 10, scale );
|
||||
|
||||
ImGui::InvisibleButton( "##flameHeader", ImVec2( w, ty * 1.5f ) );
|
||||
TooltipIfHovered( TimeToStringExact( ( ImGui::GetIO().MousePos.x - wpos.x ) * nspx ) );
|
||||
|
||||
const auto dx = step * pxns;
|
||||
double x = 0;
|
||||
int tw = 0;
|
||||
int tx = 0;
|
||||
int64_t tt = 0;
|
||||
while( x < w )
|
||||
{
|
||||
DrawLine( draw, dpos + ImVec2( x, 0 ), dpos + ImVec2( x, ty05 ), 0x66FFFFFF );
|
||||
if( tw == 0 )
|
||||
{
|
||||
auto txt = "0";
|
||||
draw->AddText( wpos + ImVec2( x, ty05 ), 0x66FFFFFF, txt );
|
||||
tw = ImGui::CalcTextSize( txt ).x;
|
||||
}
|
||||
else if( x > tx + tw + ty * 2 )
|
||||
{
|
||||
tx = x;
|
||||
auto txt = TimeToString( tt );
|
||||
draw->AddText( wpos + ImVec2( x, ty05 ), 0x66FFFFFF, txt );
|
||||
tw = ImGui::CalcTextSize( txt ).x;
|
||||
}
|
||||
|
||||
if( scale != 0 )
|
||||
{
|
||||
for( int i=1; i<5; i++ )
|
||||
{
|
||||
DrawLine( draw, dpos + ImVec2( x + i * dx / 10, 0 ), dpos + ImVec2( x + i * dx / 10, ty025 ), 0x33FFFFFF );
|
||||
}
|
||||
DrawLine( draw, dpos + ImVec2( x + 5 * dx / 10, 0 ), dpos + ImVec2( x + 5 * dx / 10, ty0375 ), 0x33FFFFFF );
|
||||
for( int i=6; i<10; i++ )
|
||||
{
|
||||
DrawLine( draw, dpos + ImVec2( x + i * dx / 10, 0 ), dpos + ImVec2( x + i * dx / 10, ty025 ), 0x33FFFFFF );
|
||||
}
|
||||
}
|
||||
|
||||
x += dx;
|
||||
tt += step;
|
||||
}
|
||||
}
|
||||
|
||||
static void MergeFlameGraph( std::vector<FlameGraphItem>& dst, std::vector<FlameGraphItem>&& src )
|
||||
{
|
||||
for( auto& v : src )
|
||||
{
|
||||
auto it = std::find_if( dst.begin(), dst.end(), [&v]( const auto& vv ) { return vv.srcloc == v.srcloc; } );
|
||||
if( it == dst.end() )
|
||||
{
|
||||
dst.emplace_back( std::move( v ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
it->time += v.time;
|
||||
MergeFlameGraph( it->children, std::move( v.children ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FixupTime( std::vector<FlameGraphItem>& data, uint64_t t = 0 )
|
||||
{
|
||||
for( auto& v : data )
|
||||
{
|
||||
v.begin = t;
|
||||
if( !v.children.empty() ) FixupTime( v.children, t );
|
||||
t += v.time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void View::DrawFlameGraph()
|
||||
{
|
||||
const auto scale = GetScale();
|
||||
ImGui::SetNextWindowSize( ImVec2( 1400 * scale, 800 * scale ), ImGuiCond_FirstUseEver );
|
||||
ImGui::Begin( "Flame graph", &m_showFlameGraph, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse );
|
||||
if( ImGui::GetCurrentWindowRead()->SkipItems ) { ImGui::End(); return; }
|
||||
|
||||
ImGui::PushStyleVar( ImGuiStyleVar_FramePadding, ImVec2( 2, 2 ) );
|
||||
if( ImGui::RadioButton( ICON_FA_SYRINGE " Instrumentation", &m_flameMode, 0 ) ) m_flameGraphInvariant.Reset();
|
||||
|
||||
if( m_worker.AreCallstackSamplesReady() && m_worker.GetCallstackSampleCount() > 0 )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if( ImGui::RadioButton( ICON_FA_EYE_DROPPER " Sampling", &m_flameMode, 1 ) ) m_flameGraphInvariant.Reset();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx( ImGuiSeparatorFlags_Vertical );
|
||||
ImGui::SameLine();
|
||||
|
||||
if( ImGui::Checkbox( ICON_FA_ARROW_UP_WIDE_SHORT " Sort by time", &m_flameSort ) ) m_flameGraphInvariant.Reset();
|
||||
|
||||
if( m_flameMode == 0 )
|
||||
{
|
||||
if( m_worker.HasContextSwitches() )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if( ImGui::Checkbox( "Running time", &m_flameRunningTime ) ) m_flameGraphInvariant.Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( !m_flameRunningTime );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx( ImGuiSeparatorFlags_Vertical );
|
||||
ImGui::SameLine();
|
||||
ImGui::Text( ICON_FA_SHIELD_HALVED "External" );
|
||||
ImGui::SameLine();
|
||||
if( ImGui::Checkbox( "Frames", &m_flameExternal ) ) m_flameGraphInvariant.Reset();
|
||||
ImGui::SameLine();
|
||||
if( m_flameExternal ) ImGui::BeginDisabled();
|
||||
if( ImGui::Checkbox( "Tails", &m_flameExternalTail ) ) m_flameGraphInvariant.Reset();
|
||||
if( m_flameExternal ) ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
auto& td = m_worker.GetThreadData();
|
||||
auto expand = ImGui::TreeNode( ICON_FA_SHUFFLE " Visible threads:" );
|
||||
ImGui::SameLine();
|
||||
size_t visibleThreads = 0;
|
||||
size_t tsz = 0;
|
||||
for( const auto& t : td )
|
||||
{
|
||||
if( FlameGraphThread( t->id ) ) visibleThreads++;
|
||||
tsz++;
|
||||
}
|
||||
if( visibleThreads == tsz )
|
||||
{
|
||||
ImGui::TextDisabled( "(%zu)", tsz );
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextDisabled( "(%zu/%zu)", visibleThreads, tsz );
|
||||
}
|
||||
if( expand )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if( ImGui::SmallButton( "Select all" ) )
|
||||
{
|
||||
for( const auto& t : td )
|
||||
{
|
||||
FlameGraphThread( t->id ) = true;
|
||||
}
|
||||
m_flameGraphInvariant.Reset();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if( ImGui::SmallButton( "Unselect all" ) )
|
||||
{
|
||||
for( const auto& t : td )
|
||||
{
|
||||
FlameGraphThread( t->id ) = false;
|
||||
}
|
||||
m_flameGraphInvariant.Reset();
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
for( const auto& t : td )
|
||||
{
|
||||
ImGui::PushID( idx++ );
|
||||
const auto threadColor = GetThreadColor( t->id, 0 );
|
||||
SmallColorBox( threadColor );
|
||||
ImGui::SameLine();
|
||||
if( SmallCheckbox( m_worker.GetThreadName( t->id ), &FlameGraphThread( t->id ) ) ) m_flameGraphInvariant.Reset();
|
||||
ImGui::PopID();
|
||||
if( t->isFiber )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
TextColoredUnformatted( ImVec4( 0.2f, 0.6f, 0.2f, 1.f ), "Fiber" );
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
if( m_flameMode == 0 && ( m_flameGraphInvariant.count != m_worker.GetZoneCount() || m_flameGraphInvariant.lastTime != m_worker.GetLastTime() ) ||
|
||||
m_flameMode == 1 && ( m_flameGraphInvariant.count != m_worker.GetCallstackSampleCount() ) )
|
||||
{
|
||||
size_t sz = 0;
|
||||
for( auto& thread : td ) if( FlameGraphThread( thread->id ) ) sz++;
|
||||
|
||||
std::vector<std::vector<FlameGraphItem>> threadData;
|
||||
threadData.resize( sz );
|
||||
|
||||
size_t idx = 0;
|
||||
if( m_flameMode == 0 )
|
||||
{
|
||||
for( auto& thread : td )
|
||||
{
|
||||
if( FlameGraphThread( thread->id ) )
|
||||
{
|
||||
if( m_flameRunningTime )
|
||||
{
|
||||
const auto ctx = m_worker.GetContextSwitchData( thread->id );
|
||||
if( ctx )
|
||||
{
|
||||
m_td.Queue( [this, idx, ctx, thread, &threadData] {
|
||||
BuildFlameGraph( m_worker, threadData[idx], thread->timeline, ctx );
|
||||
} );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_td.Queue( [this, idx, thread, &threadData] {
|
||||
BuildFlameGraph( m_worker, threadData[idx], thread->timeline );
|
||||
} );
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
m_flameGraphInvariant.count = m_worker.GetZoneCount();
|
||||
m_flameGraphInvariant.lastTime = m_worker.GetLastTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
for( auto& thread : td )
|
||||
{
|
||||
if( FlameGraphThread( thread->id ) )
|
||||
{
|
||||
m_td.Queue( [this, idx, thread, &threadData] {
|
||||
BuildFlameGraph( m_worker, threadData[idx], thread->samples );
|
||||
} );
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
m_flameGraphInvariant.count = m_worker.GetCallstackSampleCount();
|
||||
}
|
||||
m_td.Sync();
|
||||
|
||||
m_flameGraphData.clear();
|
||||
if( !threadData.empty() )
|
||||
{
|
||||
std::swap( m_flameGraphData, threadData[0] );
|
||||
for( size_t i=1; i<threadData.size(); i++ )
|
||||
{
|
||||
MergeFlameGraph( m_flameGraphData, std::move( threadData[i] ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( m_flameSort ) SortFlameGraph( m_flameGraphData );
|
||||
FixupTime( m_flameGraphData );
|
||||
}
|
||||
|
||||
int64_t zsz = 0;
|
||||
for( auto& v : m_flameGraphData ) zsz += v.time;
|
||||
|
||||
ImGui::BeginChild( "##flameGraph" );
|
||||
const auto region = ImGui::GetContentRegionAvail();
|
||||
|
||||
if( m_flameGraphData.empty() )
|
||||
{
|
||||
ImGui::PushFont( m_bigFont );
|
||||
ImGui::Dummy( ImVec2( 0, ( region.y - ImGui::GetTextLineHeight() * 2 ) * 0.5f ) );
|
||||
TextCentered( ICON_FA_CAT );
|
||||
TextCentered( "No data available to display" );
|
||||
ImGui::PopFont();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawFlameGraphHeader( m_flameMode == 0 ? zsz : zsz * m_worker.GetSamplingPeriod() );
|
||||
|
||||
FlameGraphContext ctx;
|
||||
ctx.draw = ImGui::GetWindowDrawList();
|
||||
ctx.wpos = ImGui::GetCursorScreenPos();
|
||||
ctx.dpos = ctx.wpos + ImVec2( 0.5f, 0.5f );
|
||||
ctx.ty = ImGui::GetTextLineHeight();
|
||||
ctx.ostep = ctx.ty + 1;
|
||||
ctx.pxns = region.x / zsz;
|
||||
ctx.nspx = 1.0 / ctx.pxns;
|
||||
ctx.vStart = 0;
|
||||
ctx.vEnd = zsz;
|
||||
|
||||
ImGui::ItemSize( region );
|
||||
DrawFlameGraphLevel( m_flameGraphData, ctx, 0, m_flameMode == 1 );
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
}
|
@ -95,7 +95,7 @@ void View::DrawFrames()
|
||||
|
||||
if( hover )
|
||||
{
|
||||
const auto hwheel_delta = io.MouseWheelH * 100.f;
|
||||
const auto hwheel_delta = io.MouseWheelH * 100.f * m_horizontalScrollMultiplier;
|
||||
if( IsMouseDragging( 1 ) || hwheel_delta != 0 )
|
||||
{
|
||||
m_viewMode = ViewMode::Paused;
|
||||
|
@ -106,7 +106,9 @@ void View::DrawTimelineFrames( const FrameData& frames )
|
||||
const auto ty025 = ty * 0.25f;
|
||||
const auto ty05 = round( ty * 0.5f );
|
||||
|
||||
ImGui::PushID( &frames );
|
||||
ImGui::InvisibleButton( "##zoneFrames", ImVec2( w, ty ) );
|
||||
ImGui::PopID();
|
||||
bool hover = ImGui::IsItemHovered();
|
||||
|
||||
auto timespan = m_vd.zvEnd - m_vd.zvStart;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "TracyImGui.hpp"
|
||||
#include "TracyPrint.hpp"
|
||||
#include "TracyView.hpp"
|
||||
#include "tracy_pdqsort.h"
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
|
@ -4,15 +4,16 @@
|
||||
#include "TracyMouse.hpp"
|
||||
#include "TracyPrint.hpp"
|
||||
#include "TracyView.hpp"
|
||||
#include "tracy_pdqsort.h"
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
|
||||
enum { ChunkBits = 10 };
|
||||
enum { PageBits = 10 };
|
||||
enum { PageSize = 1 << PageBits };
|
||||
enum { PageChunkBits = ChunkBits + PageBits };
|
||||
enum { PageChunkSize = 1 << PageChunkBits };
|
||||
constexpr size_t ChunkBits = 10;
|
||||
constexpr size_t PageBits = 10;
|
||||
constexpr size_t PageSize = 1 << PageBits;
|
||||
constexpr size_t PageChunkBits = ChunkBits + PageBits;
|
||||
constexpr size_t PageChunkSize = 1 << PageChunkBits;
|
||||
|
||||
uint32_t MemDecayColor[256] = {
|
||||
0x0, 0xFF077F07, 0xFF078007, 0xFF078207, 0xFF078307, 0xFF078507, 0xFF078707, 0xFF078807,
|
||||
@ -198,7 +199,12 @@ void View::DrawMemory()
|
||||
auto& mem = m_worker.GetMemoryNamed( m_memInfo.pool );
|
||||
if( mem.data.empty() )
|
||||
{
|
||||
ImGui::TextWrapped( "No memory data collected." );
|
||||
const auto ty = ImGui::GetTextLineHeight();
|
||||
ImGui::PushFont( m_bigFont );
|
||||
ImGui::Dummy( ImVec2( 0, ( ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeight() * 2 ) * 0.5f ) );
|
||||
TextCentered( ICON_FA_DOG );
|
||||
TextCentered( "No memory data collected" );
|
||||
ImGui::PopFont();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
@ -17,14 +17,16 @@ void View::DrawMessages()
|
||||
|
||||
if( msgs.empty() )
|
||||
{
|
||||
ImGui::TextUnformatted( "No messages were collected." );
|
||||
const auto ty = ImGui::GetTextLineHeight();
|
||||
ImGui::PushFont( m_bigFont );
|
||||
ImGui::Dummy( ImVec2( 0, ( ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeight() * 2 ) * 0.5f ) );
|
||||
TextCentered( ICON_FA_FISH_FINS );
|
||||
TextCentered( "No messages were collected" );
|
||||
ImGui::PopFont();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
size_t tsz = 0;
|
||||
for( const auto& t : m_threadOrder ) if( !t->messages.empty() ) tsz++;
|
||||
|
||||
bool filterChanged = m_messageFilter.Draw( ICON_FA_FILTER " Filter messages", 200 );
|
||||
ImGui::SameLine();
|
||||
if( ImGui::Button( ICON_FA_DELETE_LEFT " Clear" ) )
|
||||
@ -51,7 +53,22 @@ void View::DrawMessages()
|
||||
bool threadsChanged = false;
|
||||
auto expand = ImGui::TreeNode( ICON_FA_SHUFFLE " Visible threads:" );
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "(%zu)", tsz );
|
||||
size_t visibleThreads = 0;
|
||||
size_t tsz = 0;
|
||||
for( const auto& t : m_threadOrder )
|
||||
{
|
||||
if( t->messages.empty() ) continue;
|
||||
if( VisibleMsgThread( t->id ) ) visibleThreads++;
|
||||
tsz++;
|
||||
}
|
||||
if( visibleThreads == tsz )
|
||||
{
|
||||
ImGui::TextDisabled( "(%zu)", tsz );
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextDisabled( "(%zu/%zu)", visibleThreads, tsz );
|
||||
}
|
||||
if( expand )
|
||||
{
|
||||
auto& crash = m_worker.GetCrashEvent();
|
||||
@ -235,7 +252,7 @@ void View::DrawMessageLine( const MessageData& msg, bool hasCallstack, int& idx
|
||||
const auto text = m_worker.GetString( msg.ref );
|
||||
const auto tid = m_worker.DecompressThread( msg.thread );
|
||||
ImGui::PushID( &msg );
|
||||
if( ImGui::Selectable( TimeToStringExact( msg.time ), m_msgHighlight == &msg, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap ) )
|
||||
if( ImGui::Selectable( TimeToStringExact( msg.time ), m_msgHighlight == &msg, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap ) )
|
||||
{
|
||||
CenterAtTime( msg.time );
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ void View::DrawNotificationArea()
|
||||
ImGui::SameLine();
|
||||
const auto pos = ImGui::GetCursorPos();
|
||||
ImGui::TextUnformatted( " " );
|
||||
ImGui::GetWindowDrawList()->AddCircleFilled( pos + ImVec2( 0, ty * 0.75f ), ty * ( 0.2f + ( sin( s_time * 8 ) + 1 ) * 0.125f ), 0xFF888888, 10 );
|
||||
ImGui::GetWindowDrawList()->AddCircleFilled( pos + ImVec2( 0, ty * 0.675f ), ty * ( 0.2f + ( sin( s_time * 8 ) + 1 ) * 0.125f ), 0xFF888888, 10 );
|
||||
auto rmin = ImGui::GetItemRectMin();
|
||||
rmin.x -= ty * 0.5f;
|
||||
const auto rmax = ImGui::GetItemRectMax();
|
||||
@ -260,6 +260,12 @@ void View::DrawNotificationArea()
|
||||
const auto fps = RealToString( int( io.Framerate + 0.5f ) );
|
||||
const auto fpssz = ImGui::CalcTextSize( fps ).x;
|
||||
ImGui::GetWindowDrawList()->AddText( wpos + ImVec2( w-fpssz, 0 ), 0x88FFFFFF, fps );
|
||||
|
||||
#ifndef NDEBUG
|
||||
const auto dsz = ImGui::CalcTextSize( "8888 DEBUG" ).x;
|
||||
ImGui::GetWindowDrawList()->AddText( wpos + ImVec2( w-dsz, 0 ), 0x886666FF, "DEBUG" );
|
||||
#endif
|
||||
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user