blob: e74143f05d94f0bd9eca36e58296e9a75bfffd1f [file] [log] [blame]
// Copyright 2017 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/BufferUploader.h"
#include "dawn_native/vulkan/DeviceVk.h"
#include "dawn_native/vulkan/FencedDeleter.h"
#include "dawn_native/vulkan/MemoryAllocator.h"
#include <cstring>
namespace dawn_native { namespace vulkan {
BufferUploader::BufferUploader(Device* device) : mDevice(device) {
}
BufferUploader::~BufferUploader() {
}
void BufferUploader::BufferSubData(VkBuffer buffer,
VkDeviceSize offset,
VkDeviceSize size,
const void* data) {
// TODO(cwallez@chromium.org): this is soooooo bad. We should use some sort of ring buffer
// for this.
// Create a staging buffer
VkBufferCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.size = size;
createInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = 0;
VkBuffer stagingBuffer = VK_NULL_HANDLE;
if (mDevice->fn.CreateBuffer(mDevice->GetVkDevice(), &createInfo, nullptr,
&stagingBuffer) != VK_SUCCESS) {
ASSERT(false);
}
VkMemoryRequirements requirements;
mDevice->fn.GetBufferMemoryRequirements(mDevice->GetVkDevice(), stagingBuffer,
&requirements);
DeviceMemoryAllocation allocation;
if (!mDevice->GetMemoryAllocator()->Allocate(requirements, true, &allocation)) {
ASSERT(false);
}
if (mDevice->fn.BindBufferMemory(mDevice->GetVkDevice(), stagingBuffer,
allocation.GetMemory(),
allocation.GetMemoryOffset()) != VK_SUCCESS) {
ASSERT(false);
}
// Write to the staging buffer
ASSERT(allocation.GetMappedPointer() != nullptr);
memcpy(allocation.GetMappedPointer(), data, static_cast<size_t>(size));
// Enqueue host write -> transfer src barrier and copy command
VkCommandBuffer commands = mDevice->GetPendingCommandBuffer();
VkMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
mDevice->fn.CmdPipelineBarrier(commands, VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &barrier, 0, nullptr,
0, nullptr);
VkBufferCopy copy;
copy.srcOffset = 0;
copy.dstOffset = offset;
copy.size = size;
mDevice->fn.CmdCopyBuffer(commands, stagingBuffer, buffer, 1, &copy);
// TODO(cwallez@chromium.org): Buffers must be deleted before the memory.
// This happens to work for now, but is fragile.
mDevice->GetMemoryAllocator()->Free(&allocation);
mDevice->GetFencedDeleter()->DeleteWhenUnused(stagingBuffer);
}
void BufferUploader::Tick(Serial) {
}
}} // namespace dawn_native::vulkan