blob: d60ce08eef264f22dcb5e5beadcd88adbf8bd421 [file] [log] [blame]
// 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 <algorithm>
#include <utility>
#include <vector>
#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<uint32_t>(amber_buffer->ValuePtr()->size());
auto transfer_buffer = MakeUnique<TransferBuffer>(
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<VkDescriptorBufferInfo> buffer_infos;
std::vector<VkBufferView> 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<uint32_t>(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