| /* |
| * 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 <cstdint> |
| #include "../framework/layer_validation_tests.h" |
| #include "../framework/pipeline_helper.h" |
| #include "../framework/render_pass_helper.h" |
| |
| void DescriptorBufferTest::InitBasicDescriptorBuffer(void *instance_pnext) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorBuffer); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| RETURN_IF_SKIP(Init(nullptr, nullptr, instance_pnext)); |
| |
| GetPhysicalDeviceProperties2(descriptor_buffer_properties); |
| } |
| |
| class PositiveDescriptorBuffer : public DescriptorBufferTest {}; |
| |
| TEST_F(PositiveDescriptorBuffer, BasicUsage) { |
| TEST_DESCRIPTION("Create VkBuffer with extension."); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorBuffer); |
| RETURN_IF_SKIP(Init()); |
| |
| // *descriptorBufferAddressSpaceSize properties are guaranteed to be 2^27 |
| VkBufferCreateInfo buffer_ci = vku::InitStructHelper(); |
| buffer_ci.size = 4096; |
| |
| { |
| buffer_ci.usage = VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; |
| vkt::Buffer buffer(*m_device, buffer_ci); |
| } |
| |
| { |
| buffer_ci.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vkt::Buffer buffer(*m_device, buffer_ci); |
| } |
| |
| { |
| buffer_ci.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | |
| VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; |
| vkt::Buffer buffer(*m_device, buffer_ci); |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, BindBufferAndSetOffset) { |
| TEST_DESCRIPTION("Bind descriptor buffer and set descriptor offset then draw."); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}; |
| const vkt::DescriptorSetLayout set_layout(*m_device, {binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&set_layout}); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| const uint32_t index = 0; |
| const VkDeviceSize offset = 0; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &index, &offset); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, UnusedBoundBuffer) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/10290"); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}; |
| const vkt::DescriptorSetLayout set_layout(*m_device, {binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&set_layout}); |
| |
| // Pipeline has no descriptor |
| CreatePipelineHelper pipe(*this); |
| pipe.CreateGraphicsPipeline(); |
| |
| CreatePipelineHelper pipe2(*this); |
| pipe2.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe2.CreateGraphicsPipeline(); |
| |
| const uint32_t index = 0; |
| const VkDeviceSize offset = 0; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| // unused |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &index, &offset); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| 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); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, PipelineFlags2) { |
| TEST_DESCRIPTION("Use descriptor buffer with pipeline created with VkPipelineCreateFlags2CreateInfo"); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance5); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}; |
| const vkt::DescriptorSetLayout set_layout(*m_device, {binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&set_layout}); |
| |
| VkPipelineCreateFlags2CreateInfo flags_2_ci = vku::InitStructHelper(); |
| flags_2_ci.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| CreatePipelineHelper pipe(*this, &flags_2_ci); |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| const uint32_t index = 0; |
| const VkDeviceSize offset = 0; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &index, &offset); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, BindingMidBuffer) { |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| m_command_buffer.Begin(); |
| |
| vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| VkDescriptorBufferBindingInfoEXT dbbi = vku::InitStructHelper(); |
| dbbi.address = buffer.Address() + descriptor_buffer_properties.descriptorBufferOffsetAlignment; |
| dbbi.usage = VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &dbbi); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, Basic) { |
| TEST_DESCRIPTION("Tries to use a full workflow (For Resource descriptors)."); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| vkt::Buffer buffer_data(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| uint32_t *data = (uint32_t *)buffer_data.Memory().Map(); |
| data[0] = 8; |
| data[1] = 12; |
| data[2] = 1; |
| |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_data, 16); |
| |
| void *mapped_descriptor_data = descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| uint b; |
| uint c; |
| }; |
| |
| void main() { |
| c = a + b; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| if (!IsPlatformMockICD()) { |
| ASSERT_TRUE(data[2] == 20); |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, BasicSampler) { |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| std::vector<VkDescriptorSetLayoutBinding> bindings = { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, bindings, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| vkt::Buffer result_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::ImageView image_view = image.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer( |
| *m_device, ds_layout_size, |
| VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| uint8_t *mapped_descriptor_data = (uint8_t *)descriptor_buffer.Memory().Map(); |
| |
| vkt::DescriptorGetInfo get_info_sampler(&sampler.handle()); |
| vk::GetDescriptorEXT(device(), get_info_sampler, descriptor_buffer_properties.samplerDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(0)); |
| |
| vkt::DescriptorGetInfo get_info_image(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_NULL_HANDLE, image_view, VK_IMAGE_LAYOUT_GENERAL); |
| vk::GetDescriptorEXT(device(), get_info_image, descriptor_buffer_properties.sampledImageDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(1)); |
| |
| vkt::DescriptorGetInfo get_info_combined(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, sampler, image_view, |
| VK_IMAGE_LAYOUT_GENERAL); |
| vk::GetDescriptorEXT(device(), get_info_combined, descriptor_buffer_properties.combinedImageSamplerDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(2)); |
| |
| vkt::DescriptorGetInfo get_info_buffer(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, result_buffer, 32); |
| vk::GetDescriptorEXT(device(), get_info_buffer, descriptor_buffer_properties.storageBufferDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(3)); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform sampler s; |
| layout(set = 0, binding = 1) uniform texture2D t; // sampled image |
| layout(set = 0, binding = 2) uniform sampler2D c; // combined |
| layout(set = 0, binding = 3) buffer SSBO { vec4 result; }; |
| |
| void main() { |
| result = texture(c, vec2(0)); |
| result *= texture(sampler2D(t, s), vec2(0)); |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = |
| VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, MultipleDescriptors) { |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| std::vector<VkDescriptorSetLayoutBinding> bindings = { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }; |
| vkt::DescriptorSetLayout ds_layout(*m_device, bindings, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| vkt::Buffer result_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Image image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::ImageView image_view = image.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer sampler_descriptor_buffer(*m_device, ds_layout_size, VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| vkt::Buffer resource_descriptor_buffer(*m_device, ds_layout_size, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| uint8_t *mapped_descriptor_data = (uint8_t *)resource_descriptor_buffer.Memory().Map(); |
| vkt::DescriptorGetInfo get_info_image(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_NULL_HANDLE, image_view, VK_IMAGE_LAYOUT_GENERAL); |
| vk::GetDescriptorEXT(device(), get_info_image, descriptor_buffer_properties.sampledImageDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(0)); |
| |
| vkt::DescriptorGetInfo get_info_buffer(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, result_buffer, 32); |
| vk::GetDescriptorEXT(device(), get_info_buffer, descriptor_buffer_properties.storageBufferDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(1)); |
| |
| mapped_descriptor_data = (uint8_t *)sampler_descriptor_buffer.Memory().Map(); |
| vkt::DescriptorGetInfo get_info_sampler(&sampler.handle()); |
| vk::GetDescriptorEXT(device(), get_info_sampler, descriptor_buffer_properties.samplerDescriptorSize, mapped_descriptor_data); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 2) uniform sampler s; |
| layout(set = 0, binding = 0) uniform texture2D t; |
| layout(set = 0, binding = 1) buffer SSBO { vec4 result; }; |
| |
| void main() { |
| result = texture(sampler2D(t, s), vec2(0)); |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info[2]; |
| descriptor_buffer_binding_info[0] = vku::InitStructHelper(); |
| descriptor_buffer_binding_info[0].address = sampler_descriptor_buffer.Address(); |
| descriptor_buffer_binding_info[0].usage = VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; |
| descriptor_buffer_binding_info[1] = vku::InitStructHelper(); |
| descriptor_buffer_binding_info[1].address = resource_descriptor_buffer.Address(); |
| descriptor_buffer_binding_info[1].usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 2, descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| |
| buffer_index = 1; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, MultipleSet) { |
| TEST_DESCRIPTION("Have a single VkBuffer of data spread across 3 different sets."); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| const uint32_t alignment = static_cast<uint32_t>(m_device->Physical().limits_.minStorageBufferOffsetAlignment); |
| const uint32_t offset_0 = 0; |
| const uint32_t offset_1 = alignment / sizeof(uint32_t); |
| const uint32_t offset_2 = offset_1 * 2; |
| vkt::Buffer buffer_data(*m_device, 4096, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| uint32_t *data = (uint32_t *)buffer_data.Memory().Map(); |
| data[offset_0] = 8; |
| data[offset_1] = 12; |
| data[offset_2] = 1; |
| |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout, &ds_layout, &ds_layout}); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size * 3, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| uint8_t *mapped_descriptor_data = (uint8_t *)descriptor_buffer.Memory().Map(); |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_data, 4); |
| // Sets data_buffer[0] to set 0 |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| // Sets data_buffer[1] to set 1 |
| get_info.address_info.address += alignment; |
| mapped_descriptor_data += ds_layout_size; |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| // Sets data_buffer[2] to set 2 |
| get_info.address_info.address += alignment; |
| mapped_descriptor_data += ds_layout_size; |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| }; |
| layout (set = 1, binding = 0) buffer SSBO_1 { |
| uint b; |
| }; |
| layout (set = 2, binding = 0) buffer SSBO_2 { |
| uint c; |
| }; |
| |
| void main() { |
| c = a + b; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index[3] = {0, 0, 0}; |
| VkDeviceSize buffer_offset[3] = {0, ds_layout_size, ds_layout_size * 2}; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 3, buffer_index, |
| buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| if (!IsPlatformMockICD()) { |
| ASSERT_TRUE(data[offset_2] == 20); |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, MultipleBinding) { |
| TEST_DESCRIPTION("Have a single VkBuffer of data spread across 3 different bindings in the same set."); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| const uint32_t alignment = static_cast<uint32_t>(m_device->Physical().limits_.minStorageBufferOffsetAlignment); |
| const uint32_t offset_0 = 0; |
| const uint32_t offset_1 = alignment / sizeof(uint32_t); |
| const uint32_t offset_2 = offset_1 * 2; |
| vkt::Buffer buffer_data(*m_device, 4096, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| uint32_t *data = (uint32_t *)buffer_data.Memory().Map(); |
| data[offset_0] = 8; |
| data[offset_1] = 12; |
| data[offset_2] = 1; |
| |
| std::vector<VkDescriptorSetLayoutBinding> bindings = {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, bindings, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_data, 4); |
| uint8_t *mapped_descriptor_data = (uint8_t *)descriptor_buffer.Memory().Map(); |
| // Sets data_buffer[0] to binding 0 |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(0)); |
| |
| // Sets data_buffer[1] to binding 1 |
| get_info.address_info.address += alignment; |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(1)); |
| |
| // Sets data_buffer[2] to binding 2 |
| get_info.address_info.address += alignment; |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(2)); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| }; |
| layout (set = 0, binding = 1) buffer SSBO_1 { |
| uint b; |
| }; |
| layout (set = 0, binding = 2) buffer SSBO_2 { |
| uint c; |
| }; |
| |
| void main() { |
| c = a + b; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| if (!IsPlatformMockICD()) { |
| ASSERT_TRUE(data[offset_0] == 8); |
| ASSERT_TRUE(data[offset_1] == 12); |
| ASSERT_TRUE(data[offset_2] == 20); |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, DescriptorIndexing) { |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| vkt::Buffer buffer_0(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer buffer_1(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer buffer_2(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| uint32_t *data = (uint32_t *)buffer_0.Memory().Map(); |
| data[0] = 8; |
| data = (uint32_t *)buffer_1.Memory().Map(); |
| data[0] = 12; |
| data = (uint32_t *)buffer_2.Memory().Map(); |
| data[0] = 1; |
| |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3, VK_SHADER_STAGE_ALL, nullptr}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| size_t descriptor_size = descriptor_buffer_properties.storageBufferDescriptorSize; |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_0, 16); |
| uint8_t *mapped_descriptor_data = (uint8_t *)descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_size, mapped_descriptor_data); |
| |
| get_info.address_info.address = buffer_1.Address(); |
| mapped_descriptor_data += descriptor_size; |
| vk::GetDescriptorEXT(device(), get_info, descriptor_size, mapped_descriptor_data); |
| |
| get_info.address_info.address = buffer_2.Address(); |
| mapped_descriptor_data += descriptor_size; |
| vk::GetDescriptorEXT(device(), get_info, descriptor_size, mapped_descriptor_data); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| } x[3]; |
| |
| void main() { |
| x[2].data = x[0].data + x[1].data; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| if (!IsPlatformMockICD()) { |
| ASSERT_TRUE(data[0] == 20); |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, BindingInfoUsage2) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9228"); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance5); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| VkBufferUsageFlags2CreateInfo buffer_usage_flags = vku::InitStructHelper(); |
| buffer_usage_flags.usage = VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; |
| |
| VkBufferCreateInfo buffer_ci = vku::InitStructHelper(&buffer_usage_flags); |
| buffer_ci.size = 4096; |
| |
| VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper(); |
| allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| |
| vkt::Buffer buffer(*m_device, buffer_ci, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, |
| &allocate_flag_info); |
| |
| VkDescriptorBufferBindingInfoEXT dbbi = vku::InitStructHelper(); |
| dbbi.address = buffer.Address(); |
| dbbi.usage = VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &dbbi); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, DescriptorBufferBindingInfoUsage2) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9228"); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance5); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| VkBufferUsageFlags2CreateInfo buffer_usage_flags = vku::InitStructHelper(); |
| buffer_usage_flags.usage = VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| VkDescriptorBufferBindingInfoEXT dbbi = vku::InitStructHelper(&buffer_usage_flags); |
| dbbi.address = buffer.Address(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &dbbi); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, TexelBuffer) { |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| vkt::Buffer storage_buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, vkt::device_address); |
| vkt::BufferView storage_buffer_view(*m_device, storage_buffer, VK_FORMAT_R32_UINT); |
| vkt::Buffer uniform_buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, vkt::device_address); |
| vkt::BufferView uniform_buffer_view(*m_device, uniform_buffer, VK_FORMAT_R32_UINT); |
| |
| uint32_t *data = (uint32_t *)uniform_buffer.Memory().Map(); |
| data[0] = 8; |
| data[1] = 12; |
| data[2] = 1; |
| data[3] = 4; |
| |
| std::vector<VkDescriptorSetLayoutBinding> bindings = { |
| {0, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, bindings, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| vkt::DescriptorGetInfo get_info_s(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, storage_buffer, 32, VK_FORMAT_R32_UINT); |
| uint8_t *mapped_descriptor_data = (uint8_t *)descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info_s, descriptor_buffer_properties.storageTexelBufferDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(0)); |
| |
| vkt::DescriptorGetInfo get_info_u(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, uniform_buffer, 32, VK_FORMAT_R32_UINT); |
| vk::GetDescriptorEXT(device(), get_info_u, descriptor_buffer_properties.uniformTexelBufferDescriptorSize, |
| mapped_descriptor_data + ds_layout.GetDescriptorBufferBindingOffset(1)); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0, r32ui) uniform uimageBuffer s_buffer; |
| layout(set = 0, binding = 1) uniform usamplerBuffer u_buffer; |
| |
| void main() { |
| imageStore(s_buffer, 0, texelFetch(u_buffer, 0)); |
| imageStore(s_buffer, 1, texelFetch(u_buffer, 1)); |
| imageStore(s_buffer, 2, texelFetch(u_buffer, 2)); |
| imageStore(s_buffer, 3, texelFetch(u_buffer, 3)); |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| data = (uint32_t *)storage_buffer.Memory().Map(); |
| if (!IsPlatformMockICD()) { |
| ASSERT_TRUE(data[0] == 8); |
| ASSERT_TRUE(data[1] == 12); |
| ASSERT_TRUE(data[2] == 1); |
| ASSERT_TRUE(data[3] == 4); |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, BindingOffsets) { |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| // Will write "42" to offset[0], [64], and [256] |
| vkt::Buffer buffer_data(*m_device, 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size * 3, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_data, 16); |
| |
| uint8_t *mapped_descriptor_data = (uint8_t *)descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| get_info.address_info.address += 64; |
| mapped_descriptor_data += ds_layout_size; |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| get_info.address_info.address += (256 - 64); |
| mapped_descriptor_data += ds_layout_size; |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint data; |
| }; |
| void main() { |
| data = 42; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| buffer_offset += ds_layout_size; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| buffer_offset += ds_layout_size; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| uint32_t *data = (uint32_t *)buffer_data.Memory().Map(); |
| if (!IsPlatformMockICD()) { |
| ASSERT_TRUE(data[0] == 42); // [0] |
| ASSERT_TRUE(data[16] == 42); // [64] |
| ASSERT_TRUE(data[64] == 42); // [256] |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, ShaderObject) { |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| vkt::Buffer buffer_data(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| uint32_t *data = (uint32_t *)buffer_data.Memory().Map(); |
| data[0] = 8; |
| data[1] = 12; |
| data[2] = 1; |
| |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| vkt::DescriptorSetLayout ds_layout(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_data, 16); |
| void *mapped_descriptor_data = descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| uint b; |
| uint c; |
| }; |
| |
| void main() { |
| c = a + b; |
| } |
| )glsl"; |
| |
| const vkt::Shader cs(*m_device, VK_SHADER_STAGE_COMPUTE_BIT, GLSLToSPV(VK_SHADER_STAGE_COMPUTE_BIT, cs_source), |
| &ds_layout.handle()); |
| |
| m_command_buffer.Begin(); |
| const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_COMPUTE_BIT}; |
| vk::CmdBindShadersEXT(m_command_buffer, 1, stages, &cs.handle()); |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| uint32_t buffer_index = 0; |
| VkDeviceSize buffer_offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &buffer_index, |
| &buffer_offset); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| if (!IsPlatformMockICD()) { |
| ASSERT_TRUE(data[0] == 8); |
| ASSERT_TRUE(data[1] == 12); |
| ASSERT_TRUE(data[2] == 20); |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, NotInvalidatedLegacy) { |
| TEST_DESCRIPTION("Case 3 from https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/7504#note_549388"); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| vkt::Buffer legacy_buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| OneOffDescriptorSet legacy_ds(m_device, {binding}); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&legacy_ds.layout_}); |
| legacy_ds.WriteDescriptorBufferInfo(0, legacy_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| legacy_ds.UpdateDescriptorSets(); |
| |
| vkt::Buffer buffer_data(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::DescriptorSetLayout ds_layout(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| |
| VkDeviceSize ds_layout_size = ds_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_data, 16); |
| |
| void *mapped_descriptor_data = descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { uint x; }; |
| void main() { |
| x = 0; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| 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, &legacy_ds.set_, 0, nullptr); |
| |
| // Does not invalidate the legacy by itself |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, MeshShader) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| AddRequiredFeature(vkt::Feature::taskShader); |
| AddRequiredFeature(vkt::Feature::descriptorBindingPartiallyBound); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| const char *mesh_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| layout(max_vertices = 3, max_primitives=1) out; |
| layout(triangles) out; |
| layout(set=0, binding=0) buffer Buffer { |
| uint vertexCount; |
| uint primitiveCount; |
| uint padding; |
| uint sum; |
| } count; |
| void main() { |
| SetMeshOutputsEXT(count.vertexCount, count.primitiveCount); |
| count.sum = count.vertexCount + count.primitiveCount; |
| } |
| )glsl"; |
| |
| VkShaderObj ms(*m_device, mesh_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2); |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_MESH_BIT_EXT, nullptr}; |
| |
| const VkDescriptorBindingFlags ds_binding_flags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; |
| |
| VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper(); |
| flags_create_info.bindingCount = 1u; |
| flags_create_info.pBindingFlags = &ds_binding_flags; |
| |
| VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(&flags_create_info); |
| ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| ds_layout_ci.bindingCount = 1u; |
| ds_layout_ci.pBindings = &binding; |
| vkt::DescriptorSetLayout ds_layout(*m_device, ds_layout_ci); |
| |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout}); |
| |
| vkt::Buffer buffer(*m_device, sizeof(uint32_t) * 4u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| uint32_t *data = (uint32_t *)buffer.Memory().Map(); |
| data[0] = 3u; |
| data[1] = 1u; |
| vkt::Buffer descriptor_buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| uint8_t *descriptor_data = reinterpret_cast<uint8_t *>(descriptor_buffer.Memory().Map()); |
| VkDeviceSize buffer_offset = ds_layout.GetDescriptorBufferBindingOffset(0); |
| |
| vkt::DescriptorGetInfo buffer_get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer, buffer.CreateInfo().size); |
| vk::GetDescriptorEXT(*m_device, buffer_get_info, descriptor_buffer_properties.storageBufferDescriptorSize, |
| descriptor_data + buffer_offset); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.shader_stages_ = {ms.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.pVertexInputState = nullptr; |
| pipe.gp_ci_.pInputAssemblyState = nullptr; |
| pipe.CreateGraphicsPipeline(); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = descriptor_buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| uint32_t buffer_index = 0u; |
| VkDeviceSize offset = 0u; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 1u, &buffer_index, |
| &offset); |
| vk::CmdDrawMeshTasksEXT(m_command_buffer, 1, 1, 1); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| if (!IsPlatformMockICD()) { |
| ASSERT_EQ(data[0] + data[1], data[3]); |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, GraphicsPipelineLibrary) { |
| AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| const VkDescriptorSetLayoutBinding binding1 = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}; |
| const VkDescriptorSetLayoutBinding binding2 = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}; |
| |
| VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(); |
| ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| ds_layout_ci.bindingCount = 1u; |
| ds_layout_ci.pBindings = &binding1; |
| vkt::DescriptorSetLayout ds_layout1(*m_device, ds_layout_ci); |
| ds_layout_ci.pBindings = &binding2; |
| vkt::DescriptorSetLayout ds_layout2(*m_device, ds_layout_ci); |
| |
| vkt::PipelineLayout pipeline_layout_vs(*m_device, {&ds_layout1, &ds_layout1, nullptr}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_fs(*m_device, {&ds_layout1, nullptr, &ds_layout2}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_null(*m_device, {&ds_layout1, nullptr, nullptr}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer descriptor_buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| uint8_t *descriptor_data = reinterpret_cast<uint8_t *>(descriptor_buffer.Memory().Map()); |
| VkDeviceSize buffer_offset = ds_layout1.GetDescriptorBufferBindingOffset(0); |
| |
| vkt::DescriptorGetInfo buffer_get_info(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniform_buffer, uniform_buffer.CreateInfo().size); |
| vk::GetDescriptorEXT(*m_device, buffer_get_info, descriptor_buffer_properties.uniformBufferDescriptorSize, |
| descriptor_data + buffer_offset); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const char vs_src[] = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform foo { float x; } bar; |
| void main() { |
| gl_Position = vec4(bar.x); |
| } |
| )glsl"; |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_src); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.gp_ci_.layout = pipeline_layout_vs; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = pipeline_layout_fs; |
| 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.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| exe_pipe_ci.layout = pipeline_layout_null; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| ASSERT_TRUE(exe_pipe.initialized()); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = descriptor_buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| // Draw with pipeline created with null set |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| uint32_t buffer_index = 0u; |
| VkDeviceSize offset = 0u; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_null, 0u, 1u, |
| &buffer_index, &offset); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, GraphicsPipelineLibraryIndependent) { |
| AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| const VkDescriptorSetLayoutBinding binding1 = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}; |
| const VkDescriptorSetLayoutBinding binding2 = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}; |
| |
| VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(); |
| ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| ds_layout_ci.bindingCount = 1u; |
| ds_layout_ci.pBindings = &binding1; |
| vkt::DescriptorSetLayout ds_layout1(*m_device, ds_layout_ci); |
| ds_layout_ci.pBindings = &binding2; |
| vkt::DescriptorSetLayout ds_layout2(*m_device, ds_layout_ci); |
| |
| vkt::Buffer uniform_buffer(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer descriptor_buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| uint8_t *descriptor_data = reinterpret_cast<uint8_t *>(descriptor_buffer.Memory().Map()); |
| VkDeviceSize buffer_offset = ds_layout1.GetDescriptorBufferBindingOffset(0); |
| |
| vkt::DescriptorGetInfo buffer_get_info(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniform_buffer, uniform_buffer.CreateInfo().size); |
| vk::GetDescriptorEXT(*m_device, buffer_get_info, descriptor_buffer_properties.uniformBufferDescriptorSize, |
| descriptor_data + buffer_offset); |
| |
| vkt::PipelineLayout pipeline_layout_vs(*m_device, {&ds_layout1, &ds_layout1, nullptr}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_fs(*m_device, {&ds_layout1, nullptr, &ds_layout2}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| vkt::PipelineLayout pipeline_layout_link(*m_device, {&ds_layout1, &ds_layout1, &ds_layout2}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| |
| vkt::PipelineLayout pipeline_layout_ds(*m_device, {&ds_layout1, &ds_layout1, &ds_layout2}, {}, |
| VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); |
| |
| CreatePipelineHelper vertex_input_lib(*this); |
| vertex_input_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| vertex_input_lib.InitVertexInputLibInfo(); |
| vertex_input_lib.CreateGraphicsPipeline(false); |
| |
| CreatePipelineHelper pre_raster_lib(*this); |
| { |
| const char vs_src[] = R"glsl( |
| #version 450 |
| layout(set=0, binding=0) uniform foo { float x; } bar; |
| void main() { |
| gl_Position = vec4(bar.x); |
| } |
| )glsl"; |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_src); |
| vkt::GraphicsPipelineLibraryStage vs_stage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| pre_raster_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pre_raster_lib.InitPreRasterLibInfo(&vs_stage.stage_ci); |
| pre_raster_lib.gp_ci_.layout = pipeline_layout_vs; |
| pre_raster_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_shader_lib(*this); |
| { |
| const auto fs_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| vkt::GraphicsPipelineLibraryStage fs_stage(fs_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| frag_shader_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| frag_shader_lib.InitFragmentLibInfo(&fs_stage.stage_ci); |
| frag_shader_lib.gp_ci_.layout = pipeline_layout_fs; |
| frag_shader_lib.CreateGraphicsPipeline(false); |
| } |
| |
| CreatePipelineHelper frag_out_lib(*this); |
| frag_out_lib.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| 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.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| exe_pipe_ci.layout = pipeline_layout_link; |
| vkt::Pipeline exe_pipe(*m_device, exe_pipe_ci); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = descriptor_buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, exe_pipe); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| uint32_t buffer_index = 0u; |
| VkDeviceSize offset = 0u; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_ds, 0u, 1u, |
| &buffer_index, &offset); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, EmbeddedSamplers) { |
| TEST_DESCRIPTION("Bind descriptor buffer and set descriptor offset then draw."); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| const char *fsSource = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) uniform sampler samp; |
| layout(set = 1, binding = 0) uniform texture2D tex; |
| layout(location=0) out vec4 color; |
| void main() { |
| color = texture(sampler2D(tex, samp), vec2(0.5f)); |
| } |
| )glsl"; |
| VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| vkt::Buffer result_buffer(*m_device, sizeof(float) * 4u, VK_BUFFER_USAGE_TRANSFER_DST_BIT, kHostVisibleMemProps); |
| vkt::Image image(*m_device, 32u, 32u, VK_FORMAT_R32G32B32A32_SFLOAT, |
| VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); |
| image.SetLayout(VK_IMAGE_LAYOUT_GENERAL); |
| vkt::ImageView image_view = image.CreateView(); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| const VkDescriptorSetLayoutBinding sampler_binding = {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, |
| &sampler.handle()}; |
| const VkDescriptorSetLayoutBinding image_binding = {0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, |
| nullptr}; |
| |
| VkDescriptorSetLayoutCreateInfo sampler_ds_layout_ci = vku::InitStructHelper(); |
| sampler_ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT | |
| VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT; |
| sampler_ds_layout_ci.bindingCount = 1u; |
| sampler_ds_layout_ci.pBindings = &sampler_binding; |
| vkt::DescriptorSetLayout sampler_ds_layout(*m_device, sampler_ds_layout_ci); |
| |
| VkDescriptorSetLayoutCreateInfo image_ds_layout_ci = vku::InitStructHelper(); |
| image_ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| image_ds_layout_ci.bindingCount = 1u; |
| image_ds_layout_ci.pBindings = &image_binding; |
| vkt::DescriptorSetLayout image_ds_layout(*m_device, image_ds_layout_ci); |
| |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&sampler_ds_layout, &image_ds_layout}); |
| |
| vkt::Buffer descriptor_buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| uint8_t *descriptor_data = reinterpret_cast<uint8_t *>(descriptor_buffer.Memory().Map()); |
| VkDeviceSize buffer_offset = image_ds_layout.GetDescriptorBufferBindingOffset(0); |
| |
| vkt::DescriptorGetInfo image_get_info(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_NULL_HANDLE, image_view, VK_IMAGE_LAYOUT_GENERAL); |
| vk::GetDescriptorEXT(*m_device, image_get_info, descriptor_buffer_properties.sampledImageDescriptorSize, |
| descriptor_data + buffer_offset); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = descriptor_buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| VkClearColorValue clear_color_value; |
| clear_color_value.float32[0] = 0.2f; |
| clear_color_value.float32[1] = 0.4f; |
| clear_color_value.float32[2] = 0.6f; |
| clear_color_value.float32[3] = 0.8f; |
| |
| m_command_buffer.Begin(); |
| VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}; |
| vk::CmdClearColorImage(m_command_buffer, image, VK_IMAGE_LAYOUT_GENERAL, &clear_color_value, 1u, &range); |
| |
| VkMemoryBarrier memory_barrier_1 = vku::InitStructHelper(); |
| memory_barrier_1.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
| memory_barrier_1.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; |
| vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 1u, |
| &memory_barrier_1, 0u, nullptr, 0u, nullptr); |
| |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| uint32_t buffer_index = 0u; |
| VkDeviceSize offset = buffer_offset; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 1u, 1u, &buffer_index, |
| &offset); |
| vk::CmdBindDescriptorBufferEmbeddedSamplersEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| |
| VkMemoryBarrier memory_barrier_2 = vku::InitStructHelper(); |
| memory_barrier_2.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; |
| memory_barrier_2.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
| vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 1u, |
| &memory_barrier_2, 0u, nullptr, 0u, nullptr); |
| |
| VkBufferImageCopy region = {}; |
| region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u}; |
| region.imageExtent = {1u, 1u, 1u}; |
| vk::CmdCopyImageToBuffer(m_command_buffer, image, VK_IMAGE_LAYOUT_GENERAL, result_buffer, 1, ®ion); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| float *data = (float *)result_buffer.Memory().Map(); |
| if (!IsPlatformMockICD()) { |
| for (uint32_t i = 0; i < 4; i++) { |
| ASSERT_NEAR(data[i], clear_color_value.float32[i], 0.0001f); |
| } |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, InputAttachment) { |
| TEST_DESCRIPTION("Test reading from a descriptor that uses same image view as framebuffer input attachment"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; |
| |
| RenderPassSingleSubpass rp(*this); |
| rp.AddAttachmentDescription(format, VK_IMAGE_LAYOUT_UNDEFINED); |
| rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL}); |
| rp.AddInputAttachment(0); |
| rp.CreateRenderPass(); |
| |
| auto image_create_info = |
| vkt::Image::ImageCreateInfo2D(32, 32, 1, 3, format, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT); |
| vkt::Image image(*m_device, image_create_info, vkt::set_layout); |
| vkt::ImageView image_view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D, 0, 1, 0, 1); |
| VkImageView image_view_handle = image_view; |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| vkt::Framebuffer framebuffer(*m_device, rp, 1, &image_view_handle); |
| |
| const char *fsSource = R"glsl( |
| #version 450 |
| layout(location = 0) out vec4 color; |
| layout(set = 0, binding = 0, rgba8) readonly uniform image2D image1; |
| layout(set = 1, binding = 0, input_attachment_index = 0) uniform subpassInput inputColor; |
| void main(){ |
| color = subpassLoad(inputColor) + imageLoad(image1, ivec2(0)); |
| } |
| )glsl"; |
| |
| VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}; |
| |
| VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(); |
| ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| ds_layout_ci.bindingCount = 1u; |
| ds_layout_ci.pBindings = &binding; |
| vkt::DescriptorSetLayout descriptor_set_layout(*m_device, ds_layout_ci); |
| binding.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; |
| vkt::DescriptorSetLayout descriptor_set_layout2(*m_device, ds_layout_ci); |
| |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set_layout, &descriptor_set_layout2}); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.shader_stages_[1] = fs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.gp_ci_.renderPass = rp; |
| pipe.CreateGraphicsPipeline(); |
| |
| vkt::Buffer descriptor_buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| uint8_t *descriptor_data = reinterpret_cast<uint8_t *>(descriptor_buffer.Memory().Map()); |
| VkDeviceSize image_offset = descriptor_set_layout.GetDescriptorBufferBindingOffset(0); |
| VkDeviceSize input_attachment_offset = |
| descriptor_set_layout2.GetDescriptorBufferBindingOffset(0) + descriptor_buffer_properties.storageImageDescriptorSize; |
| |
| vkt::DescriptorGetInfo image_get_info(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, sampler, image_view, VK_IMAGE_LAYOUT_GENERAL); |
| vk::GetDescriptorEXT(*m_device, image_get_info, descriptor_buffer_properties.storageImageDescriptorSize, |
| descriptor_data + image_offset); |
| vkt::DescriptorGetInfo input_attachment_get_info(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, sampler, image_view, |
| VK_IMAGE_LAYOUT_GENERAL); |
| vk::GetDescriptorEXT(*m_device, input_attachment_get_info, descriptor_buffer_properties.inputAttachmentDescriptorSize, |
| descriptor_data + input_attachment_offset); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(rp, framebuffer, 32, 32, 1, m_renderPassClearValues.data()); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = descriptor_buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| uint32_t buffer_index = 0u; |
| VkDeviceSize offset = 0u; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 1u, &buffer_index, |
| &offset); |
| |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, ImageLayoutIgnored) { |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| AddRequiredFeature(vkt::Feature::descriptorBufferImageLayoutIgnored); |
| InitRenderTarget(); |
| |
| const VkFormat format = FindSupportedDepthStencilFormat(gpu_); |
| |
| auto image_create_info = vkt::Image::ImageCreateInfo2D(32, 32, 1, 3, format, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image image(*m_device, image_create_info, vkt::set_layout); |
| vkt::ImageView image_view = |
| image.CreateView(VK_IMAGE_VIEW_TYPE_2D, 0, 1, 0, 1, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| const char *fs_source = R"glsl( |
| #version 450 |
| layout(location = 0) out vec4 color; |
| layout(set = 0, binding = 0) uniform sampler s; |
| layout(set = 0, binding = 1) uniform texture2D t; |
| void main(){ |
| color = texture(sampler2D(t, s), vec2(0)); |
| } |
| )glsl"; |
| |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| std::vector<VkDescriptorSetLayoutBinding> bindings = {{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}}; |
| |
| VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper(); |
| ds_layout_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| ds_layout_ci.bindingCount = bindings.size(); |
| ds_layout_ci.pBindings = bindings.data(); |
| vkt::DescriptorSetLayout descriptor_set_layout(*m_device, ds_layout_ci); |
| |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set_layout}); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.shader_stages_[1] = fs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| vkt::Buffer descriptor_buffer( |
| *m_device, 4096, VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, |
| vkt::device_address); |
| uint8_t *descriptor_data = reinterpret_cast<uint8_t *>(descriptor_buffer.Memory().Map()); |
| |
| vkt::DescriptorGetInfo get_info_sampler(&sampler.handle()); |
| vk::GetDescriptorEXT(device(), get_info_sampler, descriptor_buffer_properties.samplerDescriptorSize, |
| descriptor_data + descriptor_set_layout.GetDescriptorBufferBindingOffset(0)); |
| |
| vkt::DescriptorGetInfo get_info_image(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_NULL_HANDLE, image_view, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
| vk::GetDescriptorEXT(device(), get_info_image, descriptor_buffer_properties.sampledImageDescriptorSize, |
| descriptor_data + descriptor_set_layout.GetDescriptorBufferBindingOffset(1)); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = descriptor_buffer.Address(); |
| buffer_binding_info.usage = |
| VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| uint32_t buffer_index = 0u; |
| VkDeviceSize offset = 0u; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 1u, &buffer_index, |
| &offset); |
| |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, ComputeAndGraphics) { |
| AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| vkt::Buffer buffer1(*m_device, sizeof(float) * 4u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer buffer2(*m_device, sizeof(float) * 4u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| |
| vkt::Buffer descriptor_buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = descriptor_buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, |
| VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT, nullptr}; |
| const vkt::DescriptorSetLayout set_layout(*m_device, {binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&set_layout}); |
| |
| vkt::DescriptorGetInfo get_info1(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer1, 16u); |
| vkt::DescriptorGetInfo get_info2(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer2, 16u); |
| |
| const VkDeviceSize offset1 = 0; |
| VkDeviceSize offset2 = descriptor_buffer_properties.storageBufferDescriptorSize; |
| if (offset2 % descriptor_buffer_properties.descriptorBufferOffsetAlignment != 0) { |
| offset2 += descriptor_buffer_properties.descriptorBufferOffsetAlignment - |
| (offset2 % descriptor_buffer_properties.descriptorBufferOffsetAlignment); |
| } |
| |
| uint8_t *mapped_descriptor_data = (uint8_t*)descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info1, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data + offset1); |
| vk::GetDescriptorEXT(device(), get_info2, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data + offset2); |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer Buf { |
| vec4 data; |
| } buf; |
| void main() { |
| vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1)); |
| gl_Position = vec4(pos, 0.0f, 1.0f); |
| buf.data[gl_VertexIndex] = 1.0f; |
| } |
| )glsl"; |
| |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.shader_stages_[0] = vs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer Buf { |
| vec4 data; |
| } buf; |
| |
| void main() { |
| buf.data.x = gl_LocalInvocationIndex + 1.0f; |
| buf.data.y = gl_LocalInvocationIndex + 2.0f; |
| buf.data.z = gl_LocalInvocationIndex + 3.0f; |
| buf.data.w = gl_LocalInvocationIndex + 4.0f; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe2(*this); |
| pipe2.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe2.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe2.cp_ci_.layout = pipeline_layout; |
| pipe2.CreateComputePipeline(); |
| |
| const uint32_t index = 0; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &index, &offset1); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe2); |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &index, &offset2); |
| vk::CmdDispatch(m_command_buffer, 1u, 1u, 1u); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| float *data1 = (float *)buffer1.Memory().Map(); |
| float *data2 = (float *)buffer2.Memory().Map(); |
| if (!IsPlatformMockICD()) { |
| for (uint32_t i = 0; i < 4; i++) { |
| ASSERT_EQ(data1[i], 1.0f); |
| ASSERT_EQ(data2[i], float(i + 1)); |
| } |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, ComputeAndGraphics2) { |
| AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| vkt::Buffer buffer(*m_device, sizeof(float) * 8u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| |
| vkt::Buffer descriptor_buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = descriptor_buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, |
| VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_COMPUTE_BIT, nullptr}; |
| const vkt::DescriptorSetLayout set_layout(*m_device, {binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&set_layout, &set_layout}); |
| |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer, 32u); |
| |
| uint8_t *mapped_descriptor_data = (uint8_t *)descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, |
| mapped_descriptor_data); |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer Buf { |
| vec4 data[2]; |
| } buf; |
| void main() { |
| vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1)); |
| gl_Position = vec4(pos, 0.0f, 1.0f); |
| buf.data[0][gl_VertexIndex] = 1.0f; |
| } |
| )glsl"; |
| |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.shader_stages_[0] = vs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 1, binding = 0) buffer Buf { |
| vec4 data[2]; |
| } buf; |
| |
| void main() { |
| buf.data[1].x = gl_LocalInvocationIndex + 1.0f; |
| buf.data[1].y = gl_LocalInvocationIndex + 2.0f; |
| buf.data[1].z = gl_LocalInvocationIndex + 3.0f; |
| buf.data[1].w = gl_LocalInvocationIndex + 4.0f; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe2(*this); |
| pipe2.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe2.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe2.cp_ci_.layout = pipeline_layout; |
| pipe2.CreateComputePipeline(); |
| |
| const uint32_t index = 0; |
| const VkDeviceSize offset = 0; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &index, |
| &offset); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe2); |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 1, 1, &index, &offset); |
| vk::CmdDispatch(m_command_buffer, 1u, 1u, 1u); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| float *data = (float *)buffer.Memory().Map(); |
| if (!IsPlatformMockICD()) { |
| for (uint32_t i = 0; i < 4; i++) { |
| ASSERT_EQ(data[i], 1.0f); |
| ASSERT_EQ(data[i + 4], float(i + 1)); |
| } |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, PushDescriptor) { |
| AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorBufferPushDescriptors); |
| AddRequiredFeature(vkt::Feature::pushDescriptor); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| vkt::Buffer buffer_data0(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer buffer_data1(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| uint32_t *data = (uint32_t *)buffer_data0.Memory().Map(); |
| data[0] = 8; |
| data[1] = 12; |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| vkt::DescriptorSetLayout descriptor_set(*m_device, {binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| vkt::DescriptorSetLayout descriptor_set_push( |
| *m_device, {binding}, |
| VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT | VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set, &descriptor_set_push}); |
| |
| VkDeviceSize ds_layout_size = descriptor_set.GetDescriptorBufferSize(); |
| ds_layout_size = std::max(ds_layout_size, descriptor_buffer_properties.descriptorBufferOffsetAlignment); |
| VkBufferUsageFlags descriptor_buffer_usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| if (!descriptor_buffer_properties.bufferlessPushDescriptors) { |
| descriptor_buffer_usage |= VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT; |
| } |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size, descriptor_buffer_usage, vkt::device_address); |
| |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer_data0, 16); |
| void *mapped_descriptor_data = descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| uint b; |
| }; |
| layout (set = 1, binding = 0) buffer SSBO_1 { |
| uint c; |
| }; |
| |
| void main() { |
| c = a + b; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferBindingPushDescriptorBufferHandleEXT descriptor_buffer_push_descriptor_buffer_handle = |
| vku::InitStructHelper(); |
| descriptor_buffer_push_descriptor_buffer_handle.buffer = descriptor_buffer; |
| |
| VkDescriptorBufferBindingInfoEXT descriptor_buffer_binding_info = vku::InitStructHelper(); |
| descriptor_buffer_binding_info.address = descriptor_buffer.Address(); |
| descriptor_buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| if (!descriptor_buffer_properties.bufferlessPushDescriptors) { |
| descriptor_buffer_binding_info.pNext = &descriptor_buffer_push_descriptor_buffer_handle; |
| descriptor_buffer_binding_info.usage |= VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT; |
| } |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &descriptor_buffer_binding_info); |
| |
| const uint32_t index = 0; |
| const VkDeviceSize offset = 0; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &index, &offset); |
| |
| VkDescriptorBufferInfo buffer_info = {buffer_data1, 0, VK_WHOLE_SIZE}; |
| VkWriteDescriptorSet descriptor_write = vku::InitStructHelper(); |
| descriptor_write.dstSet = VK_NULL_HANDLE; |
| descriptor_write.dstBinding = 0u; |
| descriptor_write.dstArrayElement = 0u; |
| descriptor_write.descriptorCount = 1u; |
| descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
| descriptor_write.pBufferInfo = &buffer_info; |
| vk::CmdPushDescriptorSetKHR(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 1u, 1u, &descriptor_write); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| if (!IsPlatformMockICD()) { |
| data = (uint32_t *)buffer_data1.Memory().Map(); |
| ASSERT_TRUE(data[0] == 20); |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, PushDescriptorOnly) { |
| AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorBufferPushDescriptors); |
| AddRequiredFeature(vkt::Feature::pushDescriptor); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| |
| vkt::Buffer buffer_data(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| uint32_t *data = (uint32_t *)buffer_data.Memory().Map(); |
| data[0] = 8; |
| data[1] = 12; |
| data[2] = 1; |
| |
| OneOffDescriptorSet descriptor_set( |
| m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }, |
| VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT | VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR); |
| vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| const char *cs_source = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer SSBO_0 { |
| uint a; |
| uint b; |
| uint c; |
| }; |
| |
| void main() { |
| c = a + b; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2); |
| pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| |
| VkDescriptorBufferInfo buffer_info = {buffer_data, 0, VK_WHOLE_SIZE}; |
| VkWriteDescriptorSet descriptor_write = vku::InitStructHelper(); |
| descriptor_write.dstSet = VK_NULL_HANDLE; |
| descriptor_write.dstBinding = 0u; |
| descriptor_write.dstArrayElement = 0u; |
| descriptor_write.descriptorCount = 1u; |
| descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
| descriptor_write.pBufferInfo = &buffer_info; |
| vk::CmdPushDescriptorSetKHR(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0u, 1u, &descriptor_write); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| if (!IsPlatformMockICD()) { |
| ASSERT_TRUE(data[2] == 20); |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, DeviceLocal) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics); |
| AddRequiredFeature(vkt::Feature::synchronization2); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| const uint32_t descriptor_buffer_size = 4096u; |
| |
| vkt::Buffer buffer(*m_device, sizeof(float) * 4u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer src_descriptor_buffer(*m_device, descriptor_buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, |
| VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); |
| VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper(); |
| allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; |
| vkt::Buffer device_local_descriptor_buffer(*m_device, 4096, |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | |
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, |
| VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocate_flag_info); |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}; |
| const vkt::DescriptorSetLayout set_layout(*m_device, {binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&set_layout}); |
| |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer, 16u); |
| |
| const VkDeviceSize offset = 0; |
| |
| uint8_t *mapped_descriptor_data = (uint8_t *)src_descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer Buf { |
| vec4 data; |
| } buf; |
| void main() { |
| vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1)); |
| gl_Position = vec4(pos, 0.0f, 1.0f); |
| buf.data[gl_VertexIndex] = 1.0f; |
| } |
| )glsl"; |
| |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.shader_stages_[0] = vs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| const uint32_t index = 0; |
| |
| VkBufferCopy buffer_copy = {}; |
| buffer_copy.srcOffset = 0u; |
| buffer_copy.dstOffset = 0u; |
| buffer_copy.size = descriptor_buffer_size; |
| |
| VkBufferMemoryBarrier2 buffer_memory_barrier = vku::InitStructHelper(); |
| buffer_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
| buffer_memory_barrier.dstAccessMask = VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT; |
| buffer_memory_barrier.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; |
| buffer_memory_barrier.dstStageMask = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT; |
| buffer_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| buffer_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| buffer_memory_barrier.buffer = device_local_descriptor_buffer; |
| buffer_memory_barrier.offset = 0u; |
| buffer_memory_barrier.size = descriptor_buffer_size; |
| |
| VkDependencyInfo dependency_info = vku::InitStructHelper(); |
| dependency_info.bufferMemoryBarrierCount = 1u; |
| dependency_info.pBufferMemoryBarriers = &buffer_memory_barrier; |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = device_local_descriptor_buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| m_command_buffer.Begin(); |
| vk::CmdCopyBuffer(m_command_buffer, src_descriptor_buffer, device_local_descriptor_buffer, 1u, &buffer_copy); |
| vk::CmdPipelineBarrier2(m_command_buffer, &dependency_info); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &index, &offset); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| float *data = (float *)buffer.Memory().Map(); |
| if (!IsPlatformMockICD()) { |
| for (uint32_t i = 0; i < 4; i++) { |
| ASSERT_EQ(data[i], 1.0f); |
| } |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, DestroyDescriptor) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics); |
| AddRequiredFeature(vkt::Feature::synchronization2); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| vkt::Buffer buffer(*m_device, sizeof(float) * 4u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer descriptor_buffer(*m_device, 4096u, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}; |
| vkt::DescriptorSetLayout set_layout(*m_device, {binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&set_layout}); |
| |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer, 16u); |
| |
| const VkDeviceSize offset = 0; |
| |
| uint8_t *mapped_descriptor_data = (uint8_t *)descriptor_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_descriptor_data); |
| |
| buffer.Destroy(); |
| set_layout.Destroy(); |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout (set = 0, binding = 0) buffer Buf { |
| vec4 data; |
| } buf; |
| void main() { |
| vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1)); |
| gl_Position = vec4(pos, 0.0f, 1.0f); |
| buf.data[gl_VertexIndex] = 1.0f; |
| } |
| )glsl"; |
| |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.shader_stages_[0] = vs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| const uint32_t index = 0; |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = descriptor_buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &index, &offset); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| float *data = (float *)buffer.Memory().Map(); |
| if (!IsPlatformMockICD()) { |
| for (uint32_t i = 0; i < 4; i++) { |
| ASSERT_EQ(data[i], 1.0f); |
| } |
| } |
| } |
| |
| TEST_F(PositiveDescriptorBuffer, SharedSet) { |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics); |
| AddRequiredFeature(vkt::Feature::synchronization2); |
| RETURN_IF_SKIP(InitBasicDescriptorBuffer()); |
| InitRenderTarget(); |
| |
| vkt::Buffer buffer(*m_device, sizeof(uint32_t) * 2u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vkt::device_address); |
| vkt::Buffer copy_buffer(*m_device, 4096u, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, |
| VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}; |
| const vkt::DescriptorSetLayout set_layout(*m_device, {binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&set_layout, &set_layout}); |
| |
| const VkDeviceSize ds_layout_size = set_layout.GetDescriptorBufferSize(); |
| vkt::Buffer descriptor_buffer(*m_device, ds_layout_size * 2u, |
| VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, |
| vkt::device_address); |
| |
| vkt::DescriptorGetInfo get_info(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, buffer, buffer.CreateInfo().size); |
| |
| uint32_t *data = (uint32_t *)buffer.Memory().Map(); |
| data[0] = 5u; |
| data[1] = 7u; |
| |
| void *mapped_copy_data = copy_buffer.Memory().Map(); |
| vk::GetDescriptorEXT(device(), get_info, descriptor_buffer_properties.storageBufferDescriptorSize, mapped_copy_data); |
| |
| void *mapped_descriptor_data = descriptor_buffer.Memory().Map(); |
| memcpy(mapped_descriptor_data, mapped_copy_data, descriptor_buffer_properties.storageBufferDescriptorSize); |
| |
| const char *vsSource = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer SSBO_0 { |
| uint a_0; |
| uint b_0; |
| }; |
| layout(set = 1, binding = 0) buffer SSBO_1 { |
| uint a_1; |
| uint b_1; |
| }; |
| void main() { |
| vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1)); |
| gl_Position = vec4(pos, 0.0f, 1.0f); |
| b_1 = a_0; |
| } |
| )glsl"; |
| |
| VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT; |
| pipe.shader_stages_[0] = vs.GetStageCreateInfo(); |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| const uint32_t buffer_indices[] = {0u, 0u}; |
| const VkDeviceSize buffer_offsets[] = {0u, ds_layout_size}; |
| |
| VkBufferCopy buffer_copy = {}; |
| buffer_copy.srcOffset = 0u; |
| buffer_copy.dstOffset = ds_layout_size; |
| buffer_copy.size = ds_layout_size; |
| |
| VkBufferMemoryBarrier2 buffer_memory_barrier = vku::InitStructHelper(); |
| buffer_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
| buffer_memory_barrier.dstAccessMask = VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT; |
| buffer_memory_barrier.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; |
| buffer_memory_barrier.dstStageMask = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT; |
| buffer_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| buffer_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| buffer_memory_barrier.buffer = descriptor_buffer; |
| buffer_memory_barrier.offset = ds_layout_size; |
| buffer_memory_barrier.size = ds_layout_size; |
| |
| VkDependencyInfo dependency_info = vku::InitStructHelper(); |
| dependency_info.bufferMemoryBarrierCount = 1u; |
| dependency_info.pBufferMemoryBarriers = &buffer_memory_barrier; |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = descriptor_buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| m_command_buffer.Begin(); |
| vk::CmdCopyBuffer(m_command_buffer, copy_buffer, descriptor_buffer, 1u, &buffer_copy); |
| vk::CmdPipelineBarrier2(m_command_buffer, &dependency_info); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 2u, buffer_indices, |
| buffer_offsets); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| |
| if (!IsPlatformMockICD()) { |
| for (uint32_t i = 0; i < 2; i++) { |
| ASSERT_EQ(data[i], 5.0f); |
| } |
| } |
| } |