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);
+380 -420
View File
@@ -4,493 +4,453 @@
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; VmaAllocation allocation;
VmaAllocation allocation; Gfx::QueueType prevQueue;
Gfx::QueueType prevQueue; bool writeOnly;
bool writeOnly;
}; };
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) numBuffers = Gfx::numFramesBuffered;
: graphics(graphics), currentBuffer(0), size(size), owner(queueType), name(name) } else {
{ numBuffers = 1;
if (dynamic) }
{ VkBufferCreateInfo info = {
numBuffers = Gfx::numFramesBuffered; .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
} .pNext = nullptr,
else .size = size,
{ .usage = usage,
numBuffers = 1; .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
} };
VkBufferCreateInfo info = { VmaAllocationCreateInfo allocInfo = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT |
.pNext = nullptr, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
.size = size, .usage = VMA_MEMORY_USAGE_AUTO,
.usage = usage, };
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, for (uint32 i = 0; i < numBuffers; ++i) {
}; vmaCreateBuffer(graphics->getAllocator(), &info, &allocInfo,
VmaAllocationCreateInfo allocInfo = { &buffers[i].buffer, &buffers[i].allocation,
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, &buffers[i].info);
.usage = VMA_MEMORY_USAGE_AUTO, vmaGetAllocationMemoryProperties(graphics->getAllocator(),
}; buffers[i].allocation,
for (uint32 i = 0; i < numBuffers; ++i) &buffers[i].properties);
{ // std::cout << "Create buffer " << std::hex << (uint64)buffers[i].buffer <<
vmaCreateBuffer(graphics->getAllocator(), &info, &allocInfo, &buffers[i].buffer, &buffers[i].allocation, &buffers[i].info); // std::dec;
vmaGetAllocationMemoryProperties(graphics->getAllocator(), buffers[i].allocation, &buffers[i].properties); if (!name.empty()) {
//std::cout << "Create buffer " << std::hex << (uint64)buffers[i].buffer << std::dec; VkDebugUtilsObjectNameInfoEXT nameInfo = {
if (!name.empty()) .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
{ .pNext = nullptr,
VkDebugUtilsObjectNameInfoEXT nameInfo = { .objectType = VK_OBJECT_TYPE_BUFFER,
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, .objectHandle = (uint64)buffers[i].buffer,
.pNext = nullptr, .pObjectName = this->name.c_str()};
.objectType = VK_OBJECT_TYPE_BUFFER, graphics->vkSetDebugUtilsObjectNameEXT(&nameInfo);
.objectHandle = (uint64)buffers[i].buffer, // std::cout << ": " << name;
.pObjectName = this->name.c_str()
};
graphics->vkSetDebugUtilsObjectNameEXT(&nameInfo);
//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, .pNext = nullptr,
.pNext = nullptr, .srcQueueFamilyIndex = mapping.getQueueTypeFamilyIndex(owner),
.srcQueueFamilyIndex = mapping.getQueueTypeFamilyIndex(owner), .dstQueueFamilyIndex = mapping.getQueueTypeFamilyIndex(newOwner),
.dstQueueFamilyIndex = mapping.getQueueTypeFamilyIndex(newOwner), .offset = 0,
.offset = 0, .size = size,
.size = size, };
}; PCommandPool sourcePool = graphics->getQueueCommands(owner);
PCommandPool sourcePool = graphics->getQueueCommands(owner); PCommandPool dstPool = nullptr;
PCommandPool dstPool = nullptr; 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;
{ srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; } else if (owner == Gfx::QueueType::COMPUTE) {
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
} srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
else if (owner == Gfx::QueueType::COMPUTE) } else if (owner == Gfx::QueueType::GRAPHICS) {
{ barrier.srcAccessMask = getSourceAccessMask();
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; srcStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; }
} if (newOwner == Gfx::QueueType::TRANSFER) {
else if (owner == Gfx::QueueType::GRAPHICS) barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
{ dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
barrier.srcAccessMask = getSourceAccessMask(); dstPool = graphics->getTransferCommands();
srcStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; } else if (newOwner == Gfx::QueueType::COMPUTE) {
} barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
if (newOwner == Gfx::QueueType::TRANSFER) dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
{ dstPool = graphics->getComputeCommands();
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; } else if (newOwner == Gfx::QueueType::GRAPHICS) {
dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; barrier.dstAccessMask = getDestAccessMask();
dstPool = graphics->getTransferCommands(); dstStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
} dstPool = graphics->getGraphicsCommands();
else if (newOwner == Gfx::QueueType::COMPUTE) }
{ VkCommandBuffer srcCommand = sourcePool->getCommands()->getHandle();
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; VkCommandBuffer dstCommand = dstPool->getCommands()->getHandle();
dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; VkBufferMemoryBarrier dynamicBarriers[Gfx::numFramesBuffered];
dstPool = graphics->getComputeCommands(); for (uint32 i = 0; i < numBuffers; ++i) {
} dynamicBarriers[i] = barrier;
else if (newOwner == Gfx::QueueType::GRAPHICS) dynamicBarriers[i].buffer = buffers[i].buffer;
{ }
barrier.dstAccessMask = getDestAccessMask(); vkCmdPipelineBarrier(srcCommand, srcStage, srcStage, 0, 0, nullptr,
dstStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; numBuffers, dynamicBarriers, 0, nullptr);
dstPool = graphics->getGraphicsCommands(); vkCmdPipelineBarrier(dstCommand, dstStage, dstStage, 0, 0, nullptr,
} numBuffers, dynamicBarriers, 0, nullptr);
VkCommandBuffer srcCommand = sourcePool->getCommands()->getHandle(); sourcePool->submitCommands();
VkCommandBuffer dstCommand = dstPool->getCommands()->getHandle();
VkBufferMemoryBarrier dynamicBarriers[Gfx::numFramesBuffered];
for (uint32 i = 0; i < numBuffers; ++i)
{
dynamicBarriers[i] = barrier;
dynamicBarriers[i].buffer = buffers[i].buffer;
}
vkCmdPipelineBarrier(srcCommand, srcStage, srcStage, 0, 0, nullptr, numBuffers, dynamicBarriers, 0, nullptr);
vkCmdPipelineBarrier(dstCommand, dstStage, dstStage, 0, 0, nullptr, numBuffers, dynamicBarriers, 0, nullptr);
sourcePool->submitCommands();
} }
void Buffer::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage, void Buffer::executePipelineBarrier(VkAccessFlags srcAccess,
VkAccessFlags dstAccess, VkPipelineStageFlags dstStage) VkPipelineStageFlags srcStage,
{ VkAccessFlags dstAccess,
PCommand commandBuffer = graphics->getQueueCommands(owner)->getCommands(); VkPipelineStageFlags dstStage) {
VkBufferMemoryBarrier barrier = { PCommand commandBuffer = graphics->getQueueCommands(owner)->getCommands();
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, VkBufferMemoryBarrier barrier = {
.pNext = nullptr, .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = srcAccess, .pNext = nullptr,
.dstAccessMask = dstAccess, .srcAccessMask = srcAccess,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstAccessMask = dstAccess,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.offset = 0, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.size = size, .offset = 0,
}; .size = size,
VkBufferMemoryBarrier dynamicBarriers[Gfx::numFramesBuffered]; };
for (uint32 i = 0; i < numBuffers; ++i) VkBufferMemoryBarrier dynamicBarriers[Gfx::numFramesBuffered];
{ 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 *data = nullptr;
PendingBuffer pending;
pending.writeOnly = writeOnly;
pending.prevQueue = owner;
pending.offset = regionOffset;
pending.size = regionSize;
if (writeOnly) {
if (buffers[currentBuffer].properties &
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
VK_CHECK(vmaMapMemory(graphics->getAllocator(),
buffers[currentBuffer].allocation, &data));
} else {
VkBufferCreateInfo stagingInfo = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = regionSize,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
VmaAllocationCreateInfo allocInfo = {
.usage = VMA_MEMORY_USAGE_AUTO,
.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
};
VK_CHECK(vmaCreateBuffer(graphics->getAllocator(), &stagingInfo,
&allocInfo, &pending.stagingBuffer,
&pending.allocation, nullptr));
vmaMapMemory(graphics->getAllocator(), pending.allocation, &data);
}
} else {
assert(false);
}
pendingBuffers[this] = std::move(pending);
assert(data);
return data;
} }
void *Buffer::mapRegion(uint64 regionOffset, uint64 regionSize, bool writeOnly) void Buffer::unmap() {
{ auto found = pendingBuffers.find(this);
void *data = nullptr; if (found != pendingBuffers.end()) {
PendingBuffer &pending = found->value;
if (pending.writeOnly) {
if (buffers[currentBuffer].properties &
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
vmaUnmapMemory(graphics->getAllocator(),
buffers[currentBuffer].allocation);
} else {
vmaFlushAllocation(graphics->getAllocator(), pending.allocation, 0,
VK_WHOLE_SIZE);
vmaUnmapMemory(graphics->getAllocator(), pending.allocation);
PCommand command = graphics->getQueueCommands(owner)->getCommands();
VkCommandBuffer cmdHandle = command->getHandle();
PendingBuffer pending; VkBufferCopy region = {
pending.writeOnly = writeOnly; .srcOffset = 0,
pending.prevQueue = owner; .dstOffset = pending.offset,
pending.offset = regionOffset; .size = pending.size,
pending.size = regionSize; };
if (writeOnly) VkBufferMemoryBarrier barrier = {
{ .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
if (buffers[currentBuffer].properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) .pNext = nullptr,
{ .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT,
VK_CHECK(vmaMapMemory(graphics->getAllocator(), buffers[currentBuffer].allocation, &data)); .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
} .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
else .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
{ .buffer = buffers[currentBuffer].buffer,
VkBufferCreateInfo stagingInfo = { .offset = 0,
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .size = size,
.pNext = nullptr, };
.flags = 0, vkCmdPipelineBarrier(cmdHandle, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
.size = regionSize, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &barrier, 0, nullptr);
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, vkCmdCopyBuffer(cmdHandle, pending.stagingBuffer,
}; buffers[currentBuffer].buffer, 1, &region);
VmaAllocationCreateInfo allocInfo = { barrier = {
.usage = VMA_MEMORY_USAGE_AUTO, .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, .pNext = nullptr,
}; .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
VK_CHECK(vmaCreateBuffer(graphics->getAllocator(), &stagingInfo, &allocInfo, &pending.stagingBuffer, &pending.allocation, nullptr)); .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
vmaMapMemory(graphics->getAllocator(), pending.allocation, &data); .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
} .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = buffers[currentBuffer].buffer,
.offset = 0,
.size = size,
};
vkCmdPipelineBarrier(cmdHandle, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr,
1, &barrier, 0, nullptr);
graphics->getDestructionManager()->queueBuffer(
command, pending.stagingBuffer, pending.allocation);
}
} }
else // requestOwnershipTransfer(pending.prevQueue);
{
assert(false);
}
pendingBuffers[this] = std::move(pending);
assert(data); pendingBuffers.erase(this);
return data; }
} }
void Buffer::unmap() UniformBuffer::UniformBuffer(PGraphics graphics,
{ const UniformBufferCreateInfo &createInfo)
auto found = pendingBuffers.find(this);
if (found != pendingBuffers.end())
{
PendingBuffer &pending = found->value;
if (pending.writeOnly)
{
if (buffers[currentBuffer].properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
{
vmaUnmapMemory(graphics->getAllocator(), buffers[currentBuffer].allocation);
}
else
{
vmaFlushAllocation(graphics->getAllocator(), pending.allocation, 0, VK_WHOLE_SIZE);
vmaUnmapMemory(graphics->getAllocator(), pending.allocation);
PCommand command = graphics->getQueueCommands(owner)->getCommands();
VkCommandBuffer cmdHandle = command->getHandle();
VkBufferCopy region = {
.srcOffset = 0,
.dstOffset = pending.offset,
.size = pending.size,
};
VkBufferMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = buffers[currentBuffer].buffer,
.offset = 0,
.size = size,
};
vkCmdPipelineBarrier(cmdHandle, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &barrier, 0, nullptr);
vkCmdCopyBuffer(cmdHandle, pending.stagingBuffer, buffers[currentBuffer].buffer, 1, &region);
barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = buffers[currentBuffer].buffer,
.offset = 0,
.size = size,
};
vkCmdPipelineBarrier(cmdHandle, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 1, &barrier, 0, nullptr);
graphics->getDestructionManager()->queueBuffer(command, pending.stagingBuffer, pending.allocation);
}
}
// requestOwnershipTransfer(pending.prevQueue);
pendingBuffers.erase(this);
}
}
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();
std::memcpy(data, createInfo.sourceData.data, createInfo.sourceData.size);
unmap();
}
}
UniformBuffer::~UniformBuffer()
{
}
bool UniformBuffer::updateContents(const DataSource &sourceData)
{
if (!Gfx::UniformBuffer::updateContents(sourceData))
{
// no update was performed, skip
return false;
}
void *data = map(); void *data = map();
std::memcpy(data, sourceData.data, sourceData.size); std::memcpy(data, createInfo.sourceData.data, createInfo.sourceData.size);
unmap(); unmap();
return true; }
} }
void UniformBuffer::beginFrame() UniformBuffer::~UniformBuffer() {}
{
Vulkan::Buffer::advanceBuffer(); bool UniformBuffer::updateContents(const DataSource &sourceData) {
if (!Gfx::UniformBuffer::updateContents(sourceData)) {
// no update was performed, skip
return false;
}
void *data = map();
std::memcpy(data, sourceData.data, sourceData.size);
unmap();
return true;
} }
void UniformBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) void UniformBuffer::beginFrame() { Vulkan::Buffer::advanceBuffer(); }
{
Gfx::QueueOwnedResource::transferOwnership(newOwner); void UniformBuffer::requestOwnershipTransfer(Gfx::QueueType 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,
void *data = map(); VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, currentOwner,
std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size); sourceData.dynamic, sourceData.name) {
unmap(); if (sourceData.sourceData.data != nullptr) {
}
}
ShaderBuffer::~ShaderBuffer()
{
}
bool ShaderBuffer::updateContents(const DataSource &sourceData)
{
assert(sourceData.size <= getSize());
Gfx::ShaderBuffer::updateContents(sourceData);
// We always want to update, as the contents could be different on the GPU
void *data = map(); void *data = map();
std::memcpy(data, sourceData.data, sourceData.size); std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size);
unmap(); unmap();
return true; }
} }
void ShaderBuffer::beginFrame() ShaderBuffer::~ShaderBuffer() {}
{
Vulkan::Buffer::advanceBuffer(); bool ShaderBuffer::updateContents(const DataSource &sourceData) {
assert(sourceData.size <= getSize());
Gfx::ShaderBuffer::updateContents(sourceData);
// We always want to update, as the contents could be different on the GPU
void *data = map();
std::memcpy(data, sourceData.data, sourceData.size);
unmap();
return true;
} }
void ShaderBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) void ShaderBuffer::beginFrame() { Vulkan::Buffer::advanceBuffer(); }
{
Gfx::QueueOwnedResource::transferOwnership(newOwner); void ShaderBuffer::requestOwnershipTransfer(Gfx::QueueType 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,
void *data = map(); VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, currentOwner, false,
std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size); sourceData.name) {
unmap(); if (sourceData.sourceData.data != nullptr) {
} void *data = map();
} std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size);
VertexBuffer::~VertexBuffer()
{
}
void VertexBuffer::updateRegion(DataSource update)
{
void *data = mapRegion(update.offset, update.size);
std::memcpy(data, update.data, update.size);
unmap(); unmap();
}
} }
void VertexBuffer::download(Array<uint8> &buffer) VertexBuffer::~VertexBuffer() {}
{
void *data = map(false); void VertexBuffer::updateRegion(DataSource update) {
buffer.resize(size); void *data = mapRegion(update.offset, update.size);
std::memcpy(buffer.data(), data, size); std::memcpy(data, update.data, update.size);
unmap();
}
void VertexBuffer::download(Array<uint8> &buffer) {
void *data = map(false);
buffer.resize(size);
std::memcpy(buffer.data(), data, size);
unmap();
}
void VertexBuffer::beginFrame() { Vulkan::Buffer::advanceBuffer(); }
void VertexBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) {
Gfx::QueueOwnedResource::transferOwnership(newOwner);
}
void VertexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) {
Vulkan::Buffer::executeOwnershipBarrier(newOwner);
}
void VertexBuffer::executePipelineBarrier(VkAccessFlags srcAccess,
VkPipelineStageFlags srcStage,
VkAccessFlags dstAccess,
VkPipelineStageFlags dstStage) {
Vulkan::Buffer::executePipelineBarrier(srcAccess, srcStage, dstAccess,
dstStage);
}
VkAccessFlags VertexBuffer::getSourceAccessMask() {
return VK_ACCESS_MEMORY_WRITE_BIT;
}
VkAccessFlags VertexBuffer::getDestAccessMask() {
return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
}
IndexBuffer::IndexBuffer(PGraphics graphics,
const IndexBufferCreateInfo &sourceData)
: 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) {
if (sourceData.sourceData.data != nullptr) {
void *data = map();
std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size);
unmap(); unmap();
}
} }
void VertexBuffer::beginFrame() IndexBuffer::~IndexBuffer() {}
{
Vulkan::Buffer::advanceBuffer(); void IndexBuffer::download(Array<uint8> &buffer) {
void *data = map(false);
buffer.resize(size);
std::memcpy(buffer.data(), data, size);
unmap();
} }
void VertexBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) void IndexBuffer::beginFrame() { Vulkan::Buffer::advanceBuffer(); }
{
Gfx::QueueOwnedResource::transferOwnership(newOwner); void IndexBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) {
Gfx::QueueOwnedResource::transferOwnership(newOwner);
} }
void VertexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) void IndexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) {
{ Vulkan::Buffer::executeOwnershipBarrier(newOwner);
Vulkan::Buffer::executeOwnershipBarrier(newOwner);
} }
void VertexBuffer::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 VertexBuffer::getSourceAccessMask() VkAccessFlags IndexBuffer::getSourceAccessMask() {
{ return VK_ACCESS_MEMORY_WRITE_BIT;
return VK_ACCESS_MEMORY_WRITE_BIT;
} }
VkAccessFlags VertexBuffer::getDestAccessMask() VkAccessFlags IndexBuffer::getDestAccessMask() {
{ return VK_ACCESS_INDEX_READ_BIT;
return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
}
IndexBuffer::IndexBuffer(PGraphics graphics, const IndexBufferCreateInfo &sourceData)
: 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)
{
if (sourceData.sourceData.data != nullptr)
{
void *data = map();
std::memcpy(data, sourceData.sourceData.data, sourceData.sourceData.size);
unmap();
}
}
IndexBuffer::~IndexBuffer()
{
}
void IndexBuffer::download(Array<uint8> &buffer)
{
void *data = map(false);
buffer.resize(size);
std::memcpy(buffer.data(), data, size);
unmap();
}
void IndexBuffer::beginFrame()
{
Vulkan::Buffer::advanceBuffer();
}
void IndexBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner)
{
Gfx::QueueOwnedResource::transferOwnership(newOwner);
}
void IndexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner)
{
Vulkan::Buffer::executeOwnershipBarrier(newOwner);
}
void IndexBuffer::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcStage,
VkAccessFlags dstAccess, VkPipelineStageFlags dstStage)
{
Vulkan::Buffer::executePipelineBarrier(srcAccess, srcStage, dstAccess, dstStage);
}
VkAccessFlags IndexBuffer::getSourceAccessMask()
{
return VK_ACCESS_MEMORY_WRITE_BIT;
}
VkAccessFlags IndexBuffer::getDestAccessMask()
{
return VK_ACCESS_INDEX_READ_BIT;
} }