Basic buffer implementation

This commit is contained in:
Dynamitos
2024-04-11 18:51:47 +02:00
parent 77dc9ef3fd
commit 4dc2df800a
5 changed files with 526 additions and 451 deletions
+24
View File
@@ -1,6 +1,8 @@
#pragma once #pragma once
#include "Graphics/Buffer.h" #include "Graphics/Buffer.h"
#include "Graphics/Enums.h"
#include "Graphics/Initializer.h" #include "Graphics/Initializer.h"
#include "Resources.h"
namespace Seele { namespace Seele {
namespace Metal { namespace Metal {
@@ -8,7 +10,29 @@ DECLARE_REF(Graphics)
class Buffer class Buffer
{ {
public: public:
Buffer(PGraphics graphics, uint64 size, void* data, bool dynamic);
virtual ~Buffer();
MTL::Buffer* getHandle() const
{
return buffers[currentBuffer];
}
uint64 getSize() const
{
return size;
}
void advanceBuffer()
{
currentBuffer = (currentBuffer + 1) % numBuffers;
}
void* map(bool writeOnly = true);
void* mapRegion(uint64 regionOffset, uint64 regionSize, bool writeOnly);
void unmap();
private: private:
PGraphics graphics;
uint32 currentBuffer;
uint64 size;
MTL::Buffer* buffers[Gfx::numFramesBuffered];
uint32 numBuffers;
}; };
DEFINE_REF(Buffer) DEFINE_REF(Buffer)
class VertexBuffer : public Gfx::VertexBuffer, public Buffer class VertexBuffer : public Gfx::VertexBuffer, public Buffer
+75
View File
@@ -1 +1,76 @@
#include "Buffer.h" #include "Buffer.h"
#include "Graphics.h"
#include "Graphics/Buffer.h"
#include "Graphics/Enums.h"
#include "Graphics/Initializer.h"
#include "Metal/MTLResource.hpp"
using namespace Seele;
using namespace Seele::Metal;
Buffer::Buffer(PGraphics graphics, uint64 size, void *data, bool dynamic)
: graphics(graphics), size(size) {
if (dynamic) {
numBuffers = Gfx::numFramesBuffered;
} else {
numBuffers = 1;
}
for (size_t i = 0; i < numBuffers; ++i) {
if (data != nullptr) {
buffers[i] = graphics->getDevice()->newBuffer(
data, size, MTL::ResourceOptionCPUCacheModeDefault);
} else {
buffers[i] = graphics->getDevice()->newBuffer(
size, MTL::ResourceOptionCPUCacheModeDefault);
}
}
}
Buffer::~Buffer() {
for (size_t i = 0; i < numBuffers; ++i) {
buffers[i]->release();
}
}
void *Buffer::map(bool) { return getHandle()->contents(); }
void *Buffer::mapRegion(uint64 regionOffset, uint64, bool) {
return (char *)getHandle()->contents() + regionOffset;
}
void unmap() {}
VertexBuffer::VertexBuffer(PGraphics graphics,
const VertexBufferCreateInfo &createInfo)
: Gfx::VertexBuffer(graphics->getFamilyMapping(), createInfo.numVertices,
createInfo.vertexSize, createInfo.sourceData.owner),
Seele::Metal::Buffer(graphics, createInfo.sourceData.size,
createInfo.sourceData.data, false) {}
VertexBuffer::~VertexBuffer() {}
IndexBuffer::IndexBuffer(PGraphics graphics,
const IndexBufferCreateInfo &createInfo)
: Gfx::IndexBuffer(graphics->getFamilyMapping(), createInfo.sourceData.size,
createInfo.indexType, createInfo.sourceData.owner),
Seele::Metal::Buffer(graphics, createInfo.sourceData.size,
createInfo.sourceData.data, false) {}
IndexBuffer::~IndexBuffer() {}
UniformBuffer::UniformBuffer(PGraphics graphics,
const UniformBufferCreateInfo &createInfo)
: Gfx::UniformBuffer(graphics->getFamilyMapping(), createInfo.sourceData),
Seele::Metal::Buffer(graphics, createInfo.sourceData.size,
createInfo.sourceData.data, createInfo.dynamic) {}
UniformBuffer::~UniformBuffer() {}
ShaderBuffer::ShaderBuffer(PGraphics graphics,
const ShaderBufferCreateInfo &createInfo)
: Gfx::ShaderBuffer(graphics->getFamilyMapping(), createInfo.numElements,
createInfo.sourceData),
Seele::Metal::Buffer(graphics, createInfo.sourceData.size,
createInfo.sourceData.data, createInfo.dynamic) {}
ShaderBuffer::~ShaderBuffer() {}
+11 -8
View File
@@ -1,12 +1,14 @@
#pragma once #pragma once
#include "Graphics/Enums.h"
#include "Graphics/Shader.h" #include "Graphics/Shader.h"
#include "Resources.h" #include "Resources.h"
namespace Seele { namespace Seele {
namespace Metal { namespace Metal {
class Shader { class Shader {
public: public:
Shader(PGraphics graphics); Shader(PGraphics graphics, Gfx::SeShaderStageFlags stage);
virtual ~Shader(); virtual ~Shader();
void create(const ShaderCreateInfo &createInfo); void create(const ShaderCreateInfo &createInfo);
@@ -19,6 +21,7 @@ public:
uint32 getShaderHash() const; uint32 getShaderHash() const;
private: private:
Gfx::SeShaderStageFlags stage;
PGraphics graphics; PGraphics graphics;
MTL::Library* library; MTL::Library* library;
MTL::Function *function; MTL::Function *function;
@@ -26,16 +29,16 @@ private:
}; };
DEFINE_REF(Shader) DEFINE_REF(Shader)
template <typename Base> class ShaderBase : public Base, public Shader { template <typename Base, Gfx::SeShaderStageFlags flags> class ShaderBase : public Base, public Shader {
public: public:
ShaderBase(PGraphics graphics) : Shader(graphics) {} ShaderBase(PGraphics graphics) : Shader(graphics, flags) {}
virtual ~ShaderBase() {} virtual ~ShaderBase() {}
}; };
using VertexShader = ShaderBase<Gfx::VertexShader>; using VertexShader = ShaderBase<Gfx::VertexShader, Gfx::SE_SHADER_STAGE_VERTEX_BIT>;
using FragmentShader = ShaderBase<Gfx::FragmentShader>; using FragmentShader = ShaderBase<Gfx::FragmentShader, Gfx::SE_SHADER_STAGE_FRAGMENT_BIT>;
using ComputeShader = ShaderBase<Gfx::ComputeShader>; using ComputeShader = ShaderBase<Gfx::ComputeShader, Gfx::SE_SHADER_STAGE_COMPUTE_BIT>;
using TaskShader = ShaderBase<Gfx::TaskShader>; using TaskShader = ShaderBase<Gfx::TaskShader, Gfx::SE_SHADER_STAGE_TASK_BIT_NV>;
using MeshShader = ShaderBase<Gfx::MeshShader>; using MeshShader = ShaderBase<Gfx::MeshShader, Gfx::SE_SHADER_STAGE_MESH_BIT_NV>;
DEFINE_REF(VertexShader) DEFINE_REF(VertexShader)
DEFINE_REF(FragmentShader) DEFINE_REF(FragmentShader)
+33 -20
View File
@@ -1,13 +1,16 @@
#include "Shader.h" #include "Shader.h"
#include "Graphics.h" #include "Graphics.h"
#include "Graphics/Enums.h"
#include "Graphics/slang-compile.h" #include "Graphics/slang-compile.h"
#include "Metal/MTLLibrary.hpp" #include "Metal/MTLLibrary.hpp"
#include "metal_irconverter/metal_irconverter.h"
#include <slang.h> #include <slang.h>
using namespace Seele; using namespace Seele;
using namespace Seele::Metal; using namespace Seele::Metal;
Shader::Shader(PGraphics graphics) : graphics(graphics) {} Shader::Shader(PGraphics graphics, Gfx::SeShaderStageFlags stage)
: stage(stage), graphics(graphics) {}
Shader::~Shader() { Shader::~Shader() {
if (function) { if (function) {
function->release(); function->release();
@@ -16,42 +19,52 @@ Shader::~Shader() {
} }
void Shader::create(const ShaderCreateInfo &createInfo) { void Shader::create(const ShaderCreateInfo &createInfo) {
Slang::ComPtr<slang::IBlob> kernelBlob = generateShader(createInfo, SLANG_DXIL); Slang::ComPtr<slang::IBlob> kernelBlob =
thread_local IRCompiler* pCompiler = nullptr; generateShader(createInfo, SLANG_DXIL);
if(pCompiler == nullptr) thread_local IRCompiler *pCompiler = nullptr;
{ if (pCompiler == nullptr) {
pCompiler = IRCompilerCreate(); pCompiler = IRCompilerCreate();
} }
IRCompilerSetEntryPointName(pCompiler, "main"); IRCompilerSetEntryPointName(pCompiler, "main");
IRObject* pDXIL = IRObjectCreateFromDXIL(kernelBlob->getBufferPointer(), kernelBlob->getBufferSize(), IRBytecodeOwnershipNone); IRObject *pDXIL = IRObjectCreateFromDXIL(
(const uint8 *)kernelBlob->getBufferPointer(),
kernelBlob->getBufferSize(), IRBytecodeOwnershipNone);
// Compile DXIL to Metal IR: // Compile DXIL to Metal IR:
IRError* pError = nullptr; IRError *pError = nullptr;
IRObject* pOutIR = IRCompilerAllocCompileAndLink(pCompiler, NULL, pDXIL, &pError); IRObject *pOutIR =
IRCompilerAllocCompileAndLink(pCompiler, NULL, pDXIL, &pError);
if (!pOutIR) if (!pOutIR) {
{
// Inspect pError to determine cause. // Inspect pError to determine cause.
IRErrorDestroy( pError ); IRErrorDestroy(pError);
}
IRShaderStage irStage;
switch (stage) {
case Gfx::SE_SHADER_STAGE_VERTEX_BIT: irStage = IRShaderStageVertex;
case Gfx::SE_SHADER_STAGE_FRAGMENT_BIT: irStage = IRShaderStageFragment;
case Gfx::SE_SHADER_STAGE_COMPUTE_BIT: irStage = IRShaderStageCompute;
case Gfx::SE_SHADER_STAGE_TASK_BIT_NV: irStage = IRShaderStageAmplification;
case Gfx::SE_SHADER_STAGE_MESH_BIT_NV: irStage = IRShaderStageMesh;
} }
// Retrieve Metallib: // Retrieve Metallib:
MetaLibBinary* pMetallib = IRMetalLibBinaryCreate(); IRMetalLibBinary *pMetallib = IRMetalLibBinaryCreate();
IRObjectGetMetalLibBinary(pOutIR, stage, pMetallib); IRObjectGetMetalLibBinary(pOutIR, irStage, pMetallib);
size_t metallibSize = IRMetalLibGetBytecodeSize(pMetallib); size_t metallibSize = IRMetalLibGetBytecodeSize(pMetallib);
uint8_t* metallib = new uint8_t[metallibSize]; uint8_t *metallib = new uint8_t[metallibSize];
IRMetalLibGetBytecode(pMetallib, metallib); IRMetalLibGetBytecode(pMetallib, metallib);
// Store the metallib to custom format or disk, or use to create a MTLLibrary. // Store the metallib to custom format or disk, or use to create a MTLLibrary.
NS::Error* __autoreleasing error = nil; NS::Error *__autoreleasing error = nil;
dispatch_data_t data = dispatch_data_t data = dispatch_data_create(metallib, metallibSize,
dispatch_data_create(metallib, metallibSize, dispatch_get_main_queue(), NULL); dispatch_get_main_queue(), NULL);
library = graphics->getDevice()->newLibrary(data, &error); library = graphics->getDevice()->newLibrary(data, &error);
function = library->newFunction(NS::String::string("main", NS::ASCIIStringEncoding)); function =
library->newFunction(NS::String::string("main", NS::ASCIIStringEncoding));
delete [] metallib; delete[] metallib;
IRMetalLibBinaryDestroy(pMetallib); IRMetalLibBinaryDestroy(pMetallib);
IRObjectDestroy(pDXIL); IRObjectDestroy(pDXIL);
IRObjectDestroy(pOutIR); IRObjectDestroy(pOutIR);
+163 -203
View File
@@ -4,8 +4,7 @@
using namespace Seele; using namespace Seele;
using namespace Seele::Vulkan; using namespace Seele::Vulkan;
struct PendingBuffer struct PendingBuffer {
{
uint64 offset; uint64 offset;
uint64 size; uint64 size;
VkBuffer stagingBuffer; VkBuffer stagingBuffer;
@@ -16,20 +15,13 @@ struct PendingBuffer
static Map<Vulkan::Buffer *, PendingBuffer> pendingBuffers; static Map<Vulkan::Buffer *, PendingBuffer> pendingBuffers;
Buffer::Buffer(PGraphics graphics, Buffer::Buffer(PGraphics graphics, uint64 size, VkBufferUsageFlags usage,
uint64 size, Gfx::QueueType &queueType, bool dynamic, std::string name)
VkBufferUsageFlags usage, : graphics(graphics), currentBuffer(0), size(size), owner(queueType),
Gfx::QueueType &queueType, name(name) {
bool dynamic, if (dynamic) {
std::string name)
: graphics(graphics), currentBuffer(0), size(size), owner(queueType), name(name)
{
if (dynamic)
{
numBuffers = Gfx::numFramesBuffered; numBuffers = Gfx::numFramesBuffered;
} } else {
else
{
numBuffers = 1; numBuffers = 1;
} }
VkBufferCreateInfo info = { VkBufferCreateInfo info = {
@@ -40,40 +32,42 @@ Buffer::Buffer(PGraphics graphics,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
}; };
VmaAllocationCreateInfo allocInfo = { VmaAllocationCreateInfo allocInfo = {
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, .flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT |
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
.usage = VMA_MEMORY_USAGE_AUTO, .usage = VMA_MEMORY_USAGE_AUTO,
}; };
for (uint32 i = 0; i < numBuffers; ++i) for (uint32 i = 0; i < numBuffers; ++i) {
{ vmaCreateBuffer(graphics->getAllocator(), &info, &allocInfo,
vmaCreateBuffer(graphics->getAllocator(), &info, &allocInfo, &buffers[i].buffer, &buffers[i].allocation, &buffers[i].info); &buffers[i].buffer, &buffers[i].allocation,
vmaGetAllocationMemoryProperties(graphics->getAllocator(), buffers[i].allocation, &buffers[i].properties); &buffers[i].info);
//std::cout << "Create buffer " << std::hex << (uint64)buffers[i].buffer << std::dec; vmaGetAllocationMemoryProperties(graphics->getAllocator(),
if (!name.empty()) buffers[i].allocation,
{ &buffers[i].properties);
// std::cout << "Create buffer " << std::hex << (uint64)buffers[i].buffer <<
// std::dec;
if (!name.empty()) {
VkDebugUtilsObjectNameInfoEXT nameInfo = { VkDebugUtilsObjectNameInfoEXT nameInfo = {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.pNext = nullptr, .pNext = nullptr,
.objectType = VK_OBJECT_TYPE_BUFFER, .objectType = VK_OBJECT_TYPE_BUFFER,
.objectHandle = (uint64)buffers[i].buffer, .objectHandle = (uint64)buffers[i].buffer,
.pObjectName = this->name.c_str() .pObjectName = this->name.c_str()};
};
graphics->vkSetDebugUtilsObjectNameEXT(&nameInfo); graphics->vkSetDebugUtilsObjectNameEXT(&nameInfo);
//std::cout << ": " << name; // std::cout << ": " << name;
} }
//std::cout << std::endl; // std::cout << std::endl;
} }
} }
Buffer::~Buffer() Buffer::~Buffer() {
{ for (uint32 i = 0; i < numBuffers; ++i) {
for (uint32 i = 0; i < numBuffers; ++i) graphics->getDestructionManager()->queueBuffer(
{ graphics->getQueueCommands(owner)->getCommands(), buffers[i].buffer,
graphics->getDestructionManager()->queueBuffer(graphics->getQueueCommands(owner)->getCommands(), buffers[i].buffer, buffers[i].allocation); buffers[i].allocation);
} }
} }
void Buffer::executeOwnershipBarrier(Gfx::QueueType newOwner) void Buffer::executeOwnershipBarrier(Gfx::QueueType newOwner) {
{
Gfx::QueueFamilyMapping mapping = graphics->getFamilyMapping(); Gfx::QueueFamilyMapping mapping = graphics->getFamilyMapping();
VkBufferMemoryBarrier barrier = { VkBufferMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
@@ -88,35 +82,25 @@ void Buffer::executeOwnershipBarrier(Gfx::QueueType newOwner)
VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
VkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; VkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
assert(barrier.srcQueueFamilyIndex != barrier.dstQueueFamilyIndex); assert(barrier.srcQueueFamilyIndex != barrier.dstQueueFamilyIndex);
if (owner == Gfx::QueueType::TRANSFER) if (owner == Gfx::QueueType::TRANSFER) {
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
} } else if (owner == Gfx::QueueType::COMPUTE) {
else if (owner == Gfx::QueueType::COMPUTE)
{
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
} } else if (owner == Gfx::QueueType::GRAPHICS) {
else if (owner == Gfx::QueueType::GRAPHICS)
{
barrier.srcAccessMask = getSourceAccessMask(); barrier.srcAccessMask = getSourceAccessMask();
srcStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; srcStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
} }
if (newOwner == Gfx::QueueType::TRANSFER) if (newOwner == Gfx::QueueType::TRANSFER) {
{
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstPool = graphics->getTransferCommands(); dstPool = graphics->getTransferCommands();
} } else if (newOwner == Gfx::QueueType::COMPUTE) {
else if (newOwner == Gfx::QueueType::COMPUTE)
{
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
dstPool = graphics->getComputeCommands(); dstPool = graphics->getComputeCommands();
} } else if (newOwner == Gfx::QueueType::GRAPHICS) {
else if (newOwner == Gfx::QueueType::GRAPHICS)
{
barrier.dstAccessMask = getDestAccessMask(); barrier.dstAccessMask = getDestAccessMask();
dstStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; dstStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
dstPool = graphics->getGraphicsCommands(); dstPool = graphics->getGraphicsCommands();
@@ -124,19 +108,21 @@ void Buffer::executeOwnershipBarrier(Gfx::QueueType newOwner)
VkCommandBuffer srcCommand = sourcePool->getCommands()->getHandle(); VkCommandBuffer srcCommand = sourcePool->getCommands()->getHandle();
VkCommandBuffer dstCommand = dstPool->getCommands()->getHandle(); VkCommandBuffer dstCommand = dstPool->getCommands()->getHandle();
VkBufferMemoryBarrier dynamicBarriers[Gfx::numFramesBuffered]; VkBufferMemoryBarrier dynamicBarriers[Gfx::numFramesBuffered];
for (uint32 i = 0; i < numBuffers; ++i) for (uint32 i = 0; i < numBuffers; ++i) {
{
dynamicBarriers[i] = barrier; dynamicBarriers[i] = barrier;
dynamicBarriers[i].buffer = buffers[i].buffer; dynamicBarriers[i].buffer = buffers[i].buffer;
} }
vkCmdPipelineBarrier(srcCommand, srcStage, srcStage, 0, 0, nullptr, numBuffers, dynamicBarriers, 0, nullptr); vkCmdPipelineBarrier(srcCommand, srcStage, srcStage, 0, 0, nullptr,
vkCmdPipelineBarrier(dstCommand, dstStage, dstStage, 0, 0, nullptr, numBuffers, dynamicBarriers, 0, nullptr); numBuffers, dynamicBarriers, 0, nullptr);
vkCmdPipelineBarrier(dstCommand, dstStage, dstStage, 0, 0, nullptr,
numBuffers, dynamicBarriers, 0, nullptr);
sourcePool->submitCommands(); sourcePool->submitCommands();
} }
void Buffer::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, void Buffer::executePipelineBarrier(VkAccessFlags srcAccess,
VkAccessFlags dstAccess, VkPipelineStageFlags dstStage) VkPipelineStageFlags srcStage,
{ VkAccessFlags dstAccess,
VkPipelineStageFlags dstStage) {
PCommand commandBuffer = graphics->getQueueCommands(owner)->getCommands(); PCommand commandBuffer = graphics->getQueueCommands(owner)->getCommands();
VkBufferMemoryBarrier barrier = { VkBufferMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
@@ -149,21 +135,18 @@ void Buffer::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlag
.size = size, .size = size,
}; };
VkBufferMemoryBarrier dynamicBarriers[Gfx::numFramesBuffered]; VkBufferMemoryBarrier dynamicBarriers[Gfx::numFramesBuffered];
for (uint32 i = 0; i < numBuffers; ++i) for (uint32 i = 0; i < numBuffers; ++i) {
{
dynamicBarriers[i] = barrier; dynamicBarriers[i] = barrier;
dynamicBarriers[i].buffer = buffers[i].buffer; dynamicBarriers[i].buffer = buffers[i].buffer;
} }
vkCmdPipelineBarrier(commandBuffer->getHandle(), srcStage, dstStage, 0, 0, nullptr, numBuffers, dynamicBarriers, 0, nullptr); vkCmdPipelineBarrier(commandBuffer->getHandle(), srcStage, dstStage, 0, 0,
nullptr, numBuffers, dynamicBarriers, 0, nullptr);
} }
void *Buffer::map(bool writeOnly) void *Buffer::map(bool writeOnly) { return mapRegion(0, size, writeOnly); }
{
return mapRegion(0, size, writeOnly);
}
void *Buffer::mapRegion(uint64 regionOffset, uint64 regionSize, bool writeOnly) void *Buffer::mapRegion(uint64 regionOffset, uint64 regionSize,
{ bool writeOnly) {
void *data = nullptr; void *data = nullptr;
PendingBuffer pending; PendingBuffer pending;
@@ -171,14 +154,12 @@ void *Buffer::mapRegion(uint64 regionOffset, uint64 regionSize, bool writeOnly)
pending.prevQueue = owner; pending.prevQueue = owner;
pending.offset = regionOffset; pending.offset = regionOffset;
pending.size = regionSize; pending.size = regionSize;
if (writeOnly) if (writeOnly) {
{ if (buffers[currentBuffer].properties &
if (buffers[currentBuffer].properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
{ VK_CHECK(vmaMapMemory(graphics->getAllocator(),
VK_CHECK(vmaMapMemory(graphics->getAllocator(), buffers[currentBuffer].allocation, &data)); buffers[currentBuffer].allocation, &data));
} } else {
else
{
VkBufferCreateInfo stagingInfo = { VkBufferCreateInfo stagingInfo = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
@@ -191,12 +172,12 @@ void *Buffer::mapRegion(uint64 regionOffset, uint64 regionSize, bool writeOnly)
.usage = VMA_MEMORY_USAGE_AUTO, .usage = VMA_MEMORY_USAGE_AUTO,
.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, .requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
}; };
VK_CHECK(vmaCreateBuffer(graphics->getAllocator(), &stagingInfo, &allocInfo, &pending.stagingBuffer, &pending.allocation, nullptr)); VK_CHECK(vmaCreateBuffer(graphics->getAllocator(), &stagingInfo,
&allocInfo, &pending.stagingBuffer,
&pending.allocation, nullptr));
vmaMapMemory(graphics->getAllocator(), pending.allocation, &data); vmaMapMemory(graphics->getAllocator(), pending.allocation, &data);
} }
} } else {
else
{
assert(false); assert(false);
} }
pendingBuffers[this] = std::move(pending); pendingBuffers[this] = std::move(pending);
@@ -205,21 +186,18 @@ void *Buffer::mapRegion(uint64 regionOffset, uint64 regionSize, bool writeOnly)
return data; return data;
} }
void Buffer::unmap() void Buffer::unmap() {
{
auto found = pendingBuffers.find(this); auto found = pendingBuffers.find(this);
if (found != pendingBuffers.end()) if (found != pendingBuffers.end()) {
{
PendingBuffer &pending = found->value; PendingBuffer &pending = found->value;
if (pending.writeOnly) if (pending.writeOnly) {
{ if (buffers[currentBuffer].properties &
if (buffers[currentBuffer].properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
{ vmaUnmapMemory(graphics->getAllocator(),
vmaUnmapMemory(graphics->getAllocator(), buffers[currentBuffer].allocation); buffers[currentBuffer].allocation);
} } else {
else vmaFlushAllocation(graphics->getAllocator(), pending.allocation, 0,
{ VK_WHOLE_SIZE);
vmaFlushAllocation(graphics->getAllocator(), pending.allocation, 0, VK_WHOLE_SIZE);
vmaUnmapMemory(graphics->getAllocator(), pending.allocation); vmaUnmapMemory(graphics->getAllocator(), pending.allocation);
PCommand command = graphics->getQueueCommands(owner)->getCommands(); PCommand command = graphics->getQueueCommands(owner)->getCommands();
VkCommandBuffer cmdHandle = command->getHandle(); VkCommandBuffer cmdHandle = command->getHandle();
@@ -240,8 +218,11 @@ void Buffer::unmap()
.offset = 0, .offset = 0,
.size = size, .size = size,
}; };
vkCmdPipelineBarrier(cmdHandle, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &barrier, 0, nullptr); vkCmdPipelineBarrier(cmdHandle, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
vkCmdCopyBuffer(cmdHandle, pending.stagingBuffer, buffers[currentBuffer].buffer, 1, &region); VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1,
&barrier, 0, nullptr);
vkCmdCopyBuffer(cmdHandle, pending.stagingBuffer,
buffers[currentBuffer].buffer, 1, &region);
barrier = { barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.pNext = nullptr, .pNext = nullptr,
@@ -253,8 +234,11 @@ void Buffer::unmap()
.offset = 0, .offset = 0,
.size = size, .size = size,
}; };
vkCmdPipelineBarrier(cmdHandle, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 1, &barrier, 0, nullptr); vkCmdPipelineBarrier(cmdHandle, VK_PIPELINE_STAGE_TRANSFER_BIT,
graphics->getDestructionManager()->queueBuffer(command, pending.stagingBuffer, pending.allocation); VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr,
1, &barrier, 0, nullptr);
graphics->getDestructionManager()->queueBuffer(
command, pending.stagingBuffer, pending.allocation);
} }
} }
// requestOwnershipTransfer(pending.prevQueue); // requestOwnershipTransfer(pending.prevQueue);
@@ -263,26 +247,23 @@ void Buffer::unmap()
} }
} }
UniformBuffer::UniformBuffer(PGraphics graphics, const UniformBufferCreateInfo &createInfo) UniformBuffer::UniformBuffer(PGraphics graphics,
const UniformBufferCreateInfo &createInfo)
: Gfx::UniformBuffer(graphics->getFamilyMapping(), createInfo.sourceData), : Gfx::UniformBuffer(graphics->getFamilyMapping(), createInfo.sourceData),
Vulkan::Buffer(graphics, createInfo.sourceData.size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, currentOwner, createInfo.dynamic, createInfo.name) Vulkan::Buffer(graphics, createInfo.sourceData.size,
{ VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, currentOwner,
if (createInfo.sourceData.data != nullptr) createInfo.dynamic, createInfo.name) {
{ if (createInfo.sourceData.data != nullptr) {
void *data = map(); void *data = map();
std::memcpy(data, createInfo.sourceData.data, createInfo.sourceData.size); std::memcpy(data, createInfo.sourceData.data, createInfo.sourceData.size);
unmap(); unmap();
} }
} }
UniformBuffer::~UniformBuffer() UniformBuffer::~UniformBuffer() {}
{
}
bool UniformBuffer::updateContents(const DataSource &sourceData) bool UniformBuffer::updateContents(const DataSource &sourceData) {
{ if (!Gfx::UniformBuffer::updateContents(sourceData)) {
if (!Gfx::UniformBuffer::updateContents(sourceData))
{
// no update was performed, skip // no update was performed, skip
return false; return false;
} }
@@ -292,54 +273,49 @@ bool UniformBuffer::updateContents(const DataSource &sourceData)
return true; return true;
} }
void UniformBuffer::beginFrame() void UniformBuffer::beginFrame() { Vulkan::Buffer::advanceBuffer(); }
{
Vulkan::Buffer::advanceBuffer();
}
void UniformBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) void UniformBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) {
{
Gfx::QueueOwnedResource::transferOwnership(newOwner); Gfx::QueueOwnedResource::transferOwnership(newOwner);
} }
void UniformBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) void UniformBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) {
{
Vulkan::Buffer::executeOwnershipBarrier(newOwner); Vulkan::Buffer::executeOwnershipBarrier(newOwner);
} }
void UniformBuffer::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, void UniformBuffer::executePipelineBarrier(VkAccessFlags srcAccess,
VkAccessFlags dstAccess, VkPipelineStageFlags dstStage) VkPipelineStageFlags srcStage,
{ VkAccessFlags dstAccess,
Vulkan::Buffer::executePipelineBarrier(srcAccess, srcStage, dstAccess, dstStage); VkPipelineStageFlags dstStage) {
Vulkan::Buffer::executePipelineBarrier(srcAccess, srcStage, dstAccess,
dstStage);
} }
VkAccessFlags UniformBuffer::getSourceAccessMask() VkAccessFlags UniformBuffer::getSourceAccessMask() {
{
return VK_ACCESS_MEMORY_WRITE_BIT; return VK_ACCESS_MEMORY_WRITE_BIT;
} }
VkAccessFlags UniformBuffer::getDestAccessMask() VkAccessFlags UniformBuffer::getDestAccessMask() {
{
return VK_ACCESS_UNIFORM_READ_BIT; return VK_ACCESS_UNIFORM_READ_BIT;
} }
ShaderBuffer::ShaderBuffer(PGraphics graphics, const ShaderBufferCreateInfo &sourceData) ShaderBuffer::ShaderBuffer(PGraphics graphics,
: Gfx::ShaderBuffer(graphics->getFamilyMapping(), sourceData.numElements, sourceData.sourceData), Vulkan::Buffer(graphics, sourceData.sourceData.size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, currentOwner, sourceData.dynamic, sourceData.name) const ShaderBufferCreateInfo &sourceData)
{ : Gfx::ShaderBuffer(graphics->getFamilyMapping(), sourceData.numElements,
if (sourceData.sourceData.data != nullptr) sourceData.sourceData),
{ Vulkan::Buffer(graphics, sourceData.sourceData.size,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, currentOwner,
sourceData.dynamic, sourceData.name) {
if (sourceData.sourceData.data != nullptr) {
void *data = map(); void *data = map();
std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size); std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size);
unmap(); unmap();
} }
} }
ShaderBuffer::~ShaderBuffer() ShaderBuffer::~ShaderBuffer() {}
{
}
bool ShaderBuffer::updateContents(const DataSource &sourceData) bool ShaderBuffer::updateContents(const DataSource &sourceData) {
{
assert(sourceData.size <= getSize()); assert(sourceData.size <= getSize());
Gfx::ShaderBuffer::updateContents(sourceData); Gfx::ShaderBuffer::updateContents(sourceData);
// We always want to update, as the contents could be different on the GPU // We always want to update, as the contents could be different on the GPU
@@ -349,148 +325,132 @@ bool ShaderBuffer::updateContents(const DataSource &sourceData)
return true; return true;
} }
void ShaderBuffer::beginFrame() void ShaderBuffer::beginFrame() { Vulkan::Buffer::advanceBuffer(); }
{
Vulkan::Buffer::advanceBuffer();
}
void ShaderBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) void ShaderBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) {
{
Gfx::QueueOwnedResource::transferOwnership(newOwner); Gfx::QueueOwnedResource::transferOwnership(newOwner);
} }
void ShaderBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) void ShaderBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) {
{
Vulkan::Buffer::executeOwnershipBarrier(newOwner); Vulkan::Buffer::executeOwnershipBarrier(newOwner);
} }
void ShaderBuffer::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, void ShaderBuffer::executePipelineBarrier(VkAccessFlags srcAccess,
VkAccessFlags dstAccess, VkPipelineStageFlags dstStage) VkPipelineStageFlags srcStage,
{ VkAccessFlags dstAccess,
Vulkan::Buffer::executePipelineBarrier(srcAccess, srcStage, dstAccess, dstStage); VkPipelineStageFlags dstStage) {
Vulkan::Buffer::executePipelineBarrier(srcAccess, srcStage, dstAccess,
dstStage);
} }
VkAccessFlags ShaderBuffer::getSourceAccessMask() VkAccessFlags ShaderBuffer::getSourceAccessMask() {
{
return VK_ACCESS_MEMORY_WRITE_BIT; return VK_ACCESS_MEMORY_WRITE_BIT;
} }
VkAccessFlags ShaderBuffer::getDestAccessMask() VkAccessFlags ShaderBuffer::getDestAccessMask() {
{
return VK_ACCESS_MEMORY_READ_BIT; return VK_ACCESS_MEMORY_READ_BIT;
} }
VertexBuffer::VertexBuffer(PGraphics graphics, const VertexBufferCreateInfo &sourceData) VertexBuffer::VertexBuffer(PGraphics graphics,
: Gfx::VertexBuffer(graphics->getFamilyMapping(), sourceData.numVertices, sourceData.vertexSize, sourceData.sourceData.owner), Vulkan::Buffer(graphics, sourceData.sourceData.size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, currentOwner, false, sourceData.name) const VertexBufferCreateInfo &sourceData)
{ : Gfx::VertexBuffer(graphics->getFamilyMapping(), sourceData.numVertices,
if (sourceData.sourceData.data != nullptr) sourceData.vertexSize, sourceData.sourceData.owner),
{ Vulkan::Buffer(graphics, sourceData.sourceData.size,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, currentOwner, false,
sourceData.name) {
if (sourceData.sourceData.data != nullptr) {
void *data = map(); void *data = map();
std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size); std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size);
unmap(); unmap();
} }
} }
VertexBuffer::~VertexBuffer() VertexBuffer::~VertexBuffer() {}
{
}
void VertexBuffer::updateRegion(DataSource update) void VertexBuffer::updateRegion(DataSource update) {
{
void *data = mapRegion(update.offset, update.size); void *data = mapRegion(update.offset, update.size);
std::memcpy(data, update.data, update.size); std::memcpy(data, update.data, update.size);
unmap(); unmap();
} }
void VertexBuffer::download(Array<uint8> &buffer) void VertexBuffer::download(Array<uint8> &buffer) {
{
void *data = map(false); void *data = map(false);
buffer.resize(size); buffer.resize(size);
std::memcpy(buffer.data(), data, size); std::memcpy(buffer.data(), data, size);
unmap(); unmap();
} }
void VertexBuffer::beginFrame() void VertexBuffer::beginFrame() { Vulkan::Buffer::advanceBuffer(); }
{
Vulkan::Buffer::advanceBuffer();
}
void VertexBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) void VertexBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) {
{
Gfx::QueueOwnedResource::transferOwnership(newOwner); Gfx::QueueOwnedResource::transferOwnership(newOwner);
} }
void VertexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) void VertexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) {
{
Vulkan::Buffer::executeOwnershipBarrier(newOwner); Vulkan::Buffer::executeOwnershipBarrier(newOwner);
} }
void VertexBuffer::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, void VertexBuffer::executePipelineBarrier(VkAccessFlags srcAccess,
VkAccessFlags dstAccess, VkPipelineStageFlags dstStage) VkPipelineStageFlags srcStage,
{ VkAccessFlags dstAccess,
Vulkan::Buffer::executePipelineBarrier(srcAccess, srcStage, dstAccess, dstStage); VkPipelineStageFlags dstStage) {
Vulkan::Buffer::executePipelineBarrier(srcAccess, srcStage, dstAccess,
dstStage);
} }
VkAccessFlags VertexBuffer::getSourceAccessMask() VkAccessFlags VertexBuffer::getSourceAccessMask() {
{
return VK_ACCESS_MEMORY_WRITE_BIT; return VK_ACCESS_MEMORY_WRITE_BIT;
} }
VkAccessFlags VertexBuffer::getDestAccessMask() VkAccessFlags VertexBuffer::getDestAccessMask() {
{
return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
} }
IndexBuffer::IndexBuffer(PGraphics graphics, const IndexBufferCreateInfo &sourceData) IndexBuffer::IndexBuffer(PGraphics graphics,
: Gfx::IndexBuffer(graphics->getFamilyMapping(), sourceData.sourceData.size, sourceData.indexType, sourceData.sourceData.owner), Vulkan::Buffer(graphics, sourceData.sourceData.size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, currentOwner, false, sourceData.name) const IndexBufferCreateInfo &sourceData)
{ : Gfx::IndexBuffer(graphics->getFamilyMapping(), sourceData.sourceData.size,
if (sourceData.sourceData.data != nullptr) sourceData.indexType, sourceData.sourceData.owner),
{ Vulkan::Buffer(graphics, sourceData.sourceData.size,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT, currentOwner, false,
sourceData.name) {
if (sourceData.sourceData.data != nullptr) {
void *data = map(); void *data = map();
std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size); std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size);
unmap(); unmap();
} }
} }
IndexBuffer::~IndexBuffer() IndexBuffer::~IndexBuffer() {}
{
}
void IndexBuffer::download(Array<uint8> &buffer) void IndexBuffer::download(Array<uint8> &buffer) {
{
void *data = map(false); void *data = map(false);
buffer.resize(size); buffer.resize(size);
std::memcpy(buffer.data(), data, size); std::memcpy(buffer.data(), data, size);
unmap(); unmap();
} }
void IndexBuffer::beginFrame() void IndexBuffer::beginFrame() { Vulkan::Buffer::advanceBuffer(); }
{
Vulkan::Buffer::advanceBuffer();
}
void IndexBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) void IndexBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) {
{
Gfx::QueueOwnedResource::transferOwnership(newOwner); Gfx::QueueOwnedResource::transferOwnership(newOwner);
} }
void IndexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) void IndexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) {
{
Vulkan::Buffer::executeOwnershipBarrier(newOwner); Vulkan::Buffer::executeOwnershipBarrier(newOwner);
} }
void IndexBuffer::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, void IndexBuffer::executePipelineBarrier(VkAccessFlags srcAccess,
VkAccessFlags dstAccess, VkPipelineStageFlags dstStage) VkPipelineStageFlags srcStage,
{ VkAccessFlags dstAccess,
Vulkan::Buffer::executePipelineBarrier(srcAccess, srcStage, dstAccess, dstStage); VkPipelineStageFlags dstStage) {
Vulkan::Buffer::executePipelineBarrier(srcAccess, srcStage, dstAccess,
dstStage);
} }
VkAccessFlags IndexBuffer::getSourceAccessMask() VkAccessFlags IndexBuffer::getSourceAccessMask() {
{
return VK_ACCESS_MEMORY_WRITE_BIT; return VK_ACCESS_MEMORY_WRITE_BIT;
} }
VkAccessFlags IndexBuffer::getDestAccessMask() VkAccessFlags IndexBuffer::getDestAccessMask() {
{
return VK_ACCESS_INDEX_READ_BIT; return VK_ACCESS_INDEX_READ_BIT;
} }