Skip to content
Draft
6 changes: 3 additions & 3 deletions bldsys/cmake/template/sample/sample.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#include "platform/filesystem.h"
#include "platform/platform.h"
#include "rendering/subpasses/forward_subpass.h"
#include "stats.h"
#include "stats/stats.h"

@SAMPLE_NAME@::@SAMPLE_NAME@()
{
Expand Down Expand Up @@ -52,8 +52,8 @@ bool @SAMPLE_NAME@::prepare(vkb::Platform &platform)
set_render_pipeline(std::move(render_pipeline));

// Add a GUI with the stats you want to monitor
stats = std::make_unique<vkb::Stats>(std::set<vkb::StatIndex>{vkb::StatIndex::frame_times});
gui = std::make_unique<vkb::Gui>(*this, platform.get_window());
stats->request_stats({/*stats you require*/});
gui = std::make_unique<vkb::Gui>(*this, platform.get_window(), stats.get());

return true;
}
Expand Down
24 changes: 21 additions & 3 deletions framework/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ project(framework LANGUAGES C CXX)
set(FRAMEWORK_FILES
# Header Files
gui.h
stats.h
glsl_compiler.h
spirv_reflection.h
gltf_loader.h
Expand All @@ -41,7 +40,6 @@ set(FRAMEWORK_FILES
camera.h
# Source Files
gui.cpp
stats.cpp
glsl_compiler.cpp
spirv_reflection.cpp
gltf_loader.cpp
Expand Down Expand Up @@ -164,6 +162,22 @@ set(SCENE_GRAPH_SCRIPTS_FILES
scene_graph/scripts/free_camera.cpp
scene_graph/scripts/node_animation.cpp)

set(STATS_FILES
# Header Files
stats/stats.h
stats/stats_common.h
stats/stats_provider.h
stats/frame_time_stats_provider.h
stats/hwcpipe_stats_provider.h
stats/vulkan_stats_provider.h

# Source Files
stats/stats.cpp
stats/stats_provider.cpp
stats/frame_time_stats_provider.cpp
stats/hwcpipe_stats_provider.cpp
stats/vulkan_stats_provider.cpp)

set(CORE_FILES
# Header Files
core/instance.h
Expand All @@ -186,6 +200,7 @@ set(CORE_FILES
core/sampler.h
core/framebuffer.h
core/render_pass.h
core/query_pool.h
# Source Files
core/instance.cpp
core/physical_device.cpp
Expand All @@ -207,7 +222,8 @@ set(CORE_FILES
core/instance.cpp
core/sampler.cpp
core/framebuffer.cpp
core/render_pass.cpp)
core/render_pass.cpp
core/query_pool.cpp)

set(PLATFORM_FILES
# Header Files
Expand Down Expand Up @@ -292,6 +308,7 @@ source_group("rendering\\subpasses" FILES ${RENDERING_SUBPASSES_FILES})
source_group("scene_graph\\" FILES ${SCENE_GRAPH_FILES})
source_group("scene_graph\\components\\" FILES ${SCENE_GRAPH_COMPONENT_FILES})
source_group("scene_graph\\scripts\\" FILES ${SCENE_GRAPH_SCRIPTS_FILES})
source_group("stats\\" FILES ${STATS_FILES})
source_group("graphing\\" FILES ${GRAPHING_FILES})

set(PROJECT_FILES
Expand All @@ -305,6 +322,7 @@ set(PROJECT_FILES
${SCENE_GRAPH_FILES}
${SCENE_GRAPH_COMPONENT_FILES}
${SCENE_GRAPH_SCRIPTS_FILES}
${STATS_FILES}
${GRAPHING_FILES})

# Add files based on platform
Expand Down
2 changes: 1 addition & 1 deletion framework/api_vulkan_sample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ bool ApiVulkanSample::prepare(vkb::Platform &platform)
width = get_render_context().get_surface_extent().width;
height = get_render_context().get_surface_extent().height;

gui = std::make_unique<vkb::Gui>(*this, platform.get_window(), 15.0f, true);
gui = std::make_unique<vkb::Gui>(*this, platform.get_window(), /*stats=*/nullptr, 15.0f, true);
gui->prepare(pipeline_cache, render_pass,
{load_shader("uioverlay/uioverlay.vert", VK_SHADER_STAGE_VERTEX_BIT),
load_shader("uioverlay/uioverlay.frag", VK_SHADER_STAGE_FRAGMENT_BIT)});
Expand Down
21 changes: 21 additions & 0 deletions framework/core/command_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,27 @@ const bool CommandBuffer::is_render_size_optimal(const VkExtent2D &framebuffer_e
((render_area.extent.height % render_area_granularity.height == 0) || (render_area.offset.y + render_area.extent.height == framebuffer_extent.height)));
}

void CommandBuffer::reset_query_pool(const QueryPool &query_pool, uint32_t first_query, uint32_t query_count)
{
vkCmdResetQueryPool(get_handle(), query_pool.get_handle(), first_query, query_count);
}

void CommandBuffer::begin_query(const QueryPool &query_pool, uint32_t query, VkQueryControlFlags flags)
{
vkCmdBeginQuery(get_handle(), query_pool.get_handle(), query, flags);
}

void CommandBuffer::end_query(const QueryPool &query_pool, uint32_t query)
{
vkCmdEndQuery(get_handle(), query_pool.get_handle(), query);
}

void CommandBuffer::write_timestamp(VkPipelineStageFlagBits pipeline_stage,
const QueryPool &query_pool, uint32_t query)
{
vkCmdWriteTimestamp(get_handle(), pipeline_stage, query_pool.get_handle(), query);
}

VkResult CommandBuffer::reset(ResetMode reset_mode)
{
VkResult result = VK_SUCCESS;
Expand Down
9 changes: 9 additions & 0 deletions framework/core/command_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "core/buffer.h"
#include "core/image.h"
#include "core/image_view.h"
#include "core/query_pool.h"
#include "core/sampler.h"
#include "rendering/pipeline_state.h"
#include "rendering/render_target.h"
Expand Down Expand Up @@ -219,6 +220,14 @@ class CommandBuffer

void set_update_after_bind(bool update_after_bind_);

void reset_query_pool(const QueryPool &query_pool, uint32_t first_query, uint32_t query_count);

void begin_query(const QueryPool &query_pool, uint32_t query, VkQueryControlFlags flags);

void end_query(const QueryPool &query_pool, uint32_t query);

void write_timestamp(VkPipelineStageFlagBits pipeline_stage, const QueryPool &query_pool, uint32_t query);

/**
* @brief Reset the command buffer to a state where it can be recorded to
* @param reset_mode How to reset the buffer, should match the one used by the pool to allocate it
Expand Down
39 changes: 33 additions & 6 deletions framework/core/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ VKBP_ENABLE_WARNINGS()

namespace vkb
{
Device::Device(const PhysicalDevice &gpu, VkSurfaceKHR surface, std::unordered_map<const char *, bool> requested_extensions) :
Device::Device(PhysicalDevice &gpu, VkSurfaceKHR surface, std::unordered_map<const char *, bool> requested_extensions) :
gpu{gpu},
resource_cache{*this}
{
Expand Down Expand Up @@ -68,13 +68,39 @@ Device::Device(const PhysicalDevice &gpu, VkSurfaceKHR surface, std::unordered_m
bool can_get_memory_requirements = is_extension_supported("VK_KHR_get_memory_requirements2");
bool has_dedicated_allocation = is_extension_supported("VK_KHR_dedicated_allocation");

// For performance queries, we also use host query reset since queryPool resets cannot
// live in the same command buffer as beginQuery
bool has_performance_query = is_extension_supported("VK_KHR_performance_query") &&
is_extension_supported("VK_EXT_host_query_reset");

if (can_get_memory_requirements && has_dedicated_allocation)
{
enabled_extensions.push_back("VK_KHR_get_memory_requirements2");
enabled_extensions.push_back("VK_KHR_dedicated_allocation");

LOGI("Dedicated Allocation enabled");
}

if (has_performance_query)
{
gpu.request_performance_counter_features();
gpu.request_host_query_reset_features();

auto perf_counter_features = gpu.get_performance_counter_features();
auto host_query_reset_features = gpu.get_host_query_reset_features();

if (perf_counter_features.performanceCounterQueryPools && host_query_reset_features.hostQueryReset)
{
enabled_extensions.push_back("VK_KHR_performance_query");
enabled_extensions.push_back("VK_EXT_host_query_reset");
LOGI("Performance query enabled");
}
else
{
has_performance_query = false;
}
}

// Check that extensions are supported before trying to create the device
std::vector<const char *> unsupported_extensions{};
for (auto &extension : requested_extensions)
Expand Down Expand Up @@ -123,16 +149,17 @@ Device::Device(const PhysicalDevice &gpu, VkSurfaceKHR surface, std::unordered_m

VkDeviceCreateInfo create_info{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};

// Latest requested feature will have the pNext's all set up for device creation.
create_info.pNext = gpu.get_requested_extension_features();

create_info.pQueueCreateInfos = queue_create_infos.data();
create_info.queueCreateInfoCount = to_u32(queue_create_infos.size());
const auto requested_gpu_features = gpu.get_requested_features();
create_info.pEnabledFeatures = &requested_gpu_features;
create_info.enabledExtensionCount = to_u32(enabled_extensions.size());
create_info.ppEnabledExtensionNames = enabled_extensions.data();

const auto requested_gpu_features = gpu.get_requested_features();

// Latest requested feature will have the pNext's all set up for device creation.
create_info.pNext = gpu.get_requested_extension_features();
create_info.pEnabledFeatures = &requested_gpu_features;

VkResult result = vkCreateDevice(gpu.get_handle(), &create_info, nullptr, &handle);

if (result != VK_SUCCESS)
Expand Down
4 changes: 2 additions & 2 deletions framework/core/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ class Device
public:
/**
* @brief Device constructor
* @param gpu A valid Vulkan physical device and the requested gpu features
* @param gpu A valid Vulkan physical device and the requested gpu features
* @param surface The surface
* @param requested_extensions (Optional) List of required device extensions and whether support is optional or not
*/
Device(const PhysicalDevice &gpu, VkSurfaceKHR surface, std::unordered_map<const char *, bool> requested_extensions = {});
Device(PhysicalDevice &gpu, VkSurfaceKHR surface, std::unordered_map<const char *, bool> requested_extensions = {});

Device(const Device &) = delete;

Expand Down
11 changes: 11 additions & 0 deletions framework/core/instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,17 @@ Instance::Instance(const std::string & application_nam
enabled_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
}

for (auto &available_extension : available_instance_extensions)
{
// VK_KHR_get_physical_device_properties2 is a prerequisite of VK_KHR_performance_query
// which will be used for stats gathering where available.
if (strcmp(available_extension.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
{
LOGI("{} is available, enabling it", VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
enabled_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
}
}

auto extension_error = false;
for (auto extension : required_extensions)
{
Expand Down
54 changes: 46 additions & 8 deletions framework/core/physical_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,25 @@ const std::vector<VkQueueFamilyProperties> &PhysicalDevice::get_queue_family_pro
return queue_family_properties;
}

uint32_t PhysicalDevice::get_queue_family_performance_query_passes(
const VkQueryPoolPerformanceCreateInfoKHR *perf_query_create_info) const
{
uint32_t passes_needed;
vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR(get_handle(), perf_query_create_info,
&passes_needed);
return passes_needed;
}

void PhysicalDevice::enumerate_queue_family_performance_query_counters(
uint32_t queue_family_index,
uint32_t * count,
VkPerformanceCounterKHR * counters,
VkPerformanceCounterDescriptionKHR *descriptions) const
{
VK_CHECK(vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(
get_handle(), queue_family_index, count, counters, descriptions));
}

VkPhysicalDeviceFeatures &PhysicalDevice::get_mutable_requested_features()
{
return requested_features;
Expand All @@ -111,19 +130,38 @@ void PhysicalDevice::request_descriptor_indexing_features()
// Request the relevant extension
descriptor_indexing_features = request_extension_features<VkPhysicalDeviceDescriptorIndexingFeaturesEXT>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT);

// If an extension has already been requested, set that to the pNext element
if (last_requested_extension_feature)
{
descriptor_indexing_features.pNext = last_requested_extension_feature;
}

// Set the last requested extension to the pointer of the most recently requested extension
last_requested_extension_feature = &descriptor_indexing_features;
chain_extension_features(descriptor_indexing_features);
}

const VkPhysicalDeviceDescriptorIndexingFeaturesEXT &PhysicalDevice::get_descriptor_indexing_features() const
{
return descriptor_indexing_features;
}

void PhysicalDevice::request_performance_counter_features()
{
// Request the relevant extensions
performance_counter_features = request_extension_features<VkPhysicalDevicePerformanceQueryFeaturesKHR>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR);

chain_extension_features(performance_counter_features);
}

const VkPhysicalDevicePerformanceQueryFeaturesKHR &PhysicalDevice::get_performance_counter_features() const
{
return performance_counter_features;
}

void PhysicalDevice::request_host_query_reset_features()
{
// Request the relevant extension
host_query_reset_features = request_extension_features<VkPhysicalDeviceHostQueryResetFeatures>(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES);

chain_extension_features(host_query_reset_features);
}

const VkPhysicalDeviceHostQueryResetFeatures &PhysicalDevice::get_host_query_reset_features() const
{
return host_query_reset_features;
}

} // namespace vkb
34 changes: 34 additions & 0 deletions framework/core/physical_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ class PhysicalDevice

const std::vector<VkQueueFamilyProperties> &get_queue_family_properties() const;

uint32_t get_queue_family_performance_query_passes(
const VkQueryPoolPerformanceCreateInfoKHR *perf_query_create_info) const;

void enumerate_queue_family_performance_query_counters(
uint32_t queue_family_index,
uint32_t * count,
VkPerformanceCounterKHR * counters,
VkPerformanceCounterDescriptionKHR *descriptions) const;

VkPhysicalDeviceFeatures &get_mutable_requested_features();

const VkPhysicalDeviceFeatures get_requested_features() const;
Expand All @@ -70,6 +79,14 @@ class PhysicalDevice

const VkPhysicalDeviceDescriptorIndexingFeaturesEXT &get_descriptor_indexing_features() const;

void request_performance_counter_features();

const VkPhysicalDevicePerformanceQueryFeaturesKHR &get_performance_counter_features() const;

void request_host_query_reset_features();

const VkPhysicalDeviceHostQueryResetFeatures &get_host_query_reset_features() const;

protected:
template <typename T>
const T request_extension_features(VkStructureType type)
Expand All @@ -89,6 +106,19 @@ class PhysicalDevice
return ext;
}

template <typename T>
void chain_extension_features(T &features)
{
// If an extension has already been requested, set that to the pNext element
if (last_requested_extension_feature)
{
features.pNext = last_requested_extension_feature;
}

// Set the last requested extension to the pointer of the most recently requested extension
last_requested_extension_feature = &features;
}

private:
// Handle to the Vulkan instance
const Instance &instance;
Expand All @@ -115,5 +145,9 @@ class PhysicalDevice
void *last_requested_extension_feature{nullptr};

VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing_features{};

VkPhysicalDevicePerformanceQueryFeaturesKHR performance_counter_features{};

VkPhysicalDeviceHostQueryResetFeatures host_query_reset_features{};
};
} // namespace vkb
Loading