Skip to content

Commit

Permalink
shader_debugprintf: support new VVL-DEBUG-PRINTF message and fix VVL …
Browse files Browse the repository at this point in the history
…version check for API selection (#1187)

* shader_debugprintf: support new VVL-DEBUG-PRINTF message and fix VVL version check for API selection

* Incorporate review feedback: update comments and simpify code

* Add VK_EXT_validation_features and move VK_EXT_layer_settings extensions to ShaderDebugPrintf::create_instance()

* Fix VK_EXT_layer_settings string comparison in [HPP]Instance::[HPP]Instance()

* When VK_EXT_layer_settings extension is available don't enable it during instance creation

* Check for VK_EXT_layer_settings available vs. enabled in [HPP]Instance::[HPP]Instance()

* Use vk::ExtensionProperties vs. VkExtensionProperties in HPPInstance::HPPInstance()

* Update comments and explicitly request required GPU features for debugPrintfEXT

(cherry picked from commit 3365c7d974ae1cb7222cf35fdbe82accfa3fd926)

* Check for defined layer settings before chaining-in layerSettingsCreateInfo in [HPP]Instance::[HPP]Instance()

* Check VVL instance extensions for VK_EXT_layer_settings and use #define for VVL layer name

* Check for required GPU features otherwise throw exception with error message

* Update copyright year for all affected files

* Review: Remove shaderInt64 feature request, Use %v3f shader print format

* Fix copyright dates in updated shaders

* Update hwcpipe submodule to match main branch
  • Loading branch information
SRSaunders authored Feb 25, 2025
1 parent aaccd0c commit 43c23e5
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 63 deletions.
4 changes: 2 additions & 2 deletions framework/core/hpp_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,8 @@ HPPInstance::HPPInstance(const std::string &applicati

vk::LayerSettingsCreateInfoEXT layerSettingsCreateInfo;

// If layer settings extension enabled by sample, then activate layer settings during instance creation
if (std::find(enabled_extensions.begin(), enabled_extensions.end(), VK_EXT_LAYER_SETTINGS_EXTENSION_NAME) != enabled_extensions.end())
// If layer settings are defined, then activate the sample's required layer settings during instance creation
if (required_layer_settings.size() > 0)
{
layerSettingsCreateInfo.settingCount = static_cast<uint32_t>(required_layer_settings.size());
layerSettingsCreateInfo.pSettings = required_layer_settings.data();
Expand Down
4 changes: 2 additions & 2 deletions framework/core/instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,8 @@ Instance::Instance(const std::string &application_nam

VkLayerSettingsCreateInfoEXT layerSettingsCreateInfo{VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT};

// If layer settings extension enabled by sample, then activate layer settings during instance creation
if (std::find(enabled_extensions.begin(), enabled_extensions.end(), VK_EXT_LAYER_SETTINGS_EXTENSION_NAME) != enabled_extensions.end())
// If layer settings are defined, then activate the sample's required layer settings during instance creation
if (required_layer_settings.size() > 0)
{
layerSettingsCreateInfo.settingCount = static_cast<uint32_t>(required_layer_settings.size());
layerSettingsCreateInfo.pSettings = required_layer_settings.data();
Expand Down
127 changes: 87 additions & 40 deletions samples/extensions/shader_debugprintf/shader_debugprintf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include "scene_graph/components/sub_mesh.h"

#define validation_layer_name "VK_LAYER_KHRONOS_validation"

std::string ShaderDebugPrintf::debug_output{};

VKAPI_ATTR VkBool32 VKAPI_CALL ShaderDebugPrintf::debug_utils_message_callback(
Expand All @@ -28,11 +30,11 @@ VKAPI_ATTR VkBool32 VKAPI_CALL ShaderDebugPrintf::debug_utils_message_callback(
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
void *pUserData)
{
// Look for Validation Layer message id names: WARNING-DEBUG-PRINTF or UNASSIGNED-DEBUG-PRINTF (have observed UNASSIGNED with older Vulkan SDKs)
if (strcmp(pCallbackData->pMessageIdName, "WARNING-DEBUG-PRINTF") == 0 || strcmp(pCallbackData->pMessageIdName, "UNASSIGNED-DEBUG-PRINTF") == 0)
// Look for Validation Layer message id names: VVL-DEBUG-PRINTF or WARNING-DEBUG-PRINTF or UNASSIGNED-DEBUG-PRINTF (have observed WARNING and UNASSIGNED with older Vulkan SDKs)
if (strcmp(pCallbackData->pMessageIdName, "VVL-DEBUG-PRINTF") == 0 || strcmp(pCallbackData->pMessageIdName, "WARNING-DEBUG-PRINTF") == 0 || strcmp(pCallbackData->pMessageIdName, "UNASSIGNED-DEBUG-PRINTF") == 0)
{
// Validation messages are a bit verbose, but we only want the text from the shader, so we cut off everything before the first word from the shader message
// See scene.vert: debugPrintfEXT("Position = %v4f", outPos);
// See scene.vert: debugPrintfEXT("Position = %v3f", outPos);
std::string shader_message{pCallbackData->pMessage};
shader_message = shader_message.substr(shader_message.find("Position"));
debug_output.append(shader_message + "\n");
Expand All @@ -46,22 +48,7 @@ ShaderDebugPrintf::ShaderDebugPrintf()

add_device_extension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME);

// If layer settings available, use it to configure validation layer for debugPrintfEXT
add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional*/ true);

add_instance_layer("VK_LAYER_KHRONOS_shader_object");

VkLayerSettingEXT layerSetting;
layerSetting.pLayerName = "VK_LAYER_KHRONOS_validation";
layerSetting.pSettingName = "enables";
layerSetting.type = VK_LAYER_SETTING_TYPE_STRING_EXT;
layerSetting.valueCount = 1;

// Make this static so layer setting reference remains valid after leaving constructor scope
static const char *layerEnables = "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT";
layerSetting.pValues = &layerEnables;

add_layer_setting(layerSetting);
add_instance_layer(validation_layer_name);
}

ShaderDebugPrintf::~ShaderDebugPrintf()
Expand All @@ -86,10 +73,24 @@ ShaderDebugPrintf::~ShaderDebugPrintf()

void ShaderDebugPrintf::request_gpu_features(vkb::PhysicalDevice &gpu)
{
auto const &supportedFeatures = gpu.get_features();
auto &requestedFeatures = gpu.get_mutable_requested_features();

// debugPrintfEXT requires fragmentStoresAndAtomics and vertexPipelineStoresAndAtomics
if (supportedFeatures.fragmentStoresAndAtomics && supportedFeatures.vertexPipelineStoresAndAtomics)
{
requestedFeatures.fragmentStoresAndAtomics = VK_TRUE;
requestedFeatures.vertexPipelineStoresAndAtomics = VK_TRUE;
}
else
{
throw vkb::VulkanException(VK_ERROR_FEATURE_NOT_PRESENT, "Selected GPU does not support features fragmentStoresAndAtomics and/or vertexPipelineStoresAndAtomics");
}

// Enable anisotropic filtering if supported
if (gpu.get_features().samplerAnisotropy)
if (supportedFeatures.samplerAnisotropy)
{
gpu.get_mutable_requested_features().samplerAnisotropy = VK_TRUE;
requestedFeatures.samplerAnisotropy = VK_TRUE;
}
}

Expand Down Expand Up @@ -422,29 +423,64 @@ bool ShaderDebugPrintf::prepare(const vkb::ApplicationOptions &options)
// This sample overrides the instance creation part of the framework to chain in additional structures
std::unique_ptr<vkb::Instance> ShaderDebugPrintf::create_instance()
{
uint32_t instanceApiVersion;
VK_CHECK(vkEnumerateInstanceVersion(&instanceApiVersion));
auto debugprintf_api_version = VK_API_VERSION_1_1;

uint32_t instance_extension_count;
VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr));
std::vector<VkExtensionProperties> available_instance_extensions(instance_extension_count);
VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, available_instance_extensions.data()));
// Enumerate all instance layer properties so we can find and use the validation layer (VVL) version in subsequent steps
// The VVL version is needed to work around validation layer performance issues when running with Vulkan SDKs <= 1.3.290
uint32_t layer_property_count;
VK_CHECK(vkEnumerateInstanceLayerProperties(&layer_property_count, nullptr));
std::vector<VkLayerProperties> layer_properties(layer_property_count);
VK_CHECK(vkEnumerateInstanceLayerProperties(&layer_property_count, layer_properties.data()));

// When VK_EXT_layer_settings is available at runtime, the debugPrintfEXT layer feature is enabled using the standard framework
// For backwards compatibility with SDKs < 1.3.272 without VK_EXT_layer_settings, the remainder of this custom override is required
if (std::any_of(available_instance_extensions.begin(),
available_instance_extensions.end(),
[](VkExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_EXT_LAYER_SETTINGS_EXTENSION_NAME) == 0; }))
const auto vvl_properties = std::find_if(layer_properties.begin(),
layer_properties.end(),
[](VkLayerProperties const &properties) { return strcmp(properties.layerName, validation_layer_name) == 0; });

// Make sure we have found the validation layer before checking the VVL version and enumerating VVL instance extensions for VK_EXT_layer_settings
if (vvl_properties != layer_properties.end())
{
// debugPrintfEXT layer feature requires Vulkan API 1.1, but use API 1.2 until VVL performance fix is available in SDKs > 1.3.290
// See VVL issue https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7562 for defect and fix information
set_api_version(instanceApiVersion <= VK_MAKE_API_VERSION(0, 1, 3, 290) ? VK_API_VERSION_1_2 : VK_API_VERSION_1_1);
// debugPrintfEXT layer feature requires Vulkan API 1.1, but override with API 1.2 for Vulkan SDKs <= 1.3.290 to work around VVL performance defect
// See VVL issue https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7562 for defect and fix information (fix available in SDK 1.3.296)
// Note: An additional, unrelated VVL performance issue affecting nVidia GPUs was found in SDK 1.3.296 following release - for nVidia GPUs please
// use SDK 1.3.290 until a fix is made available in a later SDK (see https://github.com/KhronosGroup/Vulkan-ValidationLayers/pull/8766).
if (vvl_properties->specVersion <= VK_MAKE_API_VERSION(0, 1, 3, 290))
{
debugprintf_api_version = VK_API_VERSION_1_2;
}

// Enumerate all instance extensions for the validation layer to determine if VK_EXT_layer_settings is supported by the layer
uint32_t vvl_extension_count;
VK_CHECK(vkEnumerateInstanceExtensionProperties(validation_layer_name, &vvl_extension_count, nullptr));
std::vector<VkExtensionProperties> vvl_instance_extensions(vvl_extension_count);
VK_CHECK(vkEnumerateInstanceExtensionProperties(validation_layer_name, &vvl_extension_count, vvl_instance_extensions.data()));

// When VK_EXT_layer_settings is available at runtime, the debugPrintfEXT layer feature is enabled using the standard framework
// For this case set Vulkan API version and return via base class, otherwise the remainder of this custom override is required
if (std::any_of(vvl_instance_extensions.begin(),
vvl_instance_extensions.end(),
[](VkExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_EXT_LAYER_SETTINGS_EXTENSION_NAME) == 0; }))
{
set_api_version(debugprintf_api_version);

// Since layer settings extension is available, use it to configure validation layer for debugPrintfEXT
VkLayerSettingEXT layerSetting;
layerSetting.pLayerName = validation_layer_name;
layerSetting.pSettingName = "enables";
layerSetting.type = VK_LAYER_SETTING_TYPE_STRING_EXT;
layerSetting.valueCount = 1;

// Run standard create_instance() from framework (with set_api_version and layer settings support) and return
return VulkanSample::create_instance();
// Make this static so layer setting reference remains valid after leaving the current scope
static const char *layerEnables = "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT";
layerSetting.pValues = &layerEnables;

add_layer_setting(layerSetting);

// Run standard create_instance() from framework with set_api_version() and add_layer_setting() support
return VulkanSample::create_instance();
}
}

// Run remainder of this custom create_instance() (without layer settings support) and return
// As a fallack, run remainder of this custom create_instance() override (without layer settings support) and return
std::vector<const char *> enabled_extensions;
enabled_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);

Expand All @@ -455,7 +491,15 @@ std::unique_ptr<vkb::Instance> ShaderDebugPrintf::create_instance()

enabled_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
enabled_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);

#if (defined(VKB_ENABLE_PORTABILITY))
// Enumerate all instance extensions for the loader + driver to determine if VK_KHR_portability_enumeration is available
uint32_t available_extension_count;
VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &available_extension_count, nullptr));
std::vector<VkExtensionProperties> available_instance_extensions(available_extension_count);
VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &available_extension_count, available_instance_extensions.data()));

// If VK_KHR_portability_enumeration is available in the portability implementation, then we must enable the extension
bool portability_enumeration_available = false;
if (std::any_of(available_instance_extensions.begin(),
available_instance_extensions.end(),
Expand All @@ -469,7 +513,10 @@ std::unique_ptr<vkb::Instance> ShaderDebugPrintf::create_instance()
VkApplicationInfo app_info{VK_STRUCTURE_TYPE_APPLICATION_INFO};
app_info.pApplicationName = "Shader debugprintf";
app_info.pEngineName = "Vulkan Samples";
app_info.apiVersion = instanceApiVersion <= VK_MAKE_API_VERSION(0, 1, 3, 290) ? VK_API_VERSION_1_2 : VK_API_VERSION_1_1;
app_info.apiVersion = debugprintf_api_version;

// Enable VK_EXT_validation_features extension for configuring validation layer features using VkValidationFeaturesEXT
enabled_extensions.push_back(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME);

// Shader printf is a feature of the validation layers that needs to be enabled
std::vector<VkValidationFeatureEnableEXT> validation_feature_enables = {VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT};
Expand All @@ -478,7 +525,7 @@ std::unique_ptr<vkb::Instance> ShaderDebugPrintf::create_instance()
validation_features.enabledValidationFeatureCount = static_cast<uint32_t>(validation_feature_enables.size());
validation_features.pEnabledValidationFeatures = validation_feature_enables.data();

std::vector<const char *> validation_layers = {"VK_LAYER_KHRONOS_validation"};
std::vector<const char *> validation_layers = {validation_layer_name};

VkInstanceCreateInfo instance_create_info{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO};
instance_create_info.ppEnabledExtensionNames = enabled_extensions.data();
Expand Down
30 changes: 15 additions & 15 deletions samples/extensions/shader_debugprintf/shader_debugprintf.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,21 @@ class ShaderDebugPrintf : public ApiVulkanSample

ShaderDebugPrintf();
~ShaderDebugPrintf();
virtual void request_gpu_features(vkb::PhysicalDevice &gpu) override;
void build_command_buffers() override;
void load_assets();
void setup_descriptor_pool();
void setup_descriptor_set_layout();
void setup_descriptor_sets();
void prepare_pipelines();
void prepare_uniform_buffers();
void update_uniform_buffers();
void draw();
bool prepare(const vkb::ApplicationOptions &options) override;
std::unique_ptr<vkb::Instance> create_instance() override;
virtual void render(float delta_time) override;
virtual void on_update_ui_overlay(vkb::Drawer &drawer) override;
virtual bool resize(const uint32_t width, const uint32_t height) override;
virtual void request_gpu_features(vkb::PhysicalDevice &gpu) override;
void build_command_buffers() override;
void load_assets();
void setup_descriptor_pool();
void setup_descriptor_set_layout();
void setup_descriptor_sets();
void prepare_pipelines();
void prepare_uniform_buffers();
void update_uniform_buffers();
void draw();
bool prepare(const vkb::ApplicationOptions &options) override;
std::unique_ptr<vkb::Instance> create_instance() override;
virtual void render(float delta_time) override;
virtual void on_update_ui_overlay(vkb::Drawer &drawer) override;
virtual bool resize(const uint32_t width, const uint32_t height) override;
};

std::unique_ptr<vkb::Application> create_shader_debugprintf();
4 changes: 2 additions & 2 deletions shaders/shader_debugprintf/glsl/scene.vert
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#version 450
/* Copyright (c) 2024, Sascha Willems
/* Copyright (c) 2024-2025, Sascha Willems
*
* SPDX-License-Identifier: Apache-2.0
*
Expand Down Expand Up @@ -63,6 +63,6 @@ void main()

// Output the vertex position using debug printf
if (gl_VertexIndex == 0) {
debugPrintfEXT("Position = %v4f", outPos);
debugPrintfEXT("Position = %v3f", outPos);
}
}
4 changes: 2 additions & 2 deletions shaders/shader_debugprintf/hlsl/scene.vert.hlsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (c) 2024, Sascha Willems
/* Copyright (c) 2024-2025, Sascha Willems
*
* SPDX-License-Identifier: Apache-2.0
*
Expand Down Expand Up @@ -75,7 +75,7 @@ VSOutput main(VSInput input)

// Output the vertex position using debug printf
if (input.VertexIndex == 0) {
printf("Position = %v4f", output.Pos);
printf("Position = %v3f", output.Pos);
}

return output;
Expand Down

0 comments on commit 43c23e5

Please sign in to comment.