blob: a0b4d7155ad1a74da51c2b19bbea603c5f3ec7a0 [file] [log] [blame]
/*
* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
* Copyright (c) 2015-2023 Google, 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 "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
TEST_F(PositivePushDescriptor, NullDstSet) {
TEST_DESCRIPTION("Use null dstSet in CmdPushDescriptorSetKHR");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
VkDescriptorSetLayoutBinding dsl_binding = {};
dsl_binding.binding = 2;
dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
dsl_binding.descriptorCount = 1;
dsl_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
dsl_binding.pImmutableSamplers = NULL;
const vkt::DescriptorSetLayout ds_layout(*m_device, {dsl_binding});
// Create push descriptor set layout
const vkt::DescriptorSetLayout push_ds_layout(*m_device, {dsl_binding},
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR);
// Use helper to create graphics pipeline
CreatePipelineHelper helper(*this);
helper.InitState();
helper.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&push_ds_layout, &ds_layout});
helper.CreateGraphicsPipeline();
const uint32_t data_size = sizeof(float) * 3;
vkt::Buffer vbo(*m_device, data_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo buff_info;
buff_info.buffer = vbo.handle();
buff_info.offset = 0;
buff_info.range = data_size;
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstBinding = 2;
descriptor_write.descriptorCount = 1;
descriptor_write.pTexelBufferView = nullptr;
descriptor_write.pBufferInfo = &buff_info;
descriptor_write.pImageInfo = nullptr;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.dstSet = 0; // Should not cause a validation error
m_commandBuffer->begin();
// In Intel GPU, it needs to bind pipeline before push descriptor set.
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, helper.pipeline_);
vk::CmdPushDescriptorSetKHR(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, helper.pipeline_layout_.handle(), 0, 1,
&descriptor_write);
}
TEST_F(PositivePushDescriptor, UnboundSet) {
TEST_DESCRIPTION("Ensure that no validation errors are produced for not bound push descriptor sets");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
// Create descriptor set layout
VkDescriptorSetLayoutBinding dsl_binding = {};
dsl_binding.binding = 2;
dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
dsl_binding.descriptorCount = 1;
dsl_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
dsl_binding.pImmutableSamplers = NULL;
OneOffDescriptorSet descriptor_set(m_device, {dsl_binding}, 0, nullptr, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
nullptr);
// Create push descriptor set layout
const vkt::DescriptorSetLayout push_ds_layout(*m_device, {dsl_binding},
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR);
// Create PSO
char const fsSource[] = R"glsl(
#version 450
layout(location=0) out vec4 x;
layout(set=0) layout(binding=2) uniform foo1 { float x; } bar1;
layout(set=1) layout(binding=2) uniform foo2 { float y; } bar2;
void main(){
x = vec4(bar1.x) + vec4(bar2.y);
}
)glsl";
VkShaderObj vs(this, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.InitState();
// Now use the descriptor layouts to create a pipeline layout
pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {&push_ds_layout, &descriptor_set.layout_});
pipe.CreateGraphicsPipeline();
const uint32_t data_size = sizeof(float);
vkt::Buffer buffer(*m_device, data_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
// Update descriptor set
descriptor_set.WriteDescriptorBufferInfo(2, buffer.handle(), 0, data_size);
descriptor_set.UpdateDescriptorSets();
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_);
// Push descriptors and bind descriptor set
vk::CmdPushDescriptorSetKHR(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 0, 1,
descriptor_set.descriptor_writes.data());
vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_layout_.handle(), 1, 1,
&descriptor_set.set_, 0, NULL);
// No errors should be generated.
vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
TEST_F(PositivePushDescriptor, SetUpdatingSetNumber) {
TEST_DESCRIPTION(
"Ensure that no validation errors are produced when the push descriptor set number changes "
"between two vk::CmdPushDescriptorSetKHR calls.");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
InitRenderTarget();
// Create a descriptor to push
vkt::Buffer buffer(*m_device, sizeof(uint32_t) * 4,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
VkDescriptorBufferInfo buffer_info = {buffer.handle(), 0, VK_WHOLE_SIZE};
const VkDescriptorSetLayoutBinding ds_binding_0 = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT,
nullptr};
const VkDescriptorSetLayoutBinding ds_binding_1 = {1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT,
nullptr};
const vkt::DescriptorSetLayout ds_layout(*m_device, {ds_binding_0, ds_binding_1});
ASSERT_TRUE(ds_layout.initialized());
const VkDescriptorSetLayoutBinding push_ds_binding_0 = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT,
nullptr};
const vkt::DescriptorSetLayout push_ds_layout(*m_device, {push_ds_binding_0},
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR);
ASSERT_TRUE(push_ds_layout.initialized());
m_commandBuffer->begin();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
CreatePipelineHelper pipe0(*this);
CreatePipelineHelper pipe1(*this);
{
// Note: the push descriptor set is set number 2.
const vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout, &ds_layout, &push_ds_layout, &ds_layout});
ASSERT_TRUE(pipeline_layout.initialized());
char const *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 x;
layout(set=2) layout(binding=0) uniform foo { vec4 y; } bar;
void main(){
x = bar.y;
}
)glsl";
VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
pipe0.InitState();
pipe0.shader_stages_[1] = fs.GetStageCreateInfo();
pipe0.gp_ci_.layout = pipeline_layout.handle();
pipe0.CreateGraphicsPipeline();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe0.Handle());
const VkWriteDescriptorSet descriptor_write =
vkt::Device::write_descriptor_set(vkt::DescriptorSet(), 0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, &buffer_info);
// Note: pushing to desciptor set number 2.
vk::CmdPushDescriptorSetKHR(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 2, 1,
&descriptor_write);
vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
}
{
// Note: the push descriptor set is now set number 3.
const vkt::PipelineLayout pipeline_layout(*m_device, {&ds_layout, &ds_layout, &ds_layout, &push_ds_layout});
ASSERT_TRUE(pipeline_layout.initialized());
const VkWriteDescriptorSet descriptor_write =
vkt::Device::write_descriptor_set(vkt::DescriptorSet(), 0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, &buffer_info);
char const *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 x;
layout(set=3) layout(binding=0) uniform foo { vec4 y; } bar;
void main(){
x = bar.y;
}
)glsl";
VkShaderObj fs(this, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
pipe1.InitState();
pipe1.shader_stages_[1] = fs.GetStageCreateInfo();
pipe1.gp_ci_.layout = pipeline_layout.handle();
pipe1.CreateGraphicsPipeline();
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe1.Handle());
// Note: now pushing to desciptor set number 3.
vk::CmdPushDescriptorSetKHR(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 3, 1,
&descriptor_write);
vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0);
}
m_commandBuffer->EndRenderPass();
m_commandBuffer->end();
}
TEST_F(PositivePushDescriptor, CreateDescriptorSetBindingWithIgnoredSamplers) {
TEST_DESCRIPTION("Test that layers conditionally do ignore the pImmutableSamplers on vkCreateDescriptorSetLayout");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
const uint64_t fake_address_64 = 0xCDCDCDCDCDCDCDCD;
const uint64_t fake_address_32 = 0xCDCDCDCD;
const void *fake_pointer =
sizeof(void *) == 8 ? reinterpret_cast<void *>(fake_address_64) : reinterpret_cast<void *>(fake_address_32);
const VkSampler *hopefully_undereferencable_pointer = reinterpret_cast<const VkSampler *>(fake_pointer);
// regular descriptors
{
const VkDescriptorSetLayoutBinding non_sampler_bindings[] = {
{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{2, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{3, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{4, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{6, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{8, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
};
const auto dslci =
vku::InitStruct<VkDescriptorSetLayoutCreateInfo>(nullptr, 0u, size32(non_sampler_bindings), non_sampler_bindings);
vkt::DescriptorSetLayout dsl(*m_device, dslci);
}
// push descriptors
{
const VkDescriptorSetLayoutBinding non_sampler_bindings[] = {
{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{2, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{3, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{4, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
{6, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, hopefully_undereferencable_pointer},
};
const auto dslci = vku::InitStruct<VkDescriptorSetLayoutCreateInfo>(
nullptr, static_cast<VkDescriptorSetLayoutCreateFlags>(VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR),
size32(non_sampler_bindings), non_sampler_bindings);
vkt::DescriptorSetLayout dsl(*m_device, dslci);
}
}
TEST_F(PositivePushDescriptor, ImmutableSampler) {
TEST_DESCRIPTION("Use a push descriptor with an immutable sampler.");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
vkt::Sampler sampler(*m_device, sampler_ci);
VkSampler sampler_handle = sampler.handle();
VkImageObj image(m_device);
image.InitNoLayout(32, 32, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
VkImageView imageView = image.targetView(VK_FORMAT_R8G8B8A8_UNORM);
std::vector<VkDescriptorSetLayoutBinding> ds_bindings = {
{0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler_handle}};
OneOffDescriptorSet descriptor_set(m_device, ds_bindings);
vkt::DescriptorSetLayout push_dsl(*m_device, ds_bindings, VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR);
vkt::PipelineLayout pipeline_layout(*m_device, {&push_dsl});
VkDescriptorImageInfo img_info = {};
img_info.sampler = sampler_handle;
img_info.imageView = imageView;
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.pTexelBufferView = nullptr;
descriptor_write.pBufferInfo = nullptr;
descriptor_write.pImageInfo = &img_info;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
descriptor_write.dstSet = descriptor_set.set_;
m_commandBuffer->begin();
vk::CmdPushDescriptorSetKHR(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1,
&descriptor_write);
m_commandBuffer->end();
}
TEST_F(PositivePushDescriptor, TemplateBasic) {
TEST_DESCRIPTION("Basic use of vkCmdPushDescriptorSetWithTemplateKHR");
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.size = 32;
buffer_ci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
vkt::Buffer buffer(*m_device, buffer_ci);
std::vector<VkDescriptorSetLayoutBinding> ds_bindings = {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}};
OneOffDescriptorSet descriptor_set(m_device, ds_bindings);
vkt::DescriptorSetLayout push_dsl(*m_device, ds_bindings, VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR);
vkt::PipelineLayout pipeline_layout(*m_device, {&push_dsl});
struct SimpleTemplateData {
VkDescriptorBufferInfo buff_info;
};
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 0;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
update_template_entry.offset = offsetof(SimpleTemplateData, buff_info);
update_template_entry.stride = sizeof(SimpleTemplateData);
VkDescriptorUpdateTemplateCreateInfoKHR update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR;
update_template_ci.descriptorSetLayout = descriptor_set.layout_.handle();
update_template_ci.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
update_template_ci.pipelineLayout = pipeline_layout.handle();
VkDescriptorUpdateTemplate update_template = VK_NULL_HANDLE;
vk::CreateDescriptorUpdateTemplateKHR(m_device->device(), &update_template_ci, nullptr, &update_template);
SimpleTemplateData update_template_data;
update_template_data.buff_info = {buffer.handle(), 0, 32};
m_commandBuffer->begin();
vk::CmdPushDescriptorSetWithTemplateKHR(m_commandBuffer->handle(), update_template, pipeline_layout.handle(), 0,
&update_template_data);
m_commandBuffer->end();
vk::DestroyDescriptorUpdateTemplateKHR(m_device->device(), update_template, nullptr);
}
TEST_F(PositivePushDescriptor, WriteDescriptorSetNotAllocated) {
TEST_DESCRIPTION("Try to update a descriptor that has yet to be allocated and make sure its ignored");
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkDescriptorSetLayoutBinding ds_binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr};
VkDescriptorSetLayoutCreateInfo dsl_ci = vku::InitStructHelper();
dsl_ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
dsl_ci.bindingCount = 1;
dsl_ci.pBindings = &ds_binding;
vkt::DescriptorSetLayout ds_layout(*m_device, dsl_ci);
VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper();
pipeline_layout_ci.setLayoutCount = 1;
pipeline_layout_ci.pSetLayouts = &ds_layout.handle();
pipeline_layout_ci.pushConstantRangeCount = 0;
vkt::PipelineLayout pipeline_layout(*m_device, pipeline_layout_ci);
// Valid, from spec:
// "Each element of pDescriptorWrites is interpreted as in VkWriteDescriptorSet, except the dstSet member is ignored"
VkDescriptorSet bad_set = CastFromUint64<VkDescriptorSet>(0xcadecade);
VkDescriptorBufferInfo buffer_info = {buffer.handle(), 0, 32};
VkWriteDescriptorSet descriptor_write = vku::InitStructHelper();
descriptor_write.dstSet = bad_set;
descriptor_write.dstBinding = 0;
descriptor_write.descriptorCount = 1;
descriptor_write.pTexelBufferView = nullptr;
descriptor_write.pBufferInfo = &buffer_info;
descriptor_write.pImageInfo = nullptr;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
m_commandBuffer->begin();
vk::CmdPushDescriptorSetKHR(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1,
&descriptor_write);
VkDescriptorSet null_set = CastFromUint64<VkDescriptorSet>(0);
descriptor_write.dstSet = null_set;
vk::CmdPushDescriptorSetKHR(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1,
&descriptor_write);
m_commandBuffer->end();
}
TEST_F(PositivePushDescriptor, PushDescriptorWithTemplateMultipleSets) {
TEST_DESCRIPTION("Basic use of vkCmdPushDescriptorSetWithTemplateKHR");
AddRequiredExtensions(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
if (IsDriver(VK_DRIVER_ID_AMD_PROPRIETARY)) {
GTEST_SKIP() << "Test crashes on AMD.";
}
VkBufferCreateInfo buffer_ci = vku::InitStructHelper();
buffer_ci.size = 32;
buffer_ci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
vkt::Buffer buffer(*m_device, buffer_ci);
std::vector<VkDescriptorSetLayoutBinding> ds_bindings = {
{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
{2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr},
};
OneOffDescriptorSet descriptor_set(m_device, ds_bindings);
vkt::DescriptorSetLayout push_dsl1(*m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}});
vkt::DescriptorSetLayout push_dsl2(*m_device, ds_bindings, VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR);
vkt::PipelineLayout pipeline_layout(*m_device, {&push_dsl1, &push_dsl2});
struct SimpleTemplateData {
VkDescriptorBufferInfo buff_info;
};
VkDescriptorUpdateTemplateEntry update_template_entry = {};
update_template_entry.dstBinding = 1;
update_template_entry.dstArrayElement = 0;
update_template_entry.descriptorCount = 1;
update_template_entry.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
update_template_entry.offset = offsetof(SimpleTemplateData, buff_info);
update_template_entry.stride = sizeof(SimpleTemplateData);
VkDescriptorUpdateTemplateCreateInfoKHR update_template_ci = vku::InitStructHelper();
update_template_ci.descriptorUpdateEntryCount = 1;
update_template_ci.pDescriptorUpdateEntries = &update_template_entry;
update_template_ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR;
update_template_ci.descriptorSetLayout = descriptor_set.layout_.handle();
update_template_ci.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
update_template_ci.pipelineLayout = pipeline_layout.handle();
update_template_ci.set = 1;
VkDescriptorUpdateTemplate update_template = VK_NULL_HANDLE;
vk::CreateDescriptorUpdateTemplateKHR(m_device->device(), &update_template_ci, nullptr, &update_template);
SimpleTemplateData update_template_data;
update_template_data.buff_info = {buffer.handle(), 0, 32};
m_commandBuffer->begin();
vk::CmdPushDescriptorSetWithTemplateKHR(m_commandBuffer->handle(), update_template, pipeline_layout.handle(), 1,
&update_template_data);
m_commandBuffer->end();
vk::DestroyDescriptorUpdateTemplateKHR(m_device->device(), update_template, nullptr);
}