[Vulkan] Basic shared memory uploading
This commit is contained in:
208
src/xenia/gpu/vulkan/deferred_command_buffer.cc
Normal file
208
src/xenia/gpu/vulkan/deferred_command_buffer.cc
Normal file
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/gpu/vulkan/deferred_command_buffer.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/profiling.h"
|
||||
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
namespace vulkan {
|
||||
|
||||
DeferredCommandBuffer::DeferredCommandBuffer(
|
||||
const VulkanCommandProcessor& command_processor, size_t initial_size)
|
||||
: command_processor_(command_processor) {
|
||||
command_stream_.reserve(initial_size / sizeof(uintmax_t));
|
||||
}
|
||||
|
||||
void DeferredCommandBuffer::Reset() { command_stream_.clear(); }
|
||||
|
||||
void DeferredCommandBuffer::Execute(VkCommandBuffer command_buffer) {
|
||||
#if XE_UI_VULKAN_FINE_GRAINED_DRAW_SCOPES
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
#endif // XE_UI_VULKAN_FINE_GRAINED_DRAW_SCOPES
|
||||
|
||||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn =
|
||||
command_processor_.GetVulkanContext().GetVulkanProvider().dfn();
|
||||
const uintmax_t* stream = command_stream_.data();
|
||||
size_t stream_remaining = command_stream_.size();
|
||||
while (stream_remaining) {
|
||||
const CommandHeader& header =
|
||||
*reinterpret_cast<const CommandHeader*>(stream);
|
||||
stream += kCommandHeaderSizeElements;
|
||||
stream_remaining -= kCommandHeaderSizeElements;
|
||||
|
||||
switch (header.command) {
|
||||
case Command::kVkBindIndexBuffer: {
|
||||
auto& args = *reinterpret_cast<const ArgsVkBindIndexBuffer*>(stream);
|
||||
dfn.vkCmdBindIndexBuffer(command_buffer, args.buffer, args.offset,
|
||||
args.index_type);
|
||||
} break;
|
||||
|
||||
case Command::kVkCopyBuffer: {
|
||||
auto& args = *reinterpret_cast<const ArgsVkCopyBuffer*>(stream);
|
||||
static_assert(alignof(VkBufferCopy) <= alignof(uintmax_t));
|
||||
dfn.vkCmdCopyBuffer(
|
||||
command_buffer, args.src_buffer, args.dst_buffer, args.region_count,
|
||||
reinterpret_cast<const VkBufferCopy*>(
|
||||
reinterpret_cast<const uint8_t*>(stream) +
|
||||
xe::align(sizeof(ArgsVkCopyBuffer), alignof(VkBufferCopy))));
|
||||
} break;
|
||||
|
||||
case Command::kVkPipelineBarrier: {
|
||||
auto& args = *reinterpret_cast<const ArgsVkPipelineBarrier*>(stream);
|
||||
size_t barrier_offset_bytes = sizeof(ArgsVkPipelineBarrier);
|
||||
|
||||
const VkMemoryBarrier* memory_barriers;
|
||||
if (args.memory_barrier_count) {
|
||||
static_assert(alignof(VkMemoryBarrier) <= alignof(uintmax_t));
|
||||
barrier_offset_bytes =
|
||||
xe::align(barrier_offset_bytes, alignof(VkMemoryBarrier));
|
||||
memory_barriers = reinterpret_cast<const VkMemoryBarrier*>(
|
||||
reinterpret_cast<const uint8_t*>(stream) + barrier_offset_bytes);
|
||||
barrier_offset_bytes +=
|
||||
sizeof(VkMemoryBarrier) * args.memory_barrier_count;
|
||||
} else {
|
||||
memory_barriers = nullptr;
|
||||
}
|
||||
|
||||
const VkBufferMemoryBarrier* buffer_memory_barriers;
|
||||
if (args.buffer_memory_barrier_count) {
|
||||
static_assert(alignof(VkBufferMemoryBarrier) <= alignof(uintmax_t));
|
||||
barrier_offset_bytes =
|
||||
xe::align(barrier_offset_bytes, alignof(VkBufferMemoryBarrier));
|
||||
buffer_memory_barriers =
|
||||
reinterpret_cast<const VkBufferMemoryBarrier*>(
|
||||
reinterpret_cast<const uint8_t*>(stream) +
|
||||
barrier_offset_bytes);
|
||||
barrier_offset_bytes +=
|
||||
sizeof(VkBufferMemoryBarrier) * args.buffer_memory_barrier_count;
|
||||
} else {
|
||||
buffer_memory_barriers = nullptr;
|
||||
}
|
||||
|
||||
const VkImageMemoryBarrier* image_memory_barriers;
|
||||
if (args.image_memory_barrier_count) {
|
||||
static_assert(alignof(VkImageMemoryBarrier) <= alignof(uintmax_t));
|
||||
barrier_offset_bytes =
|
||||
xe::align(barrier_offset_bytes, alignof(VkImageMemoryBarrier));
|
||||
image_memory_barriers = reinterpret_cast<const VkImageMemoryBarrier*>(
|
||||
reinterpret_cast<const uint8_t*>(stream) + barrier_offset_bytes);
|
||||
barrier_offset_bytes +=
|
||||
sizeof(VkImageMemoryBarrier) * args.image_memory_barrier_count;
|
||||
} else {
|
||||
image_memory_barriers = nullptr;
|
||||
}
|
||||
|
||||
dfn.vkCmdPipelineBarrier(
|
||||
command_buffer, args.src_stage_mask, args.dst_stage_mask,
|
||||
args.dependency_flags, args.memory_barrier_count, memory_barriers,
|
||||
args.buffer_memory_barrier_count, buffer_memory_barriers,
|
||||
args.image_memory_barrier_count, image_memory_barriers);
|
||||
} break;
|
||||
|
||||
default:
|
||||
assert_unhandled_case(header.command);
|
||||
break;
|
||||
}
|
||||
|
||||
stream += header.arguments_size_elements;
|
||||
stream_remaining -= header.arguments_size_elements;
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredCommandBuffer::CmdVkPipelineBarrier(
|
||||
VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
|
||||
VkDependencyFlags dependency_flags, uint32_t memory_barrier_count,
|
||||
const VkMemoryBarrier* memory_barriers,
|
||||
uint32_t buffer_memory_barrier_count,
|
||||
const VkBufferMemoryBarrier* buffer_memory_barriers,
|
||||
uint32_t image_memory_barrier_count,
|
||||
const VkImageMemoryBarrier* image_memory_barriers) {
|
||||
size_t arguments_size = sizeof(ArgsVkPipelineBarrier);
|
||||
|
||||
size_t memory_barriers_offset;
|
||||
if (memory_barrier_count) {
|
||||
static_assert(alignof(VkMemoryBarrier) <= alignof(uintmax_t));
|
||||
arguments_size = xe::align(arguments_size, alignof(VkMemoryBarrier));
|
||||
memory_barriers_offset = arguments_size;
|
||||
arguments_size += sizeof(VkMemoryBarrier) * memory_barrier_count;
|
||||
} else {
|
||||
memory_barriers_offset = 0;
|
||||
}
|
||||
|
||||
size_t buffer_memory_barriers_offset;
|
||||
if (buffer_memory_barrier_count) {
|
||||
static_assert(alignof(VkBufferMemoryBarrier) <= alignof(uintmax_t));
|
||||
arguments_size = xe::align(arguments_size, alignof(VkBufferMemoryBarrier));
|
||||
buffer_memory_barriers_offset = arguments_size;
|
||||
arguments_size +=
|
||||
sizeof(VkBufferMemoryBarrier) * buffer_memory_barrier_count;
|
||||
} else {
|
||||
buffer_memory_barriers_offset = 0;
|
||||
}
|
||||
|
||||
size_t image_memory_barriers_offset;
|
||||
if (image_memory_barrier_count) {
|
||||
static_assert(alignof(VkImageMemoryBarrier) <= alignof(uintmax_t));
|
||||
arguments_size = xe::align(arguments_size, alignof(VkImageMemoryBarrier));
|
||||
image_memory_barriers_offset = arguments_size;
|
||||
arguments_size += sizeof(VkImageMemoryBarrier) * image_memory_barrier_count;
|
||||
} else {
|
||||
image_memory_barriers_offset = 0;
|
||||
}
|
||||
|
||||
uint8_t* args_ptr = reinterpret_cast<uint8_t*>(
|
||||
WriteCommand(Command::kVkPipelineBarrier, arguments_size));
|
||||
auto& args = *reinterpret_cast<ArgsVkPipelineBarrier*>(args_ptr);
|
||||
args.src_stage_mask = src_stage_mask;
|
||||
args.dst_stage_mask = dst_stage_mask;
|
||||
args.dependency_flags = dependency_flags;
|
||||
args.memory_barrier_count = memory_barrier_count;
|
||||
args.buffer_memory_barrier_count = buffer_memory_barrier_count;
|
||||
args.image_memory_barrier_count = image_memory_barrier_count;
|
||||
if (memory_barrier_count) {
|
||||
std::memcpy(args_ptr + memory_barriers_offset, memory_barriers,
|
||||
sizeof(VkMemoryBarrier) * memory_barrier_count);
|
||||
}
|
||||
if (buffer_memory_barrier_count) {
|
||||
std::memcpy(args_ptr + buffer_memory_barriers_offset,
|
||||
buffer_memory_barriers,
|
||||
sizeof(VkBufferMemoryBarrier) * buffer_memory_barrier_count);
|
||||
}
|
||||
if (image_memory_barrier_count) {
|
||||
std::memcpy(args_ptr + image_memory_barriers_offset, image_memory_barriers,
|
||||
sizeof(VkImageMemoryBarrier) * image_memory_barrier_count);
|
||||
}
|
||||
}
|
||||
|
||||
void* DeferredCommandBuffer::WriteCommand(Command command,
|
||||
size_t arguments_size_bytes) {
|
||||
size_t arguments_size_elements =
|
||||
(arguments_size_bytes + sizeof(uintmax_t) - 1) / sizeof(uintmax_t);
|
||||
size_t offset = command_stream_.size();
|
||||
command_stream_.resize(offset + kCommandHeaderSizeElements +
|
||||
arguments_size_elements);
|
||||
CommandHeader& header =
|
||||
*reinterpret_cast<CommandHeader*>(command_stream_.data() + offset);
|
||||
header.command = command;
|
||||
header.arguments_size_elements = uint32_t(arguments_size_elements);
|
||||
return command_stream_.data() + (offset + kCommandHeaderSizeElements);
|
||||
}
|
||||
|
||||
} // namespace vulkan
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
||||
Reference in New Issue
Block a user