// Copyright 2018 The Amber 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 "src/vulkan/buffer_descriptor.h" #include #include #include #include "src/make_unique.h" #include "src/vulkan/command_buffer.h" #include "src/vulkan/device.h" namespace amber { namespace vulkan { BufferDescriptor::BufferDescriptor(Buffer* buffer, DescriptorType type, Device* device, uint32_t desc_set, uint32_t binding, Pipeline* pipeline) : BufferBackedDescriptor(buffer, type, device, desc_set, binding, pipeline) {} BufferDescriptor::~BufferDescriptor() = default; Result BufferDescriptor::CreateResourceIfNeeded() { auto& transfer_resources = pipeline_->GetDescriptorTransferResources(); VkBufferUsageFlags flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; if (IsUniformBuffer() || IsUniformBufferDynamic()) { flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; } else if (IsStorageBuffer() || IsStorageBufferDynamic()) { flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; } else if (IsUniformTexelBuffer()) { flags |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; } else if (IsStorageTexelBuffer()) { flags |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; } else { return Result("Unexpected buffer type when deciding usage flags"); } for (const auto& amber_buffer : GetAmberBuffers()) { // Create (but don't initialize) the transfer buffer if not already created. if (transfer_resources.count(amber_buffer) == 0) { auto size_in_bytes = static_cast(amber_buffer->ValuePtr()->size()); auto transfer_buffer = MakeUnique( device_, size_in_bytes, amber_buffer->GetFormat()); transfer_buffer->SetReadOnly(IsReadOnly()); transfer_resources[amber_buffer] = std::move(transfer_buffer); } else { // Unset transfer buffer's read only property if needed. if (!IsReadOnly()) { transfer_resources[amber_buffer]->SetReadOnly(false); } } // Update the buffer create flags. Result r = transfer_resources[amber_buffer]->AsTransferBuffer()->AddUsageFlags( flags); if (!r.IsSuccess()) return r; } is_descriptor_set_update_needed_ = true; descriptor_offsets_.reserve(GetAmberBuffers().size()); descriptor_ranges_.reserve(GetAmberBuffers().size()); return {}; } void BufferDescriptor::UpdateDescriptorSetIfNeeded( VkDescriptorSet descriptor_set) { if (!is_descriptor_set_update_needed_) return; std::vector buffer_infos; std::vector buffer_views; // Create VkDescriptorBufferInfo for every descriptor buffer. for (uint32_t i = 0; i < GetAmberBuffers().size(); i++) { const auto& buffer = pipeline_->GetDescriptorTransferResources()[GetAmberBuffers()[i]] ->AsTransferBuffer(); assert(buffer->GetVkBuffer() && "Unexpected descriptor type"); // Add buffer infos for uniform and storage buffers. if (IsUniformBuffer() || IsUniformBufferDynamic() || IsStorageBuffer() || IsStorageBufferDynamic()) { uint64_t range = descriptor_ranges_[i]; // If dynamic offset is used, we must change range with VK_WHOLE_SIZE to // an actual range. // From vulkan spec: For each dynamic uniform or storage buffer binding in // pDescriptorSets, the sum of the effective offset, as defined above, and // the range of the binding must be less than or equal to the size of the // buffer. if ((IsUniformBufferDynamic() || IsStorageBufferDynamic()) && descriptor_ranges_[i] == VK_WHOLE_SIZE) { range = buffer->GetSizeInBytes() - dynamic_offsets_[i] - descriptor_offsets_[i]; } VkDescriptorBufferInfo buffer_info; buffer_info.buffer = buffer->GetVkBuffer(); buffer_info.offset = descriptor_offsets_[i]; buffer_info.range = range; buffer_infos.push_back(buffer_info); } if (IsUniformTexelBuffer() || IsStorageTexelBuffer()) { buffer_views.push_back(*buffer->GetVkBufferView()); } } VkWriteDescriptorSet write = VkWriteDescriptorSet(); write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write.dstSet = descriptor_set; write.dstBinding = binding_; write.dstArrayElement = 0; write.descriptorCount = static_cast(GetAmberBuffers().size()); write.descriptorType = GetVkDescriptorType(); write.pBufferInfo = buffer_infos.data(); write.pTexelBufferView = buffer_views.data(); device_->GetPtrs()->vkUpdateDescriptorSets(device_->GetVkDevice(), 1, &write, 0, nullptr); is_descriptor_set_update_needed_ = false; } } // namespace vulkan } // namespace amber