blob: 4e0ff382f33e14b1971444891b39057a8ba562c1 [file] [log] [blame]
/*
* Copyright (c) 2023-2025 Valve Corporation
* Copyright (c) 2023-2025 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
*
*/
#include <vulkan/vulkan_core.h>
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
#include "../framework/shader_object_helper.h"
#include "generated/vk_function_pointers.h"
void DeviceGeneratedCommandsTest::InitBasicDeviceGeneratedCommands() {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::deviceGeneratedCommands);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT dgc_props = vku::InitStructHelper();
GetPhysicalDeviceProperties2(dgc_props);
if ((dgc_props.supportedIndirectCommandsShaderStagesPipelineBinding & VK_SHADER_STAGE_COMPUTE_BIT) == 0) {
GTEST_SKIP() << "VK_SHADER_STAGE_COMPUTE_BIT is not supported.";
} else if ((dgc_props.supportedIndirectCommandsShaderStagesPipelineBinding & VK_SHADER_STAGE_VERTEX_BIT) == 0) {
GTEST_SKIP() << "VK_SHADER_STAGE_VERTEX_BIT is not supported.";
}
}
// "If vkGetGeneratedCommandsMemoryRequirementsEXT returns a non-zero size, preprocessAddress must not be NULL"
// Does the query and updates with preprocessAddress if needed
void DeviceGeneratedCommandsTest::SetPreProcessBuffer(VkGeneratedCommandsInfoEXT& generated_commands_info,
void* pipeline_or_shader_object) {
VkGeneratedCommandsMemoryRequirementsInfoEXT dgc_mem_reqs = vku::InitStructHelper(pipeline_or_shader_object);
dgc_mem_reqs.indirectCommandsLayout = generated_commands_info.indirectCommandsLayout;
dgc_mem_reqs.indirectExecutionSet = generated_commands_info.indirectExecutionSet;
dgc_mem_reqs.maxSequenceCount = generated_commands_info.maxSequenceCount;
dgc_mem_reqs.maxDrawCount = generated_commands_info.maxDrawCount;
VkDeviceAddress pre_process_address = 0;
VkMemoryRequirements2 mem_reqs2 = vku::InitStructHelper();
vk::GetGeneratedCommandsMemoryRequirementsEXT(device(), &dgc_mem_reqs, &mem_reqs2);
const VkDeviceSize pre_process_size = mem_reqs2.memoryRequirements.size;
if (pre_process_size > 0) {
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
VkBufferUsageFlags2CreateInfo buffer_usage_flags = vku::InitStructHelper();
buffer_usage_flags.usage = VK_BUFFER_USAGE_2_PREPROCESS_BUFFER_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
VkBufferCreateInfo buffer_ci = vku::InitStructHelper(&buffer_usage_flags);
buffer_ci.size = pre_process_size;
pre_process_buffer_->Init(*m_device, buffer_ci, 0, &allocate_flag_info);
pre_process_address = pre_process_buffer_->Address();
}
generated_commands_info.preprocessSize = pre_process_size;
generated_commands_info.preprocessAddress = pre_process_address;
}
class PositiveDeviceGeneratedCommands : public DeviceGeneratedCommandsTest {};
TEST_F(PositiveDeviceGeneratedCommands, CreateIndirectExecutionSetPipeline) {
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
InitRenderTarget();
VkPipelineCreateFlags2CreateInfo pipe_flags2 = vku::InitStructHelper();
pipe_flags2.flags = VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_EXT;
CreatePipelineHelper pipe(*this, &pipe_flags2);
pipe.CreateGraphicsPipeline();
vkt::IndirectExecutionSet exe_set(*m_device, pipe, 1);
}
TEST_F(PositiveDeviceGeneratedCommands, CreateIndirectExecutionSetShaderObject) {
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::shaderObject);
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
InitRenderTarget();
const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl);
VkShaderCreateInfoEXT vert_create_info =
ShaderCreateInfoFlag(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_CREATE_INDIRECT_BINDABLE_BIT_EXT);
const vkt::Shader vertShader(*m_device, vert_create_info);
const VkShaderEXT shaders[] = {vertShader};
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
VkIndirectExecutionSetShaderLayoutInfoEXT exe_set_layouts = vku::InitStructHelper();
exe_set_layouts.setLayoutCount = 1;
exe_set_layouts.pSetLayouts = &descriptor_set.layout_.handle();
VkIndirectExecutionSetShaderInfoEXT exe_set_shader_info = vku::InitStructHelper();
exe_set_shader_info.shaderCount = 1;
exe_set_shader_info.pInitialShaders = shaders;
exe_set_shader_info.pSetLayoutInfos = &exe_set_layouts;
exe_set_shader_info.maxShaderCount = 1;
exe_set_shader_info.pushConstantRangeCount = 0;
vkt::IndirectExecutionSet exe_set(*m_device, exe_set_shader_info);
}
TEST_F(PositiveDeviceGeneratedCommands, CreateIndirectCommandsLayout) {
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
VkIndirectCommandsLayoutTokenEXT token = vku::InitStructHelper();
token.type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT;
token.offset = 0;
VkIndirectCommandsLayoutCreateInfoEXT command_layout_ci = vku::InitStructHelper();
command_layout_ci.shaderStages = VK_SHADER_STAGE_VERTEX_BIT;
command_layout_ci.pipelineLayout = VK_NULL_HANDLE;
command_layout_ci.tokenCount = 1;
command_layout_ci.pTokens = &token;
VkIndirectCommandsLayoutEXT command_layout;
vk::CreateIndirectCommandsLayoutEXT(device(), &command_layout_ci, nullptr, &command_layout);
vk::DestroyIndirectCommandsLayoutEXT(device(), command_layout, nullptr);
}
TEST_F(PositiveDeviceGeneratedCommands, GetGeneratedCommandsMemoryRequirements) {
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
InitRenderTarget();
VkIndirectCommandsLayoutTokenEXT token = vku::InitStructHelper();
token.type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT;
token.offset = 0;
VkIndirectCommandsLayoutCreateInfoEXT command_layout_ci = vku::InitStructHelper();
command_layout_ci.shaderStages = VK_SHADER_STAGE_VERTEX_BIT;
command_layout_ci.pipelineLayout = VK_NULL_HANDLE;
command_layout_ci.tokenCount = 1;
command_layout_ci.pTokens = &token;
vkt::IndirectCommandsLayout command_layout(*m_device, command_layout_ci);
VkPipelineCreateFlags2CreateInfo pipe_flags2 = vku::InitStructHelper();
pipe_flags2.flags = VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_EXT;
CreatePipelineHelper pipe(*this, &pipe_flags2);
pipe.CreateGraphicsPipeline();
VkGeneratedCommandsPipelineInfoEXT pipeline_info = vku::InitStructHelper();
pipeline_info.pipeline = pipe;
VkGeneratedCommandsMemoryRequirementsInfoEXT req_info = vku::InitStructHelper(&pipeline_info);
req_info.maxSequenceCount = 1;
req_info.indirectExecutionSet = VK_NULL_HANDLE;
req_info.indirectCommandsLayout = command_layout;
VkMemoryRequirements2 mem_req2 = vku::InitStructHelper();
vk::GetGeneratedCommandsMemoryRequirementsEXT(device(), &req_info, &mem_req2);
}
TEST_F(PositiveDeviceGeneratedCommands, PushConstant) {
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
VkIndirectCommandsPushConstantTokenEXT pc_token;
pc_token.updateRange = {VK_SHADER_STAGE_VERTEX_BIT, 8, 8};
VkIndirectCommandsLayoutTokenEXT tokens[2];
tokens[0] = vku::InitStructHelper();
tokens[0].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT;
tokens[0].data.pPushConstant = &pc_token;
tokens[0].offset = 0;
tokens[1] = vku::InitStructHelper();
tokens[1].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT;
tokens[1].offset = 8;
const std::vector<VkPushConstantRange> pc_range = {{VK_SHADER_STAGE_VERTEX_BIT, 4, 12}};
vkt::PipelineLayout pipeline_layout(*m_device, {}, pc_range);
VkIndirectCommandsLayoutCreateInfoEXT command_layout_ci = vku::InitStructHelper();
command_layout_ci.shaderStages = VK_SHADER_STAGE_VERTEX_BIT;
command_layout_ci.pipelineLayout = pipeline_layout;
command_layout_ci.tokenCount = 2;
command_layout_ci.pTokens = tokens;
vkt::IndirectCommandsLayout command_layout(*m_device, command_layout_ci);
}
TEST_F(PositiveDeviceGeneratedCommands, CmdExecuteGeneratedCommandsGraphics) {
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
InitRenderTarget();
VkPipelineCreateFlags2CreateInfo pipe_flags2 = vku::InitStructHelper();
pipe_flags2.flags = VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_EXT;
CreatePipelineHelper pipe(*this, &pipe_flags2);
pipe.CreateGraphicsPipeline();
vkt::IndirectExecutionSet exe_set(*m_device, pipe, 1);
VkIndirectCommandsExecutionSetTokenEXT exe_set_token = {VK_INDIRECT_EXECUTION_SET_INFO_TYPE_PIPELINES_EXT,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT};
VkIndirectCommandsLayoutTokenEXT tokens[2];
tokens[0] = vku::InitStructHelper();
tokens[0].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT;
tokens[0].data.pExecutionSet = &exe_set_token;
tokens[0].offset = 0;
tokens[1] = vku::InitStructHelper();
tokens[1].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT;
tokens[1].offset = 8;
VkIndirectCommandsLayoutCreateInfoEXT command_layout_ci = vku::InitStructHelper();
command_layout_ci.shaderStages = VK_SHADER_STAGE_VERTEX_BIT;
command_layout_ci.pipelineLayout = VK_NULL_HANDLE;
command_layout_ci.tokenCount = 2;
command_layout_ci.pTokens = tokens;
vkt::IndirectCommandsLayout command_layout(*m_device, command_layout_ci);
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
vkt::Buffer block_buffer(*m_device, 64, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, kHostVisibleMemProps, &allocate_flag_info);
VkGeneratedCommandsInfoEXT generated_commands_info = vku::InitStructHelper();
generated_commands_info.shaderStages = VK_SHADER_STAGE_VERTEX_BIT;
generated_commands_info.indirectExecutionSet = exe_set;
generated_commands_info.indirectCommandsLayout = command_layout;
generated_commands_info.indirectAddressSize = 64;
generated_commands_info.indirectAddress = block_buffer.Address();
generated_commands_info.sequenceCountAddress = 0;
generated_commands_info.maxSequenceCount = 1;
generated_commands_info.maxDrawCount = 1;
SetPreProcessBuffer(generated_commands_info);
m_command_buffer.Begin();
m_command_buffer.BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdExecuteGeneratedCommandsEXT(m_command_buffer, false, &generated_commands_info);
m_command_buffer.EndRenderPass();
m_command_buffer.End();
}
TEST_F(PositiveDeviceGeneratedCommands, UpdateIndirectExecutionSetPipeline) {
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
InitRenderTarget();
VkPipelineCreateFlags2CreateInfo pipe_flags2 = vku::InitStructHelper();
pipe_flags2.flags = VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_EXT;
CreatePipelineHelper pipe(*this, &pipe_flags2);
pipe.CreateGraphicsPipeline();
vkt::IndirectExecutionSet exe_set(*m_device, pipe, 4);
VkWriteIndirectExecutionSetPipelineEXT write_exe_sets[3];
write_exe_sets[0] = vku::InitStructHelper();
write_exe_sets[0].index = 1;
write_exe_sets[0].pipeline = pipe;
write_exe_sets[1] = vku::InitStructHelper();
write_exe_sets[1].index = 2;
write_exe_sets[1].pipeline = pipe;
write_exe_sets[2] = vku::InitStructHelper();
write_exe_sets[2].index = 3;
write_exe_sets[2].pipeline = pipe;
vk::UpdateIndirectExecutionSetPipelineEXT(device(), exe_set, 3, write_exe_sets);
}
TEST_F(PositiveDeviceGeneratedCommands, UpdateIndirectExecutionSetShader) {
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::shaderObject);
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
InitRenderTarget();
const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl);
VkShaderCreateInfoEXT vert_create_info =
ShaderCreateInfoFlag(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_CREATE_INDIRECT_BINDABLE_BIT_EXT);
const vkt::Shader vertShader(*m_device, vert_create_info);
const VkShaderEXT shaders[] = {vertShader};
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
VkIndirectExecutionSetShaderLayoutInfoEXT exe_set_layouts = vku::InitStructHelper();
exe_set_layouts.setLayoutCount = 1;
exe_set_layouts.pSetLayouts = &descriptor_set.layout_.handle();
VkIndirectExecutionSetShaderInfoEXT exe_set_shader_info = vku::InitStructHelper();
exe_set_shader_info.shaderCount = 1;
exe_set_shader_info.pInitialShaders = shaders;
exe_set_shader_info.pSetLayoutInfos = &exe_set_layouts;
exe_set_shader_info.maxShaderCount = 1;
exe_set_shader_info.pushConstantRangeCount = 0;
vkt::IndirectExecutionSet exe_set(*m_device, exe_set_shader_info);
VkWriteIndirectExecutionSetShaderEXT write_exe_set = vku::InitStructHelper();
write_exe_set.index = 0;
write_exe_set.shader = vertShader;
vk::UpdateIndirectExecutionSetShaderEXT(device(), exe_set, 1, &write_exe_set);
}
TEST_F(PositiveDeviceGeneratedCommands, CmdExecuteGeneratedCommandsCompute) {
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
VkIndirectCommandsExecutionSetTokenEXT exe_set_token = {VK_INDIRECT_EXECUTION_SET_INFO_TYPE_PIPELINES_EXT,
VK_SHADER_STAGE_COMPUTE_BIT};
VkIndirectCommandsLayoutTokenEXT tokens[2];
tokens[0] = vku::InitStructHelper();
tokens[0].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT;
tokens[0].data.pExecutionSet = &exe_set_token;
tokens[0].offset = 0;
tokens[1] = vku::InitStructHelper();
tokens[1].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT;
tokens[1].offset = 8;
VkIndirectCommandsLayoutCreateInfoEXT command_layout_ci = vku::InitStructHelper();
command_layout_ci.shaderStages = VK_SHADER_STAGE_COMPUTE_BIT;
command_layout_ci.pipelineLayout = VK_NULL_HANDLE;
command_layout_ci.tokenCount = 2;
command_layout_ci.pTokens = tokens;
vkt::IndirectCommandsLayout command_layout(*m_device, command_layout_ci);
VkPipelineCreateFlags2CreateInfo pipe_flags2 = vku::InitStructHelper();
pipe_flags2.flags = VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_EXT;
CreateComputePipelineHelper pipe(*this, &pipe_flags2);
pipe.CreateComputePipeline();
vkt::IndirectExecutionSet exe_set(*m_device, pipe, 1);
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
vkt::Buffer block_buffer(*m_device, 64, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, kHostVisibleMemProps, &allocate_flag_info);
VkGeneratedCommandsInfoEXT generated_commands_info = vku::InitStructHelper();
generated_commands_info.shaderStages = VK_SHADER_STAGE_COMPUTE_BIT;
generated_commands_info.indirectExecutionSet = exe_set;
generated_commands_info.indirectCommandsLayout = command_layout;
generated_commands_info.indirectAddressSize = 64;
generated_commands_info.indirectAddress = block_buffer.Address();
generated_commands_info.sequenceCountAddress = 0;
generated_commands_info.maxSequenceCount = 1;
generated_commands_info.maxDrawCount = 1;
SetPreProcessBuffer(generated_commands_info);
m_command_buffer.Begin();
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe);
vk::CmdExecuteGeneratedCommandsEXT(m_command_buffer, false, &generated_commands_info);
m_command_buffer.End();
}
TEST_F(PositiveDeviceGeneratedCommands, ExecuteShaderObjectVertex) {
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::shaderObject);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
InitRenderTarget();
VkIndirectCommandsExecutionSetTokenEXT exe_set_token = {VK_INDIRECT_EXECUTION_SET_INFO_TYPE_SHADER_OBJECTS_EXT,
VK_SHADER_STAGE_VERTEX_BIT};
VkIndirectCommandsLayoutTokenEXT tokens[2];
tokens[0] = vku::InitStructHelper();
tokens[0].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT;
tokens[0].data.pExecutionSet = &exe_set_token;
tokens[0].offset = 0;
tokens[1] = vku::InitStructHelper();
tokens[1].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT;
tokens[1].offset = 8;
VkIndirectCommandsLayoutCreateInfoEXT command_layout_ci = vku::InitStructHelper();
command_layout_ci.shaderStages = VK_SHADER_STAGE_VERTEX_BIT;
command_layout_ci.pipelineLayout = VK_NULL_HANDLE;
command_layout_ci.tokenCount = 2;
command_layout_ci.pTokens = tokens;
vkt::IndirectCommandsLayout command_layout(*m_device, command_layout_ci);
const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl);
VkShaderCreateInfoEXT vert_create_info =
ShaderCreateInfoFlag(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_CREATE_INDIRECT_BINDABLE_BIT_EXT);
const vkt::Shader vertShader(*m_device, vert_create_info);
const VkShaderEXT shaders[] = {vertShader};
OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
VkIndirectExecutionSetShaderLayoutInfoEXT exe_set_layouts = vku::InitStructHelper();
exe_set_layouts.setLayoutCount = 1;
exe_set_layouts.pSetLayouts = &descriptor_set.layout_.handle();
VkIndirectExecutionSetShaderInfoEXT exe_set_shader_info = vku::InitStructHelper();
exe_set_shader_info.shaderCount = 1;
exe_set_shader_info.pInitialShaders = shaders;
exe_set_shader_info.pSetLayoutInfos = &exe_set_layouts;
exe_set_shader_info.maxShaderCount = 1;
exe_set_shader_info.pushConstantRangeCount = 0;
vkt::IndirectExecutionSet exe_set(*m_device, exe_set_shader_info);
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
vkt::Buffer block_buffer(*m_device, 64, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, kHostVisibleMemProps, &allocate_flag_info);
VkGeneratedCommandsInfoEXT generated_commands_info = vku::InitStructHelper();
generated_commands_info.shaderStages = VK_SHADER_STAGE_VERTEX_BIT;
generated_commands_info.indirectExecutionSet = exe_set;
generated_commands_info.indirectCommandsLayout = command_layout;
generated_commands_info.indirectAddressSize = 64;
generated_commands_info.indirectAddress = block_buffer.Address();
generated_commands_info.sequenceCountAddress = 0;
generated_commands_info.maxSequenceCount = 1;
generated_commands_info.maxDrawCount = 1;
SetPreProcessBuffer(generated_commands_info);
m_command_buffer.Begin();
m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea());
const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT};
vk::CmdBindShadersEXT(m_command_buffer, 1u, stages, shaders);
SetDefaultDynamicStatesAll(m_command_buffer);
vk::CmdExecuteGeneratedCommandsEXT(m_command_buffer, false, &generated_commands_info);
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(PositiveDeviceGeneratedCommands, ExecuteShaderObjectMesh) {
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::shaderObject);
AddRequiredFeature(vkt::Feature::maintenance4);
AddRequiredFeature(vkt::Feature::meshShader);
AddRequiredFeature(vkt::Feature::taskShader);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
InitRenderTarget();
VkIndirectCommandsLayoutTokenEXT tokens = vku::InitStructHelper();
tokens.type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_EXT;
tokens.offset = 0;
VkIndirectCommandsLayoutCreateInfoEXT command_layout_ci = vku::InitStructHelper();
command_layout_ci.shaderStages = VK_SHADER_STAGE_MESH_BIT_EXT;
command_layout_ci.pipelineLayout = VK_NULL_HANDLE;
command_layout_ci.tokenCount = 1;
command_layout_ci.pTokens = &tokens;
vkt::IndirectCommandsLayout command_layout(*m_device, command_layout_ci);
const auto spv = GLSLToSPV(VK_SHADER_STAGE_MESH_BIT_EXT, kMeshMinimalGlsl, SPV_ENV_VULKAN_1_3);
VkShaderCreateInfoEXT mesh_create_info = ShaderCreateInfoFlag(
spv, VK_SHADER_STAGE_MESH_BIT_EXT, VK_SHADER_CREATE_INDIRECT_BINDABLE_BIT_EXT | VK_SHADER_CREATE_NO_TASK_SHADER_BIT_EXT);
const vkt::Shader mesh_shader(*m_device, mesh_create_info);
const VkShaderEXT shaders[] = {mesh_shader};
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
vkt::Buffer block_buffer(*m_device, 64, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, kHostVisibleMemProps, &allocate_flag_info);
VkGeneratedCommandsShaderInfoEXT init_shader_info = vku::InitStructHelper();
init_shader_info.shaderCount = 1;
init_shader_info.pShaders = shaders;
VkGeneratedCommandsInfoEXT generated_commands_info = vku::InitStructHelper(&init_shader_info);
generated_commands_info.shaderStages = VK_SHADER_STAGE_MESH_BIT_EXT;
generated_commands_info.indirectExecutionSet = VK_NULL_HANDLE;
generated_commands_info.indirectCommandsLayout = command_layout;
generated_commands_info.indirectAddressSize = 64;
generated_commands_info.indirectAddress = block_buffer.Address();
generated_commands_info.sequenceCountAddress = 0;
generated_commands_info.maxSequenceCount = 1;
generated_commands_info.maxDrawCount = 1;
SetPreProcessBuffer(generated_commands_info, &init_shader_info);
m_command_buffer.Begin();
m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea());
const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_MESH_BIT_EXT};
vk::CmdBindShadersEXT(m_command_buffer, 1u, stages, shaders);
const VkShaderEXT null_shader = VK_NULL_HANDLE;
VkShaderStageFlagBits null_stages = VK_SHADER_STAGE_VERTEX_BIT;
vk::CmdBindShadersEXT(m_command_buffer, 1u, &null_stages, &null_shader);
null_stages = VK_SHADER_STAGE_FRAGMENT_BIT;
vk::CmdBindShadersEXT(m_command_buffer, 1u, &null_stages, &null_shader);
null_stages = VK_SHADER_STAGE_TASK_BIT_EXT;
vk::CmdBindShadersEXT(m_command_buffer, 1u, &null_stages, &null_shader);
SetDefaultDynamicStatesAll(m_command_buffer);
vk::CmdExecuteGeneratedCommandsEXT(m_command_buffer, false, &generated_commands_info);
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(PositiveDeviceGeneratedCommands, IndirectExecutionSetNullLayout) {
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::shaderObject);
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
InitRenderTarget();
const char comp_src[] = R"glsl(
#version 460
layout (local_size_x=64, local_size_y=1, local_size_z=1) in;
layout (set=0, binding=0, std430) buffer OutputBlock { uint values[]; } outputBuffer;
layout (set=0, binding=1, std430) readonly buffer InputBlock { uint values[]; } inputBuffer;
layout (push_constant, std430) uniform PushConstantBlock { uint bufferOffset; } pc;
void main(void) {
const uint idx = gl_LocalInvocationIndex + pc.bufferOffset;
outputBuffer.values[idx] = inputBuffer.values[idx];
}
)glsl";
std::vector<uint32_t> spv = GLSLToSPV(VK_SHADER_STAGE_COMPUTE_BIT, comp_src);
vkt::Buffer buffer1(*m_device, 512, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
vkt::Buffer buffer2(*m_device, 512, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
vkt::DescriptorSetLayout descriptor_set_layout(
*m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
});
vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set_layout});
VkPushConstantRange push_constant_range{VK_SHADER_STAGE_COMPUTE_BIT, 0, 4};
VkShaderCreateInfoEXT shader_ci = vku::InitStructHelper();
shader_ci.flags = VK_SHADER_CREATE_INDIRECT_BINDABLE_BIT_EXT;
shader_ci.stage = VK_SHADER_STAGE_COMPUTE_BIT;
shader_ci.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT;
shader_ci.codeSize = spv.size() * sizeof(uint32_t);
shader_ci.pCode = spv.data();
shader_ci.pName = "main";
shader_ci.setLayoutCount = 1u;
shader_ci.pSetLayouts = &descriptor_set_layout.handle();
shader_ci.pushConstantRangeCount = 1u;
shader_ci.pPushConstantRanges = &push_constant_range;
vkt::Shader shader(*m_device, shader_ci);
VkIndirectExecutionSetShaderInfoEXT shader_info = vku::InitStructHelper();
shader_info.shaderCount = 1u;
shader_info.pInitialShaders = &shader.handle();
shader_info.pSetLayoutInfos = nullptr;
shader_info.maxShaderCount = 2u;
shader_info.pushConstantRangeCount = 1u;
shader_info.pPushConstantRanges = &push_constant_range;
VkIndirectExecutionSetCreateInfoEXT indirect_execution_set_ci = vku::InitStructHelper();
indirect_execution_set_ci.type = VK_INDIRECT_EXECUTION_SET_INFO_TYPE_SHADER_OBJECTS_EXT;
indirect_execution_set_ci.info.pShaderInfo = &shader_info;
VkIndirectExecutionSetEXT indirect_execution_set;
vk::CreateIndirectExecutionSetEXT(*m_device, &indirect_execution_set_ci, nullptr, &indirect_execution_set);
vk::DestroyIndirectExecutionSetEXT(*m_device, indirect_execution_set, nullptr);
}
TEST_F(PositiveDeviceGeneratedCommands, PushConstantMultipleRanges) {
RETURN_IF_SKIP(InitBasicDeviceGeneratedCommands());
VkIndirectCommandsPushConstantTokenEXT pc_token_vert;
pc_token_vert.updateRange = {VK_SHADER_STAGE_VERTEX_BIT, 0, 16};
VkIndirectCommandsPushConstantTokenEXT pc_token_frag;
pc_token_frag.updateRange = {VK_SHADER_STAGE_FRAGMENT_BIT, 16, 16};
VkIndirectCommandsLayoutTokenEXT tokens[3];
tokens[0] = vku::InitStructHelper();
tokens[0].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT;
tokens[0].data.pPushConstant = &pc_token_vert;
tokens[0].offset = 0;
tokens[1] = vku::InitStructHelper();
tokens[1].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT;
tokens[1].data.pPushConstant = &pc_token_frag;
tokens[1].offset = 8;
tokens[2] = vku::InitStructHelper();
tokens[2].type = VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT;
tokens[2].offset = 16;
std::vector<VkPushConstantRange> pc_ranges = {
{VK_SHADER_STAGE_VERTEX_BIT, 0, 16},
{VK_SHADER_STAGE_FRAGMENT_BIT, 16, 16},
};
vkt::PipelineLayout pipeline_layout(*m_device, {}, pc_ranges);
VkIndirectCommandsLayoutCreateInfoEXT command_layout_ci = vku::InitStructHelper();
command_layout_ci.shaderStages = VK_SHADER_STAGE_VERTEX_BIT;
command_layout_ci.pipelineLayout = pipeline_layout;
command_layout_ci.tokenCount = 3;
command_layout_ci.pTokens = tokens;
vkt::IndirectCommandsLayout command_layout(*m_device, command_layout_ci);
}