|  | // Copyright 2018 The Dawn Authors | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include "dawn_native/vulkan/BindGroupVk.h" | 
|  |  | 
|  | #include "common/BitSetIterator.h" | 
|  | #include "common/ityp_stack_vec.h" | 
|  | #include "dawn_native/ExternalTexture.h" | 
|  | #include "dawn_native/vulkan/BindGroupLayoutVk.h" | 
|  | #include "dawn_native/vulkan/BufferVk.h" | 
|  | #include "dawn_native/vulkan/DeviceVk.h" | 
|  | #include "dawn_native/vulkan/FencedDeleter.h" | 
|  | #include "dawn_native/vulkan/SamplerVk.h" | 
|  | #include "dawn_native/vulkan/TextureVk.h" | 
|  | #include "dawn_native/vulkan/VulkanError.h" | 
|  |  | 
|  | namespace dawn_native { namespace vulkan { | 
|  |  | 
|  | // static | 
|  | ResultOrError<Ref<BindGroup>> BindGroup::Create(Device* device, | 
|  | const BindGroupDescriptor* descriptor) { | 
|  | return ToBackend(descriptor->layout)->AllocateBindGroup(device, descriptor); | 
|  | } | 
|  |  | 
|  | BindGroup::BindGroup(Device* device, | 
|  | const BindGroupDescriptor* descriptor, | 
|  | DescriptorSetAllocation descriptorSetAllocation) | 
|  | : BindGroupBase(this, device, descriptor), | 
|  | mDescriptorSetAllocation(descriptorSetAllocation) { | 
|  | // Now do a write of a single descriptor set with all possible chained data allocated on the | 
|  | // stack. | 
|  | const uint32_t bindingCount = static_cast<uint32_t>((GetLayout()->GetBindingCount())); | 
|  | ityp::stack_vec<uint32_t, VkWriteDescriptorSet, kMaxOptimalBindingsPerGroup> writes( | 
|  | bindingCount); | 
|  | ityp::stack_vec<uint32_t, VkDescriptorBufferInfo, kMaxOptimalBindingsPerGroup> | 
|  | writeBufferInfo(bindingCount); | 
|  | ityp::stack_vec<uint32_t, VkDescriptorImageInfo, kMaxOptimalBindingsPerGroup> | 
|  | writeImageInfo(bindingCount); | 
|  |  | 
|  | uint32_t numWrites = 0; | 
|  | for (const auto& it : GetLayout()->GetBindingMap()) { | 
|  | BindingIndex bindingIndex = it.second; | 
|  | const BindingInfo& bindingInfo = GetLayout()->GetBindingInfo(bindingIndex); | 
|  |  | 
|  | auto& write = writes[numWrites]; | 
|  | write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; | 
|  | write.pNext = nullptr; | 
|  | write.dstSet = GetHandle(); | 
|  | write.dstBinding = static_cast<uint32_t>(bindingIndex); | 
|  | write.dstArrayElement = 0; | 
|  | write.descriptorCount = 1; | 
|  | write.descriptorType = VulkanDescriptorType(bindingInfo); | 
|  |  | 
|  | switch (bindingInfo.bindingType) { | 
|  | case BindingInfoType::Buffer: { | 
|  | BufferBinding binding = GetBindingAsBufferBinding(bindingIndex); | 
|  |  | 
|  | VkBuffer handle = ToBackend(binding.buffer)->GetHandle(); | 
|  | if (handle == VK_NULL_HANDLE) { | 
|  | // The Buffer was destroyed. Skip this descriptor write since it would be | 
|  | // a Vulkan Validation Layers error. This bind group won't be used as it | 
|  | // is an error to submit a command buffer that references destroyed | 
|  | // resources. | 
|  | continue; | 
|  | } | 
|  | writeBufferInfo[numWrites].buffer = handle; | 
|  | writeBufferInfo[numWrites].offset = binding.offset; | 
|  | writeBufferInfo[numWrites].range = binding.size; | 
|  | write.pBufferInfo = &writeBufferInfo[numWrites]; | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BindingInfoType::Sampler: { | 
|  | Sampler* sampler = ToBackend(GetBindingAsSampler(bindingIndex)); | 
|  | writeImageInfo[numWrites].sampler = sampler->GetHandle(); | 
|  | write.pImageInfo = &writeImageInfo[numWrites]; | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BindingInfoType::Texture: { | 
|  | TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex)); | 
|  |  | 
|  | VkImageView handle = view->GetHandle(); | 
|  | if (handle == VK_NULL_HANDLE) { | 
|  | // The Texture was destroyed before the TextureView was created. | 
|  | // Skip this descriptor write since it would be | 
|  | // a Vulkan Validation Layers error. This bind group won't be used as it | 
|  | // is an error to submit a command buffer that references destroyed | 
|  | // resources. | 
|  | continue; | 
|  | } | 
|  | writeImageInfo[numWrites].imageView = handle; | 
|  |  | 
|  | // The layout may be GENERAL here because of interactions between the Sampled | 
|  | // and ReadOnlyStorage usages. See the logic in VulkanImageLayout. | 
|  | writeImageInfo[numWrites].imageLayout = VulkanImageLayout( | 
|  | ToBackend(view->GetTexture()), wgpu::TextureUsage::TextureBinding); | 
|  |  | 
|  | write.pImageInfo = &writeImageInfo[numWrites]; | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BindingInfoType::StorageTexture: { | 
|  | TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex)); | 
|  |  | 
|  | VkImageView handle = view->GetHandle(); | 
|  | if (handle == VK_NULL_HANDLE) { | 
|  | // The Texture was destroyed before the TextureView was created. | 
|  | // Skip this descriptor write since it would be | 
|  | // a Vulkan Validation Layers error. This bind group won't be used as it | 
|  | // is an error to submit a command buffer that references destroyed | 
|  | // resources. | 
|  | continue; | 
|  | } | 
|  | writeImageInfo[numWrites].imageView = handle; | 
|  | writeImageInfo[numWrites].imageLayout = VK_IMAGE_LAYOUT_GENERAL; | 
|  |  | 
|  | write.pImageInfo = &writeImageInfo[numWrites]; | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BindingInfoType::ExternalTexture: { | 
|  | const std::array<Ref<dawn_native::TextureViewBase>, kMaxPlanesPerFormat>& | 
|  | textureViews = GetBindingAsExternalTexture(bindingIndex)->GetTextureViews(); | 
|  |  | 
|  | // Only single-plane formats are supported right now, so ensure only one view | 
|  | // exists. | 
|  | ASSERT(textureViews[1].Get() == nullptr); | 
|  | ASSERT(textureViews[2].Get() == nullptr); | 
|  |  | 
|  | TextureView* view = ToBackend(textureViews[0].Get()); | 
|  |  | 
|  | writeImageInfo[numWrites].imageView = view->GetHandle(); | 
|  | writeImageInfo[numWrites].imageLayout = VulkanImageLayout( | 
|  | ToBackend(view->GetTexture()), wgpu::TextureUsage::TextureBinding); | 
|  |  | 
|  | write.pImageInfo = &writeImageInfo[numWrites]; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | numWrites++; | 
|  | } | 
|  |  | 
|  | // TODO(crbug.com/dawn/855): Batch these updates | 
|  | device->fn.UpdateDescriptorSets(device->GetVkDevice(), numWrites, writes.data(), 0, | 
|  | nullptr); | 
|  | } | 
|  |  | 
|  | BindGroup::~BindGroup() { | 
|  | ToBackend(GetLayout())->DeallocateBindGroup(this, &mDescriptorSetAllocation); | 
|  | } | 
|  |  | 
|  | VkDescriptorSet BindGroup::GetHandle() const { | 
|  | return mDescriptorSetAllocation.set; | 
|  | } | 
|  |  | 
|  | }}  // namespace dawn_native::vulkan |