Skip to content

Commit 64127f5

Browse files
committed
tests: Test heap buffer usage
1 parent 654639b commit 64127f5

File tree

5 files changed

+137
-16
lines changed

5 files changed

+137
-16
lines changed

layers/gpuav/instrumentation/post_process_descriptor_heap.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2025 LunarG, Inc.
1+
/* Copyright (c) 2025-2026 LunarG, Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -69,8 +69,6 @@ void RegisterPostProcessingDescriptorHeap(Validator& gpuav, CommandBufferSubStat
6969
pp_cb_state.post_process_variables =
7070
cb.gpu_resources_manager.GetHostCoherentBufferRange(sizeof(Slot) * kDebugMaxDescSetAndBindings);
7171

72-
out_update.buffer = pp_cb_state.post_process_variables.buffer;
73-
out_update.offset = pp_cb_state.post_process_variables.offset;
7472
out_update.range = pp_cb_state.post_process_variables.size;
7573
out_update.address = pp_cb_state.post_process_variables.offset_address;
7674
out_update.binding = glsl::kBindingInstDescriptorHeapPostProcess;
@@ -123,7 +121,8 @@ void RegisterPostProcessingDescriptorHeap(Validator& gpuav, CommandBufferSubStat
123121
ASSERT_AND_CONTINUE(shader_object_state->stage.entrypoint);
124122
mappings = vku::FindStructInPNextChain<VkShaderDescriptorSetAndBindingMappingInfoEXT>(
125123
shader_object_state->create_info.pNext);
126-
auto variable_it = shader_object_state->stage.entrypoint->resource_interface_variable_map.find(slot.variable_id);
124+
auto variable_it =
125+
shader_object_state->stage.entrypoint->resource_interface_variable_map.find(slot.variable_id);
127126
if (variable_it != shader_object_state->stage.entrypoint->resource_interface_variable_map.end()) {
128127
resource_variable = variable_it->second;
129128
stage = shader_object_state->create_info.stage;
@@ -293,7 +292,8 @@ void RegisterPostProcessingDescriptorHeap(Validator& gpuav, CommandBufferSubStat
293292
ASSERT_AND_CONTINUE(shader_object_state->stage.entrypoint);
294293
mappings = vku::FindStructInPNextChain<VkShaderDescriptorSetAndBindingMappingInfoEXT>(
295294
shader_object_state->create_info.pNext);
296-
auto variable_it = shader_object_state->stage.entrypoint->resource_interface_variable_map.find(slot.variable_id);
295+
auto variable_it =
296+
shader_object_state->stage.entrypoint->resource_interface_variable_map.find(slot.variable_id);
297297
if (variable_it != shader_object_state->stage.entrypoint->resource_interface_variable_map.end()) {
298298
resource_variable = variable_it->second;
299299
}

layers/gpuav/instrumentation/post_process_descriptor_heap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2025 LunarG, Inc.
1+
/* Copyright (c) 2025-2026 LunarG, Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.

layers/gpuav/spirv/descriptor_heap_pass.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2024-2025 LunarG, Inc.
1+
/* Copyright (c) 2024-2026 LunarG, Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -53,8 +53,10 @@ void DescriptorHeapPass::CreateFunctionCall(BasicBlock& block, InstructionIt* in
5353
const uint32_t void_type = module_.type_manager_.GetTypeVoid().Id();
5454

5555
const uint32_t zero = module_.type_manager_.CreateConstantUInt32(0).Id();
56-
const uint32_t descriptor_offset_id = meta.access_chain_insts.empty() ? zero :
57-
GetLastByte(*meta.descriptor_type, meta.access_chain_insts, meta.coop_mat_access, block, inst_it);
56+
const uint32_t descriptor_offset_id =
57+
meta.access_chain_insts.empty()
58+
? zero
59+
: GetLastByte(*meta.descriptor_type, meta.access_chain_insts, meta.coop_mat_access, block, inst_it);
5860

5961
const Constant& slot_index = type_manager_.CreateConstantUInt32(slot_index_++);
6062
if (slot_index_ > glsl::kDebugMaxDescSetAndBindings) {
@@ -70,10 +72,7 @@ void DescriptorHeapPass::CreateFunctionCall(BasicBlock& block, InstructionIt* in
7072
module_.need_log_error_ = true;
7173
}
7274

73-
bool DescriptorHeapPass::HeapPointerRequiresInstrumentation(const Function& function, const Instruction& inst,
74-
InstructionMeta& meta) {
75-
return false;
76-
}
75+
bool DescriptorHeapPass::HeapPointerRequiresInstrumentation(const Function&, const Instruction&, InstructionMeta&) { return false; }
7776

7877
bool DescriptorHeapPass::RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) {
7978
const uint32_t opcode = inst.Opcode();
@@ -191,4 +190,4 @@ bool DescriptorHeapPass::Instrument() {
191190
}
192191

193192
} // namespace spirv
194-
} // namespace gpuav
193+
} // namespace gpuav

layers/gpuav/spirv/descriptor_heap_pass.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2025 LunarG, Inc.
1+
/* Copyright (c) 2025-2026 LunarG, Inc.
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.

tests/unit/gpu_av_descriptor_heap.cpp

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,4 +924,126 @@ TEST_F(NegativeGpuAVDescriptorHeap, ShaderObjects) {
924924

925925
m_default_queue->SubmitAndWait(m_command_buffer);
926926
m_errorMonitor->VerifyFound();
927-
}
927+
}
928+
929+
TEST_F(NegativeGpuAVDescriptorHeap, PushAddressUniformBufferUsage) {
930+
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
931+
AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics);
932+
RETURN_IF_SKIP(InitGpuAVDescriptorHeap());
933+
InitRenderTarget();
934+
935+
vkt::Buffer read_buffer(*m_device, sizeof(uint32_t) * 4, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address);
936+
uint32_t* read_data = static_cast<uint32_t*>(read_buffer.Memory().Map());
937+
for (uint32_t i = 0; i < 4; ++i) {
938+
read_data[i] = i + 1;
939+
}
940+
vkt::Buffer write_buffer(*m_device, sizeof(uint32_t) * 4, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR, vkt::device_address);
941+
942+
const uint32_t read_offset = 48u;
943+
const VkDeviceSize write_offset =
944+
Align(read_offset + heap_props.bufferDescriptorAlignment * 7u, heap_props.bufferDescriptorAlignment);
945+
const VkDeviceSize resource_stride = heap_props.bufferDescriptorSize;
946+
const VkDeviceSize descriptor_size = AlignResource(write_offset + resource_stride);
947+
const VkDeviceSize heap_size = descriptor_size + heap_props.minResourceHeapReservedRange;
948+
949+
vkt::Buffer heap(*m_device, heap_size, VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT, vkt::device_address);
950+
uint8_t* heap_data = static_cast<uint8_t*>(heap.Memory().Map());
951+
952+
VkHostAddressRangeEXT descriptor_host;
953+
descriptor_host.address = heap_data + write_offset;
954+
descriptor_host.size = resource_stride;
955+
956+
VkDeviceAddressRangeEXT device_range;
957+
device_range.address = write_buffer.Address();
958+
device_range.size = write_buffer.CreateInfo().size;
959+
960+
VkResourceDescriptorInfoEXT descriptor_info;
961+
descriptor_info = vku::InitStructHelper();
962+
descriptor_info.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
963+
descriptor_info.data.pAddressRange = &device_range;
964+
965+
vk::WriteResourceDescriptorsEXT(*m_device, 1u, &descriptor_info, &descriptor_host);
966+
967+
VkDescriptorSetAndBindingMappingEXT mappings[2];
968+
mappings[0] = vku::InitStructHelper();
969+
mappings[0].descriptorSet = 2u;
970+
mappings[0].firstBinding = 3u;
971+
mappings[0].bindingCount = 1u;
972+
mappings[0].resourceMask = VK_SPIRV_RESOURCE_TYPE_UNIFORM_BUFFER_BIT_EXT;
973+
mappings[0].source = VK_DESCRIPTOR_MAPPING_SOURCE_PUSH_ADDRESS_EXT;
974+
mappings[0].sourceData.pushAddressOffset = static_cast<uint32_t>(read_offset);
975+
mappings[1] = vku::InitStructHelper();
976+
mappings[1].descriptorSet = 1u;
977+
mappings[1].firstBinding = 0u;
978+
mappings[1].bindingCount = 1u;
979+
mappings[1].resourceMask = VK_SPIRV_RESOURCE_TYPE_READ_WRITE_STORAGE_BUFFER_BIT_EXT;
980+
mappings[1].source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_CONSTANT_OFFSET_EXT;
981+
mappings[1].sourceData.constantOffset.heapOffset = static_cast<uint32_t>(write_offset);
982+
mappings[1].sourceData.constantOffset.heapArrayStride = 0u;
983+
984+
VkShaderDescriptorSetAndBindingMappingInfoEXT mapping_info = vku::InitStructHelper();
985+
mapping_info.mappingCount = 2u;
986+
mapping_info.pMappings = mappings;
987+
988+
char const* vert_source = R"glsl(
989+
#version 450
990+
layout(set = 2, binding = 3) uniform ReadData {
991+
uvec4 read_data;
992+
};
993+
layout(set = 1, binding = 0) buffer WriteData {
994+
uvec4 write_data;
995+
};
996+
void main() {
997+
if (gl_VertexIndex == 0) {
998+
write_data[0] = read_data[3];
999+
}
1000+
gl_Position = vec4(1.0f);
1001+
gl_PointSize = 1.0f;
1002+
}
1003+
)glsl";
1004+
1005+
VkShaderObj vert_module = VkShaderObj(*m_device, vert_source, VK_SHADER_STAGE_VERTEX_BIT);
1006+
VkShaderObj frag_module = VkShaderObj(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
1007+
1008+
VkPipelineCreateFlags2CreateInfoKHR pipeline_create_flags_2_create_info = vku::InitStructHelper();
1009+
pipeline_create_flags_2_create_info.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT;
1010+
1011+
VkPipelineShaderStageCreateInfo stages[2];
1012+
stages[0] = vert_module.GetStageCreateInfo();
1013+
stages[0].pNext = &mapping_info;
1014+
stages[1] = frag_module.GetStageCreateInfo();
1015+
1016+
CreatePipelineHelper descriptor_heap_pipe(*this, &pipeline_create_flags_2_create_info);
1017+
descriptor_heap_pipe.gp_ci_.layout = VK_NULL_HANDLE;
1018+
descriptor_heap_pipe.gp_ci_.stageCount = 2u;
1019+
descriptor_heap_pipe.gp_ci_.pStages = stages;
1020+
descriptor_heap_pipe.CreateGraphicsPipeline(false);
1021+
1022+
VkDeviceAddress read_address = read_buffer.Address();
1023+
1024+
VkPushDataInfoEXT push_data = vku::InitStructHelper();
1025+
push_data.offset = read_offset;
1026+
push_data.data.address = &read_address;
1027+
push_data.data.size = sizeof(read_address);
1028+
1029+
m_command_buffer.Begin();
1030+
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
1031+
1032+
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, descriptor_heap_pipe);
1033+
1034+
VkBindHeapInfoEXT bind_resource_info = vku::InitStructHelper();
1035+
bind_resource_info.heapRange.address = heap.Address();
1036+
bind_resource_info.heapRange.size = heap_size;
1037+
bind_resource_info.reservedRangeOffset = descriptor_size;
1038+
bind_resource_info.reservedRangeSize = heap_props.minResourceHeapReservedRange;
1039+
vk::CmdBindResourceHeapEXT(m_command_buffer, &bind_resource_info);
1040+
1041+
vk::CmdPushDataEXT(m_command_buffer, &push_data);
1042+
vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, 0u);
1043+
1044+
m_command_buffer.EndRenderPass();
1045+
m_command_buffer.End();
1046+
m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-11438");
1047+
m_default_queue->SubmitAndWait(m_command_buffer);
1048+
m_errorMonitor->VerifyFound();
1049+
}

0 commit comments

Comments
 (0)