blob: 251b191f7e05db00df0b1fe5714d38f8e2c651fd [file]
/* Copyright (c) 2026 The Khronos Group Inc.
* Copyright (c) 2026 Valve Corporation
* Copyright (c) 2026 LunarG, Inc.
*
* 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 <vulkan/vulkan_core.h>
#include <filesystem>
#include <fstream>
#include "layer_validation_tests.h"
#include "pipeline_helper.h"
#include "descriptor_helper.h"
#include "ray_tracing_objects.h"
#include "shader_object_helper.h"
#include "shader_templates.h"
// stype-check off
static const VkValidationFeatureEnableEXT kValEnabled = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT;
static const VkValidationFeaturesEXT kValFeature = {VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, NULL, 1, &kValEnabled, 0, nullptr};
// stype-check on
class NegativeGpuAVScoped : public GpuAVTest {};
TEST_F(NegativeGpuAVScoped, SelectInstrumentedShaders) {
TEST_DESCRIPTION("GPU validation: Validate selection of which shaders get instrumented for GPU-AV");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
std::vector<VkLayerSettingEXT> layer_settings = {
{OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
vkt::Buffer write_buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, write_buffer, 0, 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char vertshader[] = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data;
void main() {
Data.data[4] = 0xdeadca71;
}
)glsl";
VkShaderObj vs(*m_device, vertshader, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr, "main",
&kValFeature);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[0] = vs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-storageBuffers-06936", 3);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, SelectInstrumentedShadersComputePipeline) {
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance5);
std::vector<VkLayerSettingEXT> layer_settings = {
{OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
vkt::Buffer write_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, write_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char* cs_source = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; };
void main() {
data[64] = 0;
}
)glsl";
VkShaderObj cs(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT);
CreateComputePipelineHelper pipe(*this);
pipe.cp_ci_.stage = cs.GetStageCreateInfo();
// On VkPipelineShaderStageCreateInfo
pipe.cp_ci_.stage.pNext = &kValFeature;
pipe.cp_ci_.layout = pipeline_layout;
pipe.CreateComputePipeline(false);
CreateComputePipelineHelper pipe2(*this);
pipe2.cp_ci_.stage = cs.GetStageCreateInfo();
// On VkComputePipelineCreateInfo
pipe2.cp_ci_.pNext = &kValFeature;
pipe2.cp_ci_.layout = pipeline_layout;
pipe2.CreateComputePipeline(false);
// On Inlined on the VkShaderModuleCreateInfo
std::vector<uint32_t> cs_spirv = GLSLToSPV(VK_SHADER_STAGE_COMPUTE_BIT, cs_source);
VkShaderModuleCreateInfo module_create_info = vku::InitStructHelper((void*)&kValFeature);
module_create_info.pCode = cs_spirv.data();
module_create_info.codeSize = cs_spirv.size() * sizeof(uint32_t);
VkPipelineShaderStageCreateInfo stage_ci = vku::InitStructHelper(&module_create_info);
stage_ci.stage = VK_SHADER_STAGE_COMPUTE_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
CreateComputePipelineHelper pipe3(*this);
pipe3.cp_ci_.stage = stage_ci;
pipe3.cp_ci_.layout = pipeline_layout;
pipe3.CreateComputePipeline(false);
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe2);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe3);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDispatch-storageBuffers-06936", 3); // one for each pipeline
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, SelectInstrumentedShadersGraphicsPipeline) {
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance5);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
std::vector<VkLayerSettingEXT> layer_settings = {
{OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
vkt::Buffer write_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, write_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char* vs_source = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; };
void main() {
if (gl_VertexIndex == 0) {
data[64] = 0;
}
}
)glsl";
VkShaderObj vs(*m_device, vs_source, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, kMinimalShaderGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineShaderStageCreateInfo stages_ci[2]{vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.layout = pipeline_layout;
pipe.gp_ci_.stageCount = 2;
pipe.gp_ci_.pStages = stages_ci;
// On VkPipelineShaderStageCreateInfo
stages_ci[0].pNext = &kValFeature;
pipe.CreateGraphicsPipeline(false);
stages_ci[0].pNext = nullptr;
// On VkGraphicsPipelineCreateInfo
CreatePipelineHelper pipe2(*this);
pipe2.gp_ci_.layout = pipeline_layout;
pipe2.gp_ci_.stageCount = 2;
pipe2.gp_ci_.pStages = stages_ci;
pipe2.gp_ci_.pNext = &kValFeature;
pipe2.CreateGraphicsPipeline(false);
// On Inlined on the VkShaderModuleCreateInfo
std::vector<uint32_t> vs_spirv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_source);
VkShaderModuleCreateInfo module_create_info = vku::InitStructHelper((void*)&kValFeature);
module_create_info.pCode = vs_spirv.data();
module_create_info.codeSize = vs_spirv.size() * sizeof(uint32_t);
stages_ci[0] = vku::InitStructHelper(&module_create_info);
stages_ci[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
stages_ci[0].module = VK_NULL_HANDLE;
stages_ci[0].pName = "main";
CreatePipelineHelper pipe3(*this);
pipe3.gp_ci_.layout = pipeline_layout;
pipe3.gp_ci_.stageCount = 2;
pipe3.gp_ci_.pStages = stages_ci;
pipe3.CreateGraphicsPipeline(false);
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe3);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-storageBuffers-06936", 3); // one for each pipeline
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, SelectInstrumentedShadersRegex) {
TEST_DESCRIPTION(
"Selectively instrument shaders for validation, using regexes: all shaders matching regexes must be instrumented. Here it "
"means they should emit errors");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
std::vector<VkLayerSettingEXT> layer_settings(2);
layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
std::array<const char*, 2> shader_regexes = {{"vertex_foo", "fragment_.*"}};
layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
shader_regexes.data()};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
vkt::Buffer write_buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, write_buffer, 0, 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char vertshader[] = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data;
void main() {
Data.data[4] = 0xdeadca71;
}
)glsl";
VkShaderObj vs(*m_device, vertshader, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr, "main");
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr,
"main");
VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
name_info.objectType = VK_OBJECT_TYPE_SHADER_MODULE;
name_info.pObjectName = "vertex_foo";
name_info.objectHandle = uint64_t(vs.handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
name_info.pObjectName = "fragment_bar";
name_info.objectHandle = uint64_t(fs.handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredInfo("vertex_foo");
m_errorMonitor->SetDesiredInfo("fragment_bar");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-storageBuffers-06936", 3);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, SelectInstrumentedComputePipelineRegex) {
TEST_DESCRIPTION("Selectively instrument a compute pipeline for validation, using regexes");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
std::vector<VkLayerSettingEXT> layer_settings(2);
layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
std::array<const char*, 1> shader_regexes = {{"pipeline_foo"}};
layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
shader_regexes.data()};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
vkt::Buffer write_buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, write_buffer, 0, 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char cs_source[] = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data;
void main() {
Data.data[4] = 0xdeadca71;
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr, "main");
pipe.cp_ci_.layout = pipeline_layout;
pipe.CreateComputePipeline();
VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
name_info.objectType = VK_OBJECT_TYPE_PIPELINE;
name_info.pObjectName = "pipeline_foo";
name_info.objectHandle = uint64_t(pipe.Handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDispatch-storageBuffers-06936", "pipeline_foo");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, SelectInstrumentedComputePipelineCDLDump) {
TEST_DESCRIPTION("Selectively instrument a compute pipeline for validation, using a CDL dump file as input");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
const char* cdl_dump_content = R"(
# ----------------------------------------------------------------
# - CRASH DIAGNOSTIC LAYER -
# ----------------------------------------------------------------
version: 1.4.350
startTime: 2026-07-06 18:02:38
timeSinceStart: 00:00:00.265
Settings:
output_path: cdl_test_output\GpuCrash\InfiniteLoopSubmit2
trace_on: false
dump_queue_submits: running
dump_command_buffers: running
dump_commands: running
dump_shaders: off
trigger_watchdog_timeout: true
watchdog_timeout_ms: 30000
track_semaphores: true
trace_all_semaphores: false
instrument_all_commands: false
sync_after_commands: false
SystemInfo:
osName: Windows 10 Home
osVersion: 26200
osBitdepth: 64-bit
osAdditional:
build: ge_release
cpuName: x64
numCpus: 24
totalRam: 63 GB
totalDiskSpace: 1 TB
availDiskSpace: 91 GB
Instance:
handle: 0x000001C7C89F7E30 []
applicationInfo:
application: GpuCrash
applicationVersion: 1
engine: InfiniteLoopSubmit2
engineVersion: 1
apiVersion: 1.3.0 (0x00403000)
extensions:
- VK_EXT_debug_utils
- VK_EXT_layer_settings
Device:
handle: 0x000001C7CA5B9A30[]
deviceName: CDL Mock Device
apiVersion: 1.4.350 (0x0040415E)
driverVersion: 0x00000001 (1)
vendorID: 0xBA5EBA11
deviceID: 0x0BADC0DE
extensions:
[]
Queues:
- # Queue
handle: 0x000001C7CA5B5A40[]
queueFamilyIndex: 0
index: 0
flags:
- graphics
- compute
- transfer
- sparse
- protected
completedSeq: 1
submittedSeq: 4
IncompleteSubmits:
- type: vkQueueSubmit2
startSeq: 1
endSeq: 4
SubmitInfos:
- startSeq: 1
endSeq: 4
state: INCOMPLETE
CommandBuffers:
- 0x000001C7CA5C7D80[] INCOMPLETE 3
CommandBuffers:
- # CommandBuffer
state: INCOMPLETE
handle: 0x000001C7CA5C7D80[]
commandPool: 0x000001C7CA5F7E80[]
queue: 0x000001C7CA5B5A40[]
fence: 0x0000000000000000[]
queueSeq: 3
level: Primary
simultaneousUse: false
beginValue: 0x00000001
endValue: 0x0000FFFF
topCheckpointValue: 0x00000006
bottomCheckpointValue: 0x00000003
lastStartedCommand: 5
lastCompletedCommand: 2
Commands:
- # Command:
id: 2
checkpointValue: 0x00000003
name: vkCmdBindPipeline
state: COMPLETED
parameters:
pipelineBindPoint: VK_PIPELINE_BIND_POINT_COMPUTE
pipeline: 0x0000000000000008[my pipeline]
message: "'>>>>>>>>>>>>>> LAST COMPLETE COMMAND <<<<<<<<<<<<<<'"
- # Command:
id: 3
checkpointValue: 0x00000004
name: vkCmdBindDescriptorSets
state: INCOMPLETE
parameters:
pipelineBindPoint: VK_PIPELINE_BIND_POINT_COMPUTE
layout: 0x0000000000000007[]
firstSet: 0
descriptorSetCount: 1
pDescriptorSets: # VkDescriptorSet
- 0x0000000000000006[]
dynamicOffsetCount: 0
pDynamicOffsets: nullptr
- # Command:
id: 4
checkpointValue: 0x00000005
name: vkCmdBeginDebugUtilsLabelEXT
state: INCOMPLETE
labels:
- hang-expected
parameters:
pLabelInfo:
sType: VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT
pNext:
- nullptr
pLabelName: hang-expected
color: # float
- 0
- 0
- 0
- 0
- # Command:
id: 5
checkpointValue: 0x00000006
name: vkCmdDispatch
state: INCOMPLETE
labels:
- hang-expected
parameters:
groupCountX: 1
groupCountY: 1
groupCountZ: 1
internalState:
pipeline:
handle: 0x0000000000000008[my pipeline]
bindPoint: compute
shaderInfos:
- stage: cs
module: 0x0000000000000003[]
entry: main
descriptorSets:
- # descriptorSet
index: 0
set: 0x0000000000000006[]
message: "'^^^^^^^^^^^^^^ LAST STARTED COMMAND ^^^^^^^^^^^^^^'"
)";
const std::filesystem::path cdl_dump_path = std::filesystem::temp_directory_path() / "vvl_test_cdl_dump.yml";
struct FileGuard {
std::filesystem::path path;
~FileGuard() { std::filesystem::remove(path); }
} cdl_dump_file_guard{cdl_dump_path};
{
std::ofstream cdl_dump_file(cdl_dump_path, std::ios::out | std::ios::trunc);
ASSERT_TRUE(cdl_dump_file.is_open());
cdl_dump_file << cdl_dump_content;
}
const std::string cdl_dump_path_str = cdl_dump_path.string();
const char* cdl_dump_path_cstr = cdl_dump_path_str.c_str();
std::vector<VkLayerSettingEXT> layer_settings(2);
layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_cdl_dump_path", VK_LAYER_SETTING_TYPE_STRING_EXT, 1, &cdl_dump_path_cstr};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
vkt::Buffer write_buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, write_buffer, 0, 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char cs_source[] = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data;
void main() {
Data.data[4] = 0xdeadca71;
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr, "main");
pipe.cp_ci_.layout = pipeline_layout;
pipe.CreateComputePipeline();
VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
name_info.objectType = VK_OBJECT_TYPE_PIPELINE;
name_info.pObjectName = "my pipeline";
name_info.objectHandle = uint64_t(pipe.Handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdDispatch(m_command_buffer, 1, 1, 1);
m_command_buffer.End();
m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDispatch-storageBuffers-06936", "my pipeline");
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, SelectInstrumentedPipelineLibrariesRegex) {
TEST_DESCRIPTION(
"Use one library to link two pipelines. Destroy first one before creating second one. Second one should be instrumented.");
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
std::vector<VkLayerSettingEXT> layer_settings(2);
layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
std::array<const char*, 1> shader_regexes = {{"pipeline_foo"}};
layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
shader_regexes.data()};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
vkt::Buffer offset_buffer(*m_device, 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps);
vkt::Buffer write_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, offset_buffer, 0, VK_WHOLE_SIZE);
descriptor_set.WriteDescriptorBufferInfo(1, write_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
uint32_t* data = (uint32_t*)offset_buffer.Memory().Map();
*data = 8;
const char vertshader[] = R"glsl(
#version 450
layout(set = 0, binding = 0) uniform Foo { uint index[]; };
layout(set = 0, binding = 1) buffer StorageBuffer { uint data[]; };
void main() {
uint index = index[0];
data[index] = 0xdeadca71;
}
)glsl";
// Create VkShaderModule to pass in
VkShaderObj vs(*m_device, vertshader, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper vertex_input_lib(*this);
vertex_input_lib.InitVertexInputLibInfo();
vertex_input_lib.CreateGraphicsPipeline(false);
// For GPU-AV tests this shrinks things so only a single fragment is executed
VkViewport viewport = {0, 0, 1, 1, 0, 1};
VkRect2D scissor = {{0, 0}, {1, 1}};
CreatePipelineHelper pre_raster_lib(*this);
{
pre_raster_lib.InitPreRasterLibInfo(&vs.GetStageCreateInfo());
pre_raster_lib.vp_state_ci_.pViewports = &viewport;
pre_raster_lib.vp_state_ci_.pScissors = &scissor;
pre_raster_lib.gp_ci_.layout = pipeline_layout;
pre_raster_lib.CreateGraphicsPipeline();
}
CreatePipelineHelper frag_shader_lib(*this);
{
frag_shader_lib.InitFragmentLibInfo(&fs.GetStageCreateInfo());
frag_shader_lib.gp_ci_.layout = pipeline_layout;
frag_shader_lib.CreateGraphicsPipeline(false);
}
CreatePipelineHelper frag_out_lib(*this);
frag_out_lib.InitFragmentOutputLibInfo();
frag_out_lib.CreateGraphicsPipeline(false);
VkPipeline libraries[4] = {
vertex_input_lib,
pre_raster_lib,
frag_shader_lib,
frag_out_lib,
};
VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper();
link_info.libraryCount = size32(libraries);
link_info.pLibraries = libraries;
VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info);
exe_pipe_ci.layout = pipeline_layout;
{
vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci);
}
vkt::Pipeline exe_pipe_2(*m_device, exe_pipe_ci);
VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
name_info.objectType = VK_OBJECT_TYPE_PIPELINE;
name_info.pObjectName = "pipeline_foo";
name_info.objectHandle = uint64_t(exe_pipe_2.handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe_2);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDraw-storageBuffers-06936", "pipeline_foo", 3);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, SelectInstrumentedGraphicsPipelineRegex) {
TEST_DESCRIPTION("Selectively instrument a pipeline for validation, using regexes");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
std::vector<VkLayerSettingEXT> layer_settings(2);
layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
std::array<const char*, 1> shader_regexes = {{"pipeline_foo"}};
layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
shader_regexes.data()};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
vkt::Buffer write_buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, write_buffer, 0, 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char vertshader[] = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data;
void main() {
Data.data[4] = 0xdeadca71;
}
)glsl";
VkShaderObj vs(*m_device, vertshader, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr, "main");
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr,
"main");
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.layout = pipeline_layout;
pipe.CreateGraphicsPipeline();
VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
name_info.objectType = VK_OBJECT_TYPE_PIPELINE;
name_info.pObjectName = "pipeline_foo";
name_info.objectHandle = uint64_t(pipe.Handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredErrorRegex("VUID-vkCmdDraw-storageBuffers-06936", "pipeline_foo", 3);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, SelectInstrumentedShadersRegexDestroyedShaders) {
TEST_DESCRIPTION(
"Selectively instrument shaders for validation, using regexes: all shaders matching regexes must be instrumented. Here it "
"means they should emit errors. Shaders are destroyed after creating pipeline, it should have no impact.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
std::vector<VkLayerSettingEXT> layer_settings(2);
layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
std::array<const char*, 2> shader_regexes = {{"vertex_foo", "fragment_.*"}};
layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
shader_regexes.data()};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
vkt::Buffer write_buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, write_buffer, 0, 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
const char vertshader[] = R"glsl(
#version 450
layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data;
void main() {
Data.data[4] = 0xdeadca71;
}
)glsl";
VkShaderObj vs(*m_device, vertshader, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr, "main");
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_GLSL, nullptr,
"main");
VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
name_info.objectType = VK_OBJECT_TYPE_SHADER_MODULE;
name_info.pObjectName = "vertex_foo";
name_info.objectHandle = uint64_t(vs.handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
name_info.pObjectName = "fragment_bar";
name_info.objectHandle = uint64_t(fs.handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredInfo("vertex_foo");
m_errorMonitor->SetDesiredInfo("fragment_bar");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
vs.Destroy();
fs.Destroy();
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-storageBuffers-06936", 3);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, SelectInstrumentedShadersShaderObject) {
TEST_DESCRIPTION("GPU validation: Validate selection of which shaders get instrumented for GPU-AV");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::shaderObject);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
std::vector<VkLayerSettingEXT> layer_settings = {
{OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
InitDynamicRenderTarget();
OneOffDescriptorSet vert_descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr},
});
vkt::PipelineLayout pipeline_layout(*m_device, {&vert_descriptor_set.layout_});
const char vert_src[] = R"glsl(
#version 460
layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data;
void main() {
Data.data[4] = 0xdeadca71;
}
)glsl";
const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vert_src);
const auto frag_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl);
VkDescriptorSetLayout descriptor_set_layouts[] = {vert_descriptor_set.layout_};
VkShaderCreateInfoEXT vert_create_info = ShaderCreateInfo(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, 1, descriptor_set_layouts);
VkShaderCreateInfoEXT frag_create_info = ShaderCreateInfo(frag_spv, VK_SHADER_STAGE_FRAGMENT_BIT, 1, descriptor_set_layouts);
vert_create_info.pNext = &kValFeature;
frag_create_info.pNext = &kValFeature;
const vkt::Shader vert_shader(*m_device, vert_create_info);
const vkt::Shader frag_shader(*m_device, frag_create_info);
vkt::Buffer buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vert_descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
vert_descriptor_set.UpdateDescriptorSets();
m_command_buffer.Begin();
m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea());
SetDefaultDynamicStatesExclude();
m_command_buffer.BindShaders(vert_shader, frag_shader);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 1u, &vert_descriptor_set.set_,
0u, nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRendering();
m_command_buffer.End();
// Should get a warning since shader was instrumented
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-08613", 3);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, SelectInstrumentedShadersShaderObjectDrawIndexedIndirect2KHR) {
TEST_DESCRIPTION("GPU validation: Validate selection of which shaders get instrumented for GPU-AV");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::shaderObject);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
AddRequiredFeature(vkt::Feature::deviceAddressCommands);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
std::vector<VkLayerSettingEXT> layer_settings = {
{OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue}};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
InitDynamicRenderTarget();
OneOffDescriptorSet vert_descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr},
});
vkt::PipelineLayout pipeline_layout(*m_device, {&vert_descriptor_set.layout_});
const char vert_src[] = R"glsl(
#version 460
layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data;
void main() {
Data.data[4] = 0xdeadca71;
}
)glsl";
const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vert_src);
const auto frag_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl);
VkDescriptorSetLayout descriptor_set_layouts[] = {vert_descriptor_set.layout_};
VkShaderCreateInfoEXT vert_create_info = ShaderCreateInfo(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, 1, descriptor_set_layouts);
VkShaderCreateInfoEXT frag_create_info = ShaderCreateInfo(frag_spv, VK_SHADER_STAGE_FRAGMENT_BIT, 1, descriptor_set_layouts);
vert_create_info.pNext = &kValFeature;
frag_create_info.pNext = &kValFeature;
const vkt::Shader vert_shader(*m_device, vert_create_info);
const vkt::Shader frag_shader(*m_device, frag_create_info);
vkt::Buffer buffer(*m_device, 4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vert_descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
vert_descriptor_set.UpdateDescriptorSets();
vkt::Buffer index_buffer(*m_device, 3 * sizeof(uint32_t), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, vkt::device_address);
uint32_t* index_data = reinterpret_cast<uint32_t*>(index_buffer.Memory().Map());
index_data[0] = 0u;
index_data[1] = 1u;
index_data[2] = 2u;
vkt::Buffer indirect_buffer(*m_device, 32, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, vkt::device_address);
VkDrawIndexedIndirectCommand* draw_command = reinterpret_cast<VkDrawIndexedIndirectCommand*>(indirect_buffer.Memory().Map());
draw_command->indexCount = 3u;
draw_command->instanceCount = 1u;
draw_command->firstIndex = 0u;
draw_command->vertexOffset = 0u;
draw_command->firstInstance = 0u;
m_command_buffer.Begin();
m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea());
SetDefaultDynamicStatesExclude();
m_command_buffer.BindShaders(vert_shader, frag_shader);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 1u, &vert_descriptor_set.set_,
0u, nullptr);
VkBindIndexBuffer3InfoKHR index_buffer_info = vku::InitStructHelper();
index_buffer_info.addressRange = index_buffer.AddressRange();
index_buffer_info.addressFlags = VK_ADDRESS_COMMAND_UNKNOWN_STORAGE_BUFFER_USAGE_BIT_KHR;
index_buffer_info.indexType = VK_INDEX_TYPE_UINT32;
vk::CmdBindIndexBuffer3KHR(m_command_buffer, &index_buffer_info);
VkDrawIndirect2InfoKHR draw_indirect_info = vku::InitStructHelper();
draw_indirect_info.addressRange = indirect_buffer.StridedAddressRange();
draw_indirect_info.addressFlags = VK_ADDRESS_COMMAND_UNKNOWN_STORAGE_BUFFER_USAGE_BIT_KHR;
draw_indirect_info.drawCount = 1u;
vk::CmdDrawIndexedIndirect2KHR(m_command_buffer, &draw_indirect_info);
m_command_buffer.EndRendering();
m_command_buffer.End();
// Should get a warning since shader was instrumented
m_errorMonitor->SetDesiredError("VUID-vkCmdDrawIndexedIndirect2KHR-None-08613", 3);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, GPLWriteSelectPipeline) {
TEST_DESCRIPTION("Select shaders within pipeline libraries for instrumentation");
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
std::vector<VkLayerSettingEXT> layer_settings(2);
layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
std::array<const char*, 2> shader_regexes = {{"bim_bap_boom", ".*_my_pipeline.*"}};
layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
shader_regexes.data()};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
vkt::Buffer offset_buffer(*m_device, 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps);
vkt::Buffer write_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, offset_buffer, 0, VK_WHOLE_SIZE);
descriptor_set.WriteDescriptorBufferInfo(1, write_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
uint32_t* data = (uint32_t*)offset_buffer.Memory().Map();
*data = 8;
const char vertshader[] = R"glsl(
#version 450
layout(set = 0, binding = 0) uniform Foo { uint index[]; };
layout(set = 0, binding = 1) buffer StorageBuffer { uint data[]; };
void main() {
uint index = index[0];
data[index] = 0xdeadca71;
}
)glsl";
// Create VkShaderModule to pass in
VkShaderObj vs(*m_device, vertshader, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
name_info.objectType = VK_OBJECT_TYPE_PIPELINE;
CreatePipelineHelper vertex_input_lib(*this);
vertex_input_lib.InitVertexInputLibInfo();
vertex_input_lib.CreateGraphicsPipeline(false);
// For GPU-AV tests this shrinks things so only a single fragment is executed
VkViewport viewport = {0, 0, 1, 1, 0, 1};
VkRect2D scissor = {{0, 0}, {1, 1}};
CreatePipelineHelper pre_raster_lib(*this);
{
pre_raster_lib.InitPreRasterLibInfo(&vs.GetStageCreateInfo());
pre_raster_lib.vp_state_ci_.pViewports = &viewport;
pre_raster_lib.vp_state_ci_.pScissors = &scissor;
pre_raster_lib.gp_ci_.layout = pipeline_layout;
pre_raster_lib.CreateGraphicsPipeline();
name_info.pObjectName = "oh_my_pipeline";
name_info.objectHandle = uint64_t(pre_raster_lib.Handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
}
CreatePipelineHelper frag_shader_lib(*this);
{
frag_shader_lib.InitFragmentLibInfo(&fs.GetStageCreateInfo());
frag_shader_lib.gp_ci_.layout = pipeline_layout;
frag_shader_lib.CreateGraphicsPipeline(false);
}
CreatePipelineHelper frag_out_lib(*this);
frag_out_lib.InitFragmentOutputLibInfo();
frag_out_lib.CreateGraphicsPipeline(false);
VkPipeline libraries[4] = {
vertex_input_lib,
pre_raster_lib,
frag_shader_lib,
frag_out_lib,
};
VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper();
link_info.libraryCount = size32(libraries);
link_info.pLibraries = libraries;
VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info);
exe_pipe_ci.layout = pipeline_layout;
m_errorMonitor->SetDesiredInfo("oh_my_pipeline");
vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci);
m_errorMonitor->VerifyFound();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-storageBuffers-06936", 3);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, GPLWriteSelectShaders) {
TEST_DESCRIPTION("Select shaders within pipeline libraries for instrumentation");
AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
std::vector<VkLayerSettingEXT> layer_settings(2);
layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
std::array<const char*, 2> shader_regexes = {{"verte[xyz]_foo", ".*gment_.*"}};
layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
shader_regexes.data()};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
InitRenderTarget();
vkt::Buffer offset_buffer(*m_device, 4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps);
vkt::Buffer write_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
descriptor_set.WriteDescriptorBufferInfo(0, offset_buffer, 0, VK_WHOLE_SIZE);
descriptor_set.WriteDescriptorBufferInfo(1, write_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
descriptor_set.UpdateDescriptorSets();
uint32_t* data = (uint32_t*)offset_buffer.Memory().Map();
*data = 8;
const char vertshader[] = R"glsl(
#version 450
layout(set = 0, binding = 0) uniform Foo { uint index[]; };
layout(set = 0, binding = 1) buffer StorageBuffer { uint data[]; };
void main() {
uint index = index[0];
data[index] = 0xdeadca71;
}
)glsl";
// Create VkShaderModule to pass in
VkShaderObj vs(*m_device, vertshader, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
name_info.objectType = VK_OBJECT_TYPE_SHADER_MODULE;
name_info.pObjectName = "vertex_foo";
name_info.objectHandle = uint64_t(vs.handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
name_info.pObjectName = "fragment_bar";
name_info.objectHandle = uint64_t(fs.handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
CreatePipelineHelper vertex_input_lib(*this);
vertex_input_lib.InitVertexInputLibInfo();
vertex_input_lib.CreateGraphicsPipeline(false);
// For GPU-AV tests this shrinks things so only a single fragment is executed
VkViewport viewport = {0, 0, 1, 1, 0, 1};
VkRect2D scissor = {{0, 0}, {1, 1}};
CreatePipelineHelper pre_raster_lib(*this);
{
pre_raster_lib.InitPreRasterLibInfo(&vs.GetStageCreateInfo());
pre_raster_lib.vp_state_ci_.pViewports = &viewport;
pre_raster_lib.vp_state_ci_.pScissors = &scissor;
pre_raster_lib.gp_ci_.layout = pipeline_layout;
pre_raster_lib.CreateGraphicsPipeline();
}
CreatePipelineHelper frag_shader_lib(*this);
{
frag_shader_lib.InitFragmentLibInfo(&fs.GetStageCreateInfo());
frag_shader_lib.gp_ci_.layout = pipeline_layout;
frag_shader_lib.CreateGraphicsPipeline(false);
}
CreatePipelineHelper frag_out_lib(*this);
frag_out_lib.InitFragmentOutputLibInfo();
frag_out_lib.CreateGraphicsPipeline(false);
VkPipeline libraries[4] = {
vertex_input_lib,
pre_raster_lib,
frag_shader_lib,
frag_out_lib,
};
VkPipelineLibraryCreateInfoKHR link_info = vku::InitStructHelper();
link_info.libraryCount = size32(libraries);
link_info.pLibraries = libraries;
VkGraphicsPipelineCreateInfo exe_pipe_ci = vku::InitStructHelper(&link_info);
exe_pipe_ci.layout = pipeline_layout;
m_errorMonitor->SetDesiredInfo("vertex_foo");
m_errorMonitor->SetDesiredInfo("fragment_bar");
vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci);
m_errorMonitor->VerifyFound();
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe);
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0,
nullptr);
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-storageBuffers-06936", 3);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeGpuAVScoped, RayGenUseQueryUninitSelectShaders) {
TEST_DESCRIPTION(
"rayQueryInitializeEXT is never called, make sure we don't hang with an uninit query object. Selectively instrument ray "
"gen shader");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_RAY_QUERY_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::rayQuery);
AddRequiredFeature(vkt::Feature::accelerationStructure);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
AddRequiredFeature(vkt::Feature::rayTracingPipeline);
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
std::vector<VkLayerSettingEXT> layer_settings(2);
layer_settings[0] = {OBJECT_LAYER_NAME, "gpuav_select_instrumented_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkTrue};
std::array<const char*, 3> shader_regexes = {{"vertex_foo", "fragment_.*", ".*ray.*"}};
layer_settings[1] = {OBJECT_LAYER_NAME, "gpuav_shaders_to_instrument", VK_LAYER_SETTING_TYPE_STRING_EXT, size32(shader_regexes),
shader_regexes.data()};
RETURN_IF_SKIP(InitGpuAvFramework(layer_settings));
RETURN_IF_SKIP(InitState());
vkt::rt::Pipeline pipeline(*this, m_device);
const char* ray_gen = R"glsl(
#version 460
#extension GL_EXT_ray_query : require
layout(binding = 0, set = 0) uniform accelerationStructureEXT tlas;
layout(set = 0, binding = 1) buffer SSBO {
float x;
float y;
} params;
void main() {
rayQueryEXT query;
rayQueryInitializeEXT(query, tlas, gl_RayFlagsTerminateOnFirstHitEXT, 0xff, vec3(0,1,0), params.x, vec3(0,0,1), 100);
rayQueryProceedEXT(query);
if (rayQueryGetIntersectionTypeEXT(query, true) != gl_RayQueryCommittedIntersectionNoneEXT) {
params.y = rayQueryGetIntersectionTEXT(query, true);
}
}
)glsl";
pipeline.SetGlslRayGenShader(ray_gen);
VkShaderObj& ray_gen_shader = pipeline.GetRayGenShader(0);
VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
name_info.objectType = VK_OBJECT_TYPE_SHADER_MODULE;
name_info.pObjectName = "my_oh_my_ray_gen";
name_info.objectHandle = uint64_t(ray_gen_shader.handle());
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
pipeline.AddBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0);
pipeline.AddBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1);
pipeline.CreateDescriptorSet();
vkt::as::BuildGeometryInfoKHR tlas(vkt::as::blueprint::BuildOnDeviceTopLevel(*m_device, *m_default_queue, m_command_buffer));
pipeline.GetDescriptorSet().WriteDescriptorAccelStruct(0, 1, &tlas.GetDstAS()->handle());
vkt::Buffer ssbo(*m_device, 4096, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps);
auto buffer_ptr = static_cast<float*>(ssbo.Memory().Map());
buffer_ptr[0] = -16.0f;
pipeline.GetDescriptorSet().WriteDescriptorBufferInfo(1, ssbo, 0, 4096, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
pipeline.GetDescriptorSet().UpdateDescriptorSets();
m_errorMonitor->SetDesiredInfo("my_oh_my_ray_gen");
pipeline.Build();
m_errorMonitor->VerifyFound();
m_command_buffer.Begin();
vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.GetPipelineLayout(), 0, 1,
&pipeline.GetDescriptorSet().set_, 0, nullptr);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline);
vkt::rt::TraceRaysSbt trace_rays_sbt = pipeline.GetTraceRaysSbt();
vk::CmdTraceRaysKHR(m_command_buffer, &trace_rays_sbt.ray_gen_sbt, &trace_rays_sbt.miss_sbt, &trace_rays_sbt.hit_sbt,
&trace_rays_sbt.callable_sbt, 1, 1, 1);
m_command_buffer.End();
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06349");
m_default_queue->Submit(m_command_buffer);
m_device->Wait();
m_errorMonitor->VerifyFound();
}