From 54e953ac399c13cdbff76a30fe4b7184477c3ed7 Mon Sep 17 00:00:00 2001 From: Tom Atkinson Date: Mon, 17 Jul 2023 18:25:55 +0100 Subject: [PATCH] Add Tracy Profiler Support --- .gitignore | 1 + .gitmodules | 3 + bldsys/cmake/global_options.cmake | 5 +- components/core/CMakeLists.txt | 8 +- .../core/include/core/util/profiling.hpp | 123 ++++++++++++ components/core/src/profiling.cpp | 33 ++++ framework/CMakeLists.txt | 2 +- framework/core/device.cpp | 23 ++- framework/core/hpp_device.cpp | 9 +- framework/gltf_loader.cpp | 12 ++ .../scene_graph/components/image/astc.cpp | 3 + framework/stats/stats.cpp | 146 +++++++++++++- framework/stats/stats.h | 7 +- scripts/tracy.py | 179 ++++++++++++++++++ third_party/CMakeLists.txt | 36 ++-- third_party/tracy | 1 + third_party/vma | 2 +- 17 files changed, 555 insertions(+), 38 deletions(-) create mode 100644 components/core/include/core/util/profiling.hpp create mode 100644 components/core/src/profiling.cpp create mode 100755 scripts/tracy.py create mode 160000 third_party/tracy diff --git a/.gitignore b/.gitignore index 37927b45d2..540779e959 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ tags *~ .*.sw* .sw* +.tracy \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 2f61d8e24d..3a8957b78f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -56,3 +56,6 @@ [submodule "third_party/catch2"] path = third_party/catch2 url = https://github.com/catchorg/Catch2.git +[submodule "third_party/tracy"] + path = third_party/tracy + url = https://github.com/wolfpld/tracy.git diff --git a/bldsys/cmake/global_options.cmake b/bldsys/cmake/global_options.cmake index 42c62029c0..a6f99af325 100644 --- a/bldsys/cmake/global_options.cmake +++ b/bldsys/cmake/global_options.cmake @@ -55,6 +55,7 @@ set(VKB_BUILD_TESTS OFF CACHE BOOL "Enable generation and building of Vulkan bes set(VKB_WSI_SELECTION "XCB" CACHE STRING "Select WSI target (XCB, XLIB, WAYLAND, D2D)") set(VKB_CLANG_TIDY OFF CACHE STRING "Use CMake Clang Tidy integration") set(VKB_CLANG_TIDY_EXTRAS "-header-filter=framework,samples,app;-checks=-*,google-*,-google-runtime-references;--fix;--fix-errors" CACHE STRING "Clang Tidy Parameters") +set(VKB_ENABLE_TRACY OFF CACHE BOOL "Enable Tracy profiling") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin/${CMAKE_BUILD_TYPE}/${TARGET_ARCH}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "lib/${CMAKE_BUILD_TYPE}/${TARGET_ARCH}") @@ -73,4 +74,6 @@ set(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG=0 ${CMAKE_CXX_FLAGS_DEBUG}") if (VKB_CLANG_TIDY) find_program(CLANG_TIDY "clang-tidy" "clang-tidy-15" REQUIRED) set(VKB_DO_CLANG_TIDY ${CLANG_TIDY} ${VKB_CLANG_TIDY_EXTRAS}) -endif() \ No newline at end of file +endif() + +set(TRACY_ENABLE ${VKB_ENABLE_TRACY}) \ No newline at end of file diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 9eaa28f991..09503efa24 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -17,13 +17,19 @@ vkb__register_component( NAME core HEADERS - include/core/util/strings.hpp + include/core/platform/context.hpp + include/core/platform/entrypoint.hpp + include/core/util/error.hpp include/core/util/hash.hpp + include/core/util/profiling.hpp + include/core/util/strings.hpp SRC src/strings.cpp + src/profiling.cpp LINK_LIBS spdlog::spdlog + TracyClient ) vkb__register_tests( diff --git a/components/core/include/core/util/profiling.hpp b/components/core/include/core/util/profiling.hpp new file mode 100644 index 0000000000..078479c263 --- /dev/null +++ b/components/core/include/core/util/profiling.hpp @@ -0,0 +1,123 @@ +/* Copyright (c) 2023, Thomas Atkinson + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#include "core/util/error.hpp" + +VKBP_DISABLE_WARNINGS() +#include +VKBP_ENABLE_WARNINGS() + +// malloc and free are used by Tracy to provide memory profiling +void *operator new(size_t count); +void operator delete(void *ptr) noexcept; + +// Tracy a scope +#define PROFILE_SCOPE(name) ZoneScopedN(name) + +// Trace a function +#define PROFILE_FUNCTION() ZoneScoped + +// The type of plot to use +enum class PlotType +{ + Number, + Percentage, + Memory, +}; + +// tracy::PlotFormatType is not defined if TRACY_ENABLE is not defined +// so we need to define a function to convert our enum to the tracy enum +#ifdef TRACY_ENABLE +namespace +{ +inline tracy::PlotFormatType to_tracy_plot_format(PlotType type) +{ + switch (type) + { + case PlotType::Number: + return tracy::PlotFormatType::Number; + case PlotType::Percentage: + return tracy::PlotFormatType::Percentage; + case PlotType::Memory: + return tracy::PlotFormatType::Memory; + default: + return tracy::PlotFormatType::Number; + } +} +} // namespace + +# define TO_TRACY_PLOT_FORMAT(name) to_tracy_plot_format(name) +#else +# define TO_TRACY_PLOT_FORMAT(name) +#endif + +// Create plots +template +class Plot +{ + public: + static void plot(const char *name, T value) + { + auto *p = get_instance(); + p->plots[name] = value; + update_tracy_plot(name, value); + } + + static void increment(const char *name, T amount) + { + auto *p = get_instance(); + p->plots[name] += amount; + update_tracy_plot(name, p->plots[name]); + } + + static void decrement(const char *name, T amount) + { + auto *p = get_instance(); + p->plots[name] -= amount; + update_tracy_plot(name, p->plots[name]); + } + + static void reset(const char *name) + { + auto *p = get_instance(); + p->plots[name] = T{}; + update_tracy_plot(name, p->plots[name]); + } + + private: + static void update_tracy_plot(const char *name, T value) + { + TracyPlot(name, value); + TracyPlotConfig(name, TO_TRACY_PLOT_FORMAT(PT), true, true, 0); + } + + static Plot *get_instance() + { + static_assert((std::is_same::value || std::is_same::value || std::is_same::value), "PlotStore only supports int64_t, double and float"); + static Plot instance; + return &instance; + } + + std::unordered_map plots; +}; diff --git a/components/core/src/profiling.cpp b/components/core/src/profiling.cpp new file mode 100644 index 0000000000..8cda489f2d --- /dev/null +++ b/components/core/src/profiling.cpp @@ -0,0 +1,33 @@ +/* Copyright (c) 2023, Thomas Atkinson + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 the "License"; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core/util/profiling.hpp" + +#include + +void *operator new(size_t count) +{ + auto ptr = malloc(count); + TracyAlloc(ptr, count); + return ptr; +} + +void operator delete(void *ptr) noexcept +{ + TracyFree(ptr); + free(ptr); +} diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index bee1774e0f..66a0c28100 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -518,7 +518,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC glm glslang SPIRV - vma + VulkanMemoryAllocator hwcpipe spirv-cross-glsl glslang-default-resource-limits diff --git a/framework/core/device.cpp b/framework/core/device.cpp index 8fbee54954..8631ff0a8b 100644 --- a/framework/core/device.cpp +++ b/framework/core/device.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2019-2022, Arm Limited and Contributors - * Copyright (c) 2019-2022, Sascha Willems +/* Copyright (c) 2019-2023, Arm Limited and Contributors + * Copyright (c) 2019-2023, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -25,9 +25,9 @@ VKBP_ENABLE_WARNINGS() namespace vkb { -Device::Device(PhysicalDevice & gpu, +Device::Device(PhysicalDevice &gpu, VkSurfaceKHR surface, - std::unique_ptr && debug_utils, + std::unique_ptr &&debug_utils, std::unordered_map requested_extensions) : VulkanResource{VK_NULL_HANDLE, this}, // Recursive, but valid debug_utils{std::move(debug_utils)}, @@ -198,6 +198,9 @@ Device::Device(PhysicalDevice & gpu, } VmaVulkanFunctions vma_vulkan_func{}; + vma_vulkan_func.vkGetDeviceProcAddr = vkGetDeviceProcAddr; + vma_vulkan_func.vkGetInstanceProcAddr = vkGetInstanceProcAddr; + vma_vulkan_func.vkAllocateMemory = vkAllocateMemory; vma_vulkan_func.vkBindBufferMemory = vkBindBufferMemory; vma_vulkan_func.vkBindImageMemory = vkBindImageMemory; @@ -263,10 +266,10 @@ Device::~Device() if (memory_allocator != VK_NULL_HANDLE) { - VmaStats stats; - vmaCalculateStats(memory_allocator, &stats); + VmaTotalStatistics stats; + vmaCalculateStatistics(memory_allocator, &stats); - LOGI("Total device memory leaked: {} bytes.", stats.total.usedBytes); + LOGI("Total device memory leaked: {} bytes.", stats.total.statistics.allocationBytes); vmaDestroyAllocator(memory_allocator); } @@ -306,7 +309,8 @@ DriverVersion Device::get_driver_version() const switch (gpu.get_properties().vendorID) { - case 0x10DE: { + case 0x10DE: + { // Nvidia version.major = (gpu.get_properties().driverVersion >> 22) & 0x3ff; version.minor = (gpu.get_properties().driverVersion >> 14) & 0x0ff; @@ -314,7 +318,8 @@ DriverVersion Device::get_driver_version() const // Ignoring optional tertiary info in lower 6 bits break; } - default: { + default: + { version.major = VK_VERSION_MAJOR(gpu.get_properties().driverVersion); version.minor = VK_VERSION_MINOR(gpu.get_properties().driverVersion); version.patch = VK_VERSION_PATCH(gpu.get_properties().driverVersion); diff --git a/framework/core/hpp_device.cpp b/framework/core/hpp_device.cpp index ad7dab81d3..d8436f4837 100644 --- a/framework/core/hpp_device.cpp +++ b/framework/core/hpp_device.cpp @@ -181,6 +181,9 @@ HPPDevice::HPPDevice(vkb::core::HPPPhysicalDevice &gpu, } VmaVulkanFunctions vma_vulkan_func{}; + vma_vulkan_func.vkGetDeviceProcAddr = reinterpret_cast(get_handle().getProcAddr("vkGetDeviceProcAddr")); + vma_vulkan_func.vkGetInstanceProcAddr = reinterpret_cast(get_handle().getProcAddr("vkGetInstanceProcAddr")); + vma_vulkan_func.vkAllocateMemory = reinterpret_cast(get_handle().getProcAddr("vkAllocateMemory")); vma_vulkan_func.vkBindBufferMemory = reinterpret_cast(get_handle().getProcAddr("vkBindBufferMemory")); vma_vulkan_func.vkBindImageMemory = reinterpret_cast(get_handle().getProcAddr("vkBindImageMemory")); @@ -239,10 +242,10 @@ HPPDevice::~HPPDevice() if (memory_allocator != VK_NULL_HANDLE) { - VmaStats stats; - vmaCalculateStats(memory_allocator, &stats); + VmaTotalStatistics stats; + vmaCalculateStatistics(memory_allocator, &stats); - LOGI("Total device memory leaked: {} bytes.", stats.total.usedBytes); + LOGI("Total device memory leaked: {} bytes.", stats.total.statistics.allocationBytes); vmaDestroyAllocator(memory_allocator); } diff --git a/framework/gltf_loader.cpp b/framework/gltf_loader.cpp index 6e6eddc27d..4a08e3b3ae 100644 --- a/framework/gltf_loader.cpp +++ b/framework/gltf_loader.cpp @@ -29,6 +29,8 @@ VKBP_DISABLE_WARNINGS() #include VKBP_ENABLE_WARNINGS() +#include + #include "api_vulkan_sample.h" #include "common/logging.h" #include "common/utils.h" @@ -406,6 +408,8 @@ GLTFLoader::GLTFLoader(Device const &device) : std::unique_ptr GLTFLoader::read_scene_from_file(const std::string &file_name, int scene_index) { + PROFILE_SCOPE("Load GLTF Scene"); + std::string err; std::string warn; @@ -448,6 +452,8 @@ std::unique_ptr GLTFLoader::read_scene_from_file(const std::string &f std::unique_ptr GLTFLoader::read_model_from_file(const std::string &file_name, uint32_t index, bool storage_buffer) { + PROFILE_SCOPE("Load GLTF Model"); + std::string err; std::string warn; @@ -490,6 +496,8 @@ std::unique_ptr GLTFLoader::read_model_from_file(const std::string sg::Scene GLTFLoader::load_scene(int scene_index) { + PROFILE_SCOPE("Process Scene"); + auto scene = sg::Scene(); scene.set_name("gltf_scene"); @@ -713,6 +721,8 @@ sg::Scene GLTFLoader::load_scene(int scene_index) for (auto &gltf_mesh : model.meshes) { + PROFILE_SCOPE("Processing Mesh"); + auto mesh = parse_mesh(gltf_mesh); for (size_t i_primitive = 0; i_primitive < gltf_mesh.primitives.size(); i_primitive++) @@ -1073,6 +1083,8 @@ sg::Scene GLTFLoader::load_scene(int scene_index) std::unique_ptr GLTFLoader::load_model(uint32_t index, bool storage_buffer) { + PROFILE_SCOPE("Process Model"); + auto submesh = std::make_unique(); std::vector transient_buffers; diff --git a/framework/scene_graph/components/image/astc.cpp b/framework/scene_graph/components/image/astc.cpp index 8b98156646..bad0a57251 100644 --- a/framework/scene_graph/components/image/astc.cpp +++ b/framework/scene_graph/components/image/astc.cpp @@ -20,6 +20,7 @@ #include #include "common/error.h" +#include "core/util/profiling.hpp" VKBP_DISABLE_WARNINGS() #include "common/glm_common.h" @@ -115,6 +116,8 @@ void Astc::init() void Astc::decode(BlockDim blockdim, VkExtent3D extent, const uint8_t *data_) { + PROFILE_SCOPE("Decode ASTC Image"); + // Actual decoding astc_decode_mode decode_mode = DECODE_LDR_SRGB; uint32_t bitness = 8; diff --git a/framework/stats/stats.cpp b/framework/stats/stats.cpp index 4c05e20b37..e92a40d31e 100644 --- a/framework/stats/stats.cpp +++ b/framework/stats/stats.cpp @@ -17,10 +17,15 @@ */ #include "stats/stats.h" -#include "core/device.h" +#include +#include +#include + +#include "core/device.h" #include "frame_time_stats_provider.h" #include "hwcpipe_stats_provider.h" +#include "rendering/render_context.h" #include "vulkan_stats_provider.h" namespace vkb @@ -217,6 +222,8 @@ void Stats::update(float delta_time) break; } } + + profile_counters(); } void Stats::continuous_sampling_worker(std::future should_terminate) @@ -279,6 +286,143 @@ void Stats::push_sample(const StatsProvider::Counters &sample) } } +namespace +{ +// For now names are taken from the stats_provider.cpp file +const char *to_string(StatIndex index) +{ + switch (index) + { + case StatIndex::frame_times: + return "Frame Times (ms)"; + case StatIndex::cpu_cycles: + return "CPU Cycles (M/s)"; + case StatIndex::cpu_instructions: + return "CPU Instructions (M/s)"; + case StatIndex::cpu_cache_miss_ratio: + return "Cache Miss Ratio (%)"; + case StatIndex::cpu_branch_miss_ratio: + return "Branch Miss Ratio (%)"; + case StatIndex::cpu_l1_accesses: + return "CPU L1 Accesses (M/s)"; + case StatIndex::cpu_instr_retired: + return "CPU Instructions Retired (M/s)"; + case StatIndex::cpu_l2_accesses: + return "CPU L2 Accesses (M/s)"; + case StatIndex::cpu_l3_accesses: + return "CPU L3 Accesses (M/s)"; + case StatIndex::cpu_bus_reads: + return "CPU Bus Read Beats (M/s)"; + case StatIndex::cpu_bus_writes: + return "CPU Bus Write Beats (M/s)"; + case StatIndex::cpu_mem_reads: + return "CPU Memory Read Instructions (M/s)"; + case StatIndex::cpu_mem_writes: + return "CPU Memory Write Instructions (M/s)"; + case StatIndex::cpu_ase_spec: + return "CPU Speculatively Exec. SIMD Instructions (M/s)"; + case StatIndex::cpu_vfp_spec: + return "CPU Speculatively Exec. FP Instructions (M/s)"; + case StatIndex::cpu_crypto_spec: + return "CPU Speculatively Exec. Crypto Instructions (M/s)"; + case StatIndex::gpu_cycles: + return "GPU Cycles (M/s)"; + case StatIndex::gpu_vertex_cycles: + return "Vertex Cycles (M/s)"; + case StatIndex::gpu_load_store_cycles: + return "Load Store Cycles (k/s)"; + case StatIndex::gpu_tiles: + return "Tiles (k/s)"; + case StatIndex::gpu_killed_tiles: + return "Tiles killed by CRC match (k/s)"; + case StatIndex::gpu_fragment_jobs: + return "Fragment Jobs (s)"; + case StatIndex::gpu_fragment_cycles: + return "Fragment Cycles (M/s)"; + case StatIndex::gpu_tex_cycles: + return "Shader Texture Cycles (k/s)"; + case StatIndex::gpu_ext_reads: + return "External Reads (M/s)"; + case StatIndex::gpu_ext_writes: + return "External Writes (M/s)"; + case StatIndex::gpu_ext_read_stalls: + return "External Read Stalls (M/s)"; + case StatIndex::gpu_ext_write_stalls: + return "External Write Stalls (M/s)"; + case StatIndex::gpu_ext_read_bytes: + return "External Read Bytes (MiB/s)"; + case StatIndex::gpu_ext_write_bytes: + return "External Write Bytes (MiB/s)"; + default: + return nullptr; + } +} +} // namespace + +void Stats::profile_counters() const +{ + static std::chrono::high_resolution_clock::time_point last_time = std::chrono::high_resolution_clock::now(); + std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now(); + + if (now - last_time < std::chrono::milliseconds(100)) + { + return; + } + + last_time = now; + + for (auto &c : counters) + { + StatIndex idx = c.first; + auto &graph_data = get_graph_data(idx); + + if (c.second.empty()) + { + continue; + } + + float average = 0.0f; + for (auto &v : c.second) + { + average += v; + } + average /= c.second.size(); + + if (auto *index_name = to_string(idx)) + { + Plot::plot(index_name, average * graph_data.scale_factor); + } + } + + static std::vector labels; + + auto &device = render_context.get_device(); + VmaAllocator allocator = device.get_memory_allocator(); + + VmaBudget heap_budgets[VK_MAX_MEMORY_HEAPS]; + vmaGetHeapBudgets(allocator, heap_budgets); + + // We know that we will only ever have one device in the system, so we can cache the labels + if (labels.size() == 0) + { + VkPhysicalDeviceMemoryProperties memory_properties; + vkGetPhysicalDeviceMemoryProperties(device.get_gpu().get_handle(), &memory_properties); + + labels.reserve(memory_properties.memoryHeapCount); + + for (size_t heap = 0; heap < memory_properties.memoryHeapCount; heap++) + { + VkMemoryPropertyFlags flags = memory_properties.memoryHeaps[heap].flags; + labels.push_back("Heap " + std::to_string(heap) + " " + vk::to_string(vk::MemoryPropertyFlags{flags})); + } + } + + for (size_t heap = 0; heap < labels.size(); heap++) + { + Plot::plot(labels[heap].c_str(), heap_budgets[heap].usage / (1024.0f * 1024.0f)); + } +} + void Stats::begin_sampling(CommandBuffer &cb) { // Inform the providers diff --git a/framework/stats/stats.h b/framework/stats/stats.h index b0813f90f7..788699da84 100644 --- a/framework/stats/stats.h +++ b/framework/stats/stats.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2018-2022, Arm Limited and Contributors - * Copyright (c) 2020-2022, Broadcom Inc. +/* Copyright (c) 2018-2023, Arm Limited and Contributors + * Copyright (c) 2020-2023, Broadcom Inc. * * SPDX-License-Identifier: Apache-2.0 * @@ -191,6 +191,9 @@ class Stats /// Updates circular buffers for CPU and GPU counters void push_sample(const StatsProvider::Counters &sample); + + // Push counters to external profilers + void profile_counters() const; }; } // namespace vkb diff --git a/scripts/tracy.py b/scripts/tracy.py new file mode 100755 index 0000000000..99e3420260 --- /dev/null +++ b/scripts/tracy.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python + +# Copyright 2023, Thomas Atkinson +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 the "License"; +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import os +from shutil import which +import shutil +import stat +import subprocess +import sys +from urllib.request import urlretrieve + +SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) +ROOT_DIR = os.path.join(SCRIPT_DIR, "..") +TRACY_SOURCE = os.path.join(ROOT_DIR, "third_party", "tracy") +TRACY_DIR = os.path.join(ROOT_DIR, ".tracy") + +TRACY_WINDOWS_RELEASE_URL="https://github.com/wolfpld/tracy/releases/download/v0.10/Tracy-0.10.7z" + +TRACY_BUILT_UNIX_EXEC = os.path.join( + TRACY_SOURCE, "profiler", "build", "unix", "Tracy-release" +) +TRACY_TARGET_EXEC = ( + os.path.join(TRACY_DIR, "tracy") + if os.name == "posix" + else os.path.join(TRACY_DIR, "Tracy.exe") +) + +def clean_tracy_third_party_changes(): + if os.path.exists(TRACY_SOURCE): + subprocess.run( + ["git", "reset", "--hard"], + cwd=TRACY_SOURCE, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + + +def clean_tracy(): + clean_tracy_third_party_changes() + + if os.path.exists(TRACY_DIR): + shutil.rmtree(TRACY_DIR) + + +def build_tracy_unix() -> bool: + if not which("pkg-config"): + print("pkg-config not found in PATH") + clean_tracy() + return False + + if not which("make"): + print("make not found in PATH") + clean_tracy() + return False + + print() + print() + print( + "you may need to install libglfw3-dev, libcapstone-dev, libdbus-glib-1-dev, libfreetype-dev" + ) + print("on ubuntu, you can run:") + print( + "sudo apt install libglfw3-dev libcapstone-dev libdbus-glib-1-dev libfreetype-dev" + ) + print() + print() + + make_returncode = subprocess.call( + [ + "make", + "LEGACY=1", + "-C", + os.path.join(TRACY_SOURCE, "profiler", "build", "unix"), + ], # ignore wayland build + stdin=subprocess.PIPE, + ) + + if make_returncode != 0: + print("make failed to build tracy") + clean_tracy() + return False + + if os.path.exists(TRACY_BUILT_UNIX_EXEC): + shutil.copyfile(TRACY_BUILT_UNIX_EXEC, TRACY_TARGET_EXEC) + + clean_tracy_third_party_changes() + return True + +def pull_tracy_windows() -> bool: + try: + from pyunpack import Archive + except ImportError: + print("pyunpack not found. Try: pip install pyunpack patool") + return False + + if os.path.exists(TRACY_TARGET_EXEC): + return True + if not os.path.exists(os.path.join(TRACY_DIR, "tracy.7z")): + print("downloading tracy") + urlretrieve(TRACY_WINDOWS_RELEASE_URL, os.path.join(TRACY_DIR, "tracy.7z")) + + try: + print("extracting tracy") + Archive(os.path.join(TRACY_DIR, "tracy.7z")).extractall(TRACY_DIR) + except: + print("failed to extract tracy. Is 7z installed?") + return False + + return True + + +def build_tracy(): + if os.name == "posix": + return build_tracy_unix() + else: + return pull_tracy_windows() + exit(1) + + +def run_tracy(): + if not os.path.exists(TRACY_TARGET_EXEC): + print("tracy not found - building tracy") + if not build_tracy(): + print("failed to build tracy") + exit(1) + + print("tracy found at {}".format(TRACY_TARGET_EXEC)) + st = os.stat(TRACY_TARGET_EXEC) + os.chmod(TRACY_TARGET_EXEC, st.st_mode | stat.S_IEXEC) + subprocess.call([TRACY_TARGET_EXEC]) + + +if __name__ == "__main__": + ## Create the tracy directory if it doesn't exist + if not os.path.exists(TRACY_DIR): + os.mkdir(TRACY_DIR) + + parser = argparse.ArgumentParser( + prog="Tracy Helper", + description="A utility to build and run the tracy profiler", + ) + + subparsers = parser.add_subparsers() + + ## Clean Tracy + clean_tracy_command = subparsers.add_parser("clean", help="clean tracy") + clean_tracy_command.set_defaults(func=clean_tracy) + + ## Build Tracy + build_tracy_command = subparsers.add_parser("build", help="build tracy") + build_tracy_command.set_defaults(func=build_tracy) + + ## Run Tracy + run_tracy_command = subparsers.add_parser("run", help="run tracy") + run_tracy_command.set_defaults(func=run_tracy) + + args = parser.parse_args() + + if len(sys.argv) == 1: + run_tracy() + else: + args.func() diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index f11d1e8e93..ed7203545e 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -42,20 +42,17 @@ target_sources(tinygltf INTERFACE ${TINYGLTF_DIR}/tiny_gltf.h ${TINYGLTF_DIR}/js target_include_directories(tinygltf INTERFACE ${TINYGLTF_DIR}) # vulkan -add_library(vulkan INTERFACE) -set(VULKAN_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vulkan/include) -target_sources(vulkan INTERFACE ${VULKAN_INCLUDE_DIR}/vulkan/vulkan.h) -target_include_directories(vulkan INTERFACE ${VULKAN_INCLUDE_DIR}) +add_subdirectory(vulkan) -target_compile_definitions(vulkan INTERFACE VK_NO_PROTOTYPES) +target_compile_definitions(Vulkan-Headers INTERFACE VK_NO_PROTOTYPES) if(ANDROID) - target_compile_definitions(vulkan INTERFACE VK_USE_PLATFORM_ANDROID_KHR) + target_compile_definitions(Vulkan-Headers INTERFACE VK_USE_PLATFORM_ANDROID_KHR) elseif(WIN32) - target_compile_definitions(vulkan INTERFACE VK_USE_PLATFORM_WIN32_KHR) + target_compile_definitions(Vulkan-Headers INTERFACE VK_USE_PLATFORM_WIN32_KHR) elseif(APPLE) - target_compile_definitions(vulkan INTERFACE VK_USE_PLATFORM_METAL_EXT) + target_compile_definitions(Vulkan-Headers INTERFACE VK_USE_PLATFORM_METAL_EXT) elseif(UNIX) # Choose WSI based on VKB_WSI_SELECTION if (VKB_WSI_SELECTION STREQUAL XCB OR VKB_WSI_SELECTION STREQUAL XLIB OR VKB_WSI_SELECTION STREQUAL WAYLAND) @@ -64,33 +61,29 @@ elseif(UNIX) if (VKB_WSI_SELECTION STREQUAL XCB) pkg_check_modules(XCB xcb REQUIRED) if (XCB_FOUND) - target_compile_definitions(vulkan INTERFACE VK_USE_PLATFORM_XCB_KHR) + target_compile_definitions(Vulkan-Headers INTERFACE VK_USE_PLATFORM_XCB_KHR) endif() elseif (VKB_WSI_SELECTION STREQUAL XLIB) pkg_check_modules(X11 x11 REQUIRED) if (X11_FOUND) - target_compile_definitions(vulkan INTERFACE VK_USE_PLATFORM_XLIB_KHR) + target_compile_definitions(Vulkan-Headers INTERFACE VK_USE_PLATFORM_XLIB_KHR) endif() elseif (VKB_WSI_SELECTION STREQUAL WAYLAND) pkg_check_modules(WAYLAND wayland-client REQUIRED) if (WAYLAND_FOUND) - target_compile_definitions(vulkan INTERFACE VK_USE_PLATFORM_WAYLAND_KHR) + target_compile_definitions(Vulkan-Headers INTERFACE VK_USE_PLATFORM_WAYLAND_KHR) endif() elseif (VKB_WSI_SELECTION STREQUAL D2D) set(DIRECT_TO_DISPLAY TRUE) set(DIRECT_TO_DISPLAY TRUE PARENT_SCOPE) - target_compile_definitions(vulkan INTERFACE VK_USE_PLATFORM_DISPLAY_KHR) + target_compile_definitions(Vulkan-Headers INTERFACE VK_USE_PLATFORM_DISPLAY_KHR) else() message(FATAL_ERROR "Unknown WSI") endif() endif() # vma -add_library(vma INTERFACE) -set(VMA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vma/src) -target_sources(vma INTERFACE ${VMA_DIR}/vk_mem_alloc.h) -target_include_directories(vma INTERFACE ${VMA_DIR}) -target_link_libraries(vma INTERFACE vulkan) +add_subdirectory(vma) # libktx set(KTX_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ktx) @@ -175,7 +168,7 @@ target_compile_definitions(ktx PUBLIC BASISU_NO_ITERATOR_DEBUG_LEVEL) target_include_directories(ktx PUBLIC ${KTX_INCLUDE_DIRS}) -target_link_libraries(ktx PUBLIC vulkan) +target_link_libraries(ktx PUBLIC Vulkan-Headers) set_target_properties(ktx PROPERTIES FOLDER "ThirdParty" POSITION_INDEPENDENT_CODE ON) @@ -188,7 +181,7 @@ set(VOLK_FILES add_library(volk STATIC ${VOLK_FILES}) set_target_properties(volk PROPERTIES POSITION_INDEPENDENT_CODE ON) -target_link_libraries(volk PUBLIC vulkan) +target_link_libraries(volk PUBLIC Vulkan-Headers) target_include_directories(volk PUBLIC ${VOLK_DIR}) if (VKB_WSI_SELECTION STREQUAL XCB) @@ -368,3 +361,8 @@ target_include_directories(opencl INTERFACE ${OPENCL_INCLUDE_DIR}) add_subdirectory(catch2) set_property(TARGET Catch2 PROPERTY FOLDER "ThirdParty") set_property(TARGET Catch2WithMain PROPERTY FOLDER "ThirdParty") + +# Tracy +set(TRACY_TIMER_FALLBACK ON) +add_subdirectory(tracy) +set_property(TARGET TracyClient PROPERTY FOLDER "ThirdParty") \ No newline at end of file diff --git a/third_party/tracy b/third_party/tracy new file mode 160000 index 0000000000..37aff70dfa --- /dev/null +++ b/third_party/tracy @@ -0,0 +1 @@ +Subproject commit 37aff70dfa50cf6307b3fee6074d627dc2929143 diff --git a/third_party/vma b/third_party/vma index f9921aefdd..33067f6b4f 160000 --- a/third_party/vma +++ b/third_party/vma @@ -1 +1 @@ -Subproject commit f9921aefddee2437cc2e3303d3175bd8ef23e22c +Subproject commit 33067f6b4f735db97c97660e46620266eebcf7de