Implementing Commandbuffers
This commit is contained in:
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.default.configurationProvider": "go2sh.cmake-integration",
|
||||||
|
"telemetry.enableTelemetry": false,
|
||||||
|
"cmake.buildDirectory": "${workspaceFolder}/bin/${buildType}",
|
||||||
|
"files.associations": {
|
||||||
|
"xstring": "cpp"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ set(GLFW_ROOT ${EXTERNAL_ROOT}/glfw)
|
|||||||
set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE})
|
set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE})
|
||||||
set(RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
set(RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR})
|
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR})
|
||||||
|
set(Boost_DETAILED_FAILURE_MSG TRUE)
|
||||||
|
|
||||||
# Configuration types
|
# Configuration types
|
||||||
SET(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configs" FORCE)
|
SET(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configs" FORCE)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ namespace Seele
|
|||||||
{
|
{
|
||||||
namespace Gfx
|
namespace Gfx
|
||||||
{
|
{
|
||||||
|
static bool useAsyncCompute = true;
|
||||||
|
|
||||||
typedef uint32_t SeFlags;
|
typedef uint32_t SeFlags;
|
||||||
typedef uint32_t SeBool32;
|
typedef uint32_t SeBool32;
|
||||||
typedef uint64_t SeDeviceSize;
|
typedef uint64_t SeDeviceSize;
|
||||||
|
|||||||
@@ -54,9 +54,6 @@ namespace Seele
|
|||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RenderCommandBase
|
class RenderCommandBase
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,6 @@ void Seele::RenderCore::init()
|
|||||||
|
|
||||||
void Seele::RenderCore::renderLoop()
|
void Seele::RenderCore::renderLoop()
|
||||||
{
|
{
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
windowManager->beginFrame();
|
|
||||||
windowManager->endFrame();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Seele::RenderCore::shutdown()
|
void Seele::RenderCore::shutdown()
|
||||||
|
|||||||
@@ -2,12 +2,21 @@ target_sources(SeeleEngine
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
VulkanAllocator.h
|
VulkanAllocator.h
|
||||||
VulkanAllocator.cpp
|
VulkanAllocator.cpp
|
||||||
|
VulkanCommandBuffer.h
|
||||||
|
VulkanCommandBuffer.cpp
|
||||||
VulkanBuffer.cpp
|
VulkanBuffer.cpp
|
||||||
|
VulkanFramebuffer.h
|
||||||
|
VulkanFramebuffer.cpp
|
||||||
VulkanGraphics.h
|
VulkanGraphics.h
|
||||||
VulkanGraphics.cpp
|
VulkanGraphics.cpp
|
||||||
VulkanGraphicsResources.h
|
VulkanGraphicsResources.h
|
||||||
|
VulkanGraphicsResources.cpp
|
||||||
VulkanDescriptorSets.cpp
|
VulkanDescriptorSets.cpp
|
||||||
VulkanGraphicsEnums.h
|
VulkanGraphicsEnums.h
|
||||||
VulkanGraphicsEnums.cpp
|
VulkanGraphicsEnums.cpp
|
||||||
VulkanInitializer.h
|
VulkanInitializer.h
|
||||||
VulkanInitializer.cpp)
|
VulkanInitializer.cpp
|
||||||
|
VulkanRenderPass.h
|
||||||
|
VulkanRenderPass.cpp
|
||||||
|
VulkanQueue.h
|
||||||
|
VulkanQueue.cpp)
|
||||||
@@ -14,7 +14,7 @@ SubAllocation::SubAllocation(Allocation* owner, uint32 allocatedOffset, uint32 s
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Allocation::Allocation(PGraphics graphics, Allocator* allocator, uint32 size, uint32 memoryTypeIndex, VkMemoryPropertyFlags properties, bool isDedicated)
|
Allocation::Allocation(WGraphics graphics, Allocator* allocator, uint32 size, uint32 memoryTypeIndex, VkMemoryPropertyFlags properties, bool isDedicated)
|
||||||
: device(graphics->getDevice())
|
: device(graphics->getDevice())
|
||||||
, allocator(allocator)
|
, allocator(allocator)
|
||||||
, bytesAllocated(0)
|
, bytesAllocated(0)
|
||||||
@@ -32,13 +32,13 @@ Allocation::Allocation(PGraphics graphics, Allocator* allocator, uint32 size, ui
|
|||||||
freeRanges.add(freeRange);
|
freeRanges.add(freeRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
PSubAllocation Allocation::getSuballocation(uint32 size, uint32 alignment)
|
PSubAllocation Allocation::getSuballocation(uint32 requestedSize, uint32 alignment)
|
||||||
{
|
{
|
||||||
if (isDedicated)
|
if (isDedicated)
|
||||||
{
|
{
|
||||||
if (activeAllocations.size() == 0)
|
if (activeAllocations.size() == 0)
|
||||||
{
|
{
|
||||||
assert(size == bytesAllocated);
|
assert(requestedSize == bytesAllocated);
|
||||||
activeAllocations.add(freeRanges.back());
|
activeAllocations.add(freeRanges.back());
|
||||||
freeRanges.clear();
|
freeRanges.clear();
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ PSubAllocation Allocation::getSuballocation(uint32 size, uint32 alignment)
|
|||||||
uint32 allocatedOffset = freeAllocation->allocatedOffset;
|
uint32 allocatedOffset = freeAllocation->allocatedOffset;
|
||||||
uint32 alignedOffset = align(allocatedOffset, alignment);
|
uint32 alignedOffset = align(allocatedOffset, alignment);
|
||||||
uint32 alignmentAdjustment = alignedOffset - allocatedOffset;
|
uint32 alignmentAdjustment = alignedOffset - allocatedOffset;
|
||||||
uint32 size = alignmentAdjustment + size;
|
uint32 size = alignmentAdjustment + requestedSize;
|
||||||
if (freeAllocation->size == size)
|
if (freeAllocation->size == size)
|
||||||
{
|
{
|
||||||
freeRanges.remove(i);
|
freeRanges.remove(i);
|
||||||
@@ -66,7 +66,7 @@ PSubAllocation Allocation::getSuballocation(uint32 size, uint32 alignment)
|
|||||||
freeAllocation->allocatedSize -= size;
|
freeAllocation->allocatedSize -= size;
|
||||||
freeAllocation->allocatedOffset += allocatedOffset;
|
freeAllocation->allocatedOffset += allocatedOffset;
|
||||||
freeAllocation->alignedOffset += allocatedOffset;
|
freeAllocation->alignedOffset += allocatedOffset;
|
||||||
PSubAllocation subAlloc = new VulkanSubAllocation(this, allocatedOffset, size, alignedOffset, size);
|
PSubAllocation subAlloc = new SubAllocation(this, allocatedOffset, size, alignedOffset, size);
|
||||||
activeAllocations.add(subAlloc);
|
activeAllocations.add(subAlloc);
|
||||||
return subAlloc;
|
return subAlloc;
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ PSubAllocation Allocation::getSuballocation(uint32 size, uint32 alignment)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Allocator::Allocator(PGraphics graphics)
|
Allocator::Allocator(WGraphics graphics)
|
||||||
: graphics(graphics)
|
: graphics(graphics)
|
||||||
{
|
{
|
||||||
vkGetPhysicalDeviceMemoryProperties(graphics->getPhysicalDevice(), &memProperties);
|
vkGetPhysicalDeviceMemoryProperties(graphics->getPhysicalDevice(), &memProperties);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace Seele
|
|||||||
class Allocation
|
class Allocation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Allocation(PGraphics graphics, Allocator* allocator, uint32 size, uint32 memoryTypeIndex, VkMemoryPropertyFlags properties, bool isDedicated);
|
Allocation(WGraphics graphics, Allocator* allocator, uint32 size, uint32 memoryTypeIndex, VkMemoryPropertyFlags properties, bool isDedicated);
|
||||||
PSubAllocation getSuballocation(uint32 size, uint32 alignment);
|
PSubAllocation getSuballocation(uint32 size, uint32 alignment);
|
||||||
private:
|
private:
|
||||||
Allocator* allocator;
|
Allocator* allocator;
|
||||||
@@ -50,7 +50,7 @@ namespace Seele
|
|||||||
class Allocator
|
class Allocator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Allocator(PGraphics graphics);
|
Allocator(WGraphics graphics);
|
||||||
~Allocator();
|
~Allocator();
|
||||||
PSubAllocation allocate(uint64 size, const VkMemoryRequirements2& requirements, VkMemoryPropertyFlags props);
|
PSubAllocation allocate(uint64 size, const VkMemoryRequirements2& requirements, VkMemoryPropertyFlags props);
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ namespace Seele
|
|||||||
};
|
};
|
||||||
Array<HeapInfo> heaps;
|
Array<HeapInfo> heaps;
|
||||||
VkResult findMemoryType(uint32 typeBits, VkMemoryPropertyFlags properties, uint32* typeIndex);
|
VkResult findMemoryType(uint32 typeBits, VkMemoryPropertyFlags properties, uint32* typeIndex);
|
||||||
PGraphics graphics;
|
WGraphics graphics;
|
||||||
VkPhysicalDeviceMemoryProperties memProperties;
|
VkPhysicalDeviceMemoryProperties memProperties;
|
||||||
};
|
};
|
||||||
DEFINE_REF(Allocator);
|
DEFINE_REF(Allocator);
|
||||||
|
|||||||
@@ -1,67 +1,5 @@
|
|||||||
#include "VulkanGraphicsResources.h"
|
#include "VulkanGraphicsResources.h"
|
||||||
|
#include "VulkanInitializer.h"
|
||||||
|
|
||||||
|
using namespace Seele;
|
||||||
using namespace Seele::Vulkan;
|
using namespace Seele::Vulkan;
|
||||||
|
|
||||||
void Buffer::executeOwnershipBarrier(QueueType newOwner)
|
|
||||||
{
|
|
||||||
VkBufferMemoryBarrier barrier =
|
|
||||||
init::BufferMemoryBarrier();
|
|
||||||
CommandBufferManager* sourceManager = getCommands();
|
|
||||||
CommandBufferManager* dstManager = nullptr;
|
|
||||||
VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
|
||||||
VkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
|
||||||
if (currentOwner == QueueType::TRANSFER)
|
|
||||||
{
|
|
||||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
barrier.srcQueueFamilyIndex = device->getTransferQueue()->getFamilyIndex();
|
|
||||||
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
||||||
}
|
|
||||||
else if (currentOwner == QueueType::COMPUTE)
|
|
||||||
{
|
|
||||||
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
|
||||||
barrier.srcQueueFamilyIndex = device->getComputeQueue()->getFamilyIndex();
|
|
||||||
srcStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
|
||||||
}
|
|
||||||
else if (currentOwner == QueueType::GRAPHICS)
|
|
||||||
{
|
|
||||||
barrier.srcAccessMask = getSourceAccessMask();
|
|
||||||
barrier.srcQueueFamilyIndex = device->getGraphicsQueue()->getFamilyIndex();
|
|
||||||
srcStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
|
||||||
}
|
|
||||||
if (newOwner == QueueType::TRANSFER)
|
|
||||||
{
|
|
||||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
|
||||||
barrier.dstQueueFamilyIndex = device->getTransferQueue()->getFamilyIndex();
|
|
||||||
dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
||||||
dstManager = device->getRHIDevice().getTransferCommands();
|
|
||||||
}
|
|
||||||
else if (newOwner == QueueType::COMPUTE)
|
|
||||||
{
|
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
barrier.dstQueueFamilyIndex = device->getComputeQueue()->getFamilyIndex();
|
|
||||||
dstStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
|
||||||
dstManager = device->getRHIDevice().getComputeCommands();
|
|
||||||
}
|
|
||||||
else if (newOwner == QueueType::GRAPHICS)
|
|
||||||
{
|
|
||||||
barrier.dstAccessMask = getDestAccessMask();
|
|
||||||
barrier.dstQueueFamilyIndex = device->getGraphicsQueue()->getFamilyIndex();
|
|
||||||
dstStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
|
||||||
dstManager = device->getRHIDevice().getGraphicsCommands();
|
|
||||||
}
|
|
||||||
VkCommandBuffer srcCommand = sourceManager->getCmdBuffer()->getHandle();
|
|
||||||
VkCommandBuffer dstCommand = dstManager->getCmdBuffer()->getHandle();
|
|
||||||
const bool bDynamic = (rhiUsage & BUF_Dynamic) != 0;
|
|
||||||
uint32_t numBuffers = bDynamic ? NUM_BUFFERS : 1;
|
|
||||||
VkBufferMemoryBarrier dynamicBarriers[NUM_BUFFERS];
|
|
||||||
for (uint32_t i = 0; i < numBuffers; ++i)
|
|
||||||
{
|
|
||||||
dynamicBarriers[i] = barrier;
|
|
||||||
dynamicBarriers[i].buffer = buffers[i]->getHandle();
|
|
||||||
dynamicBarriers[i].offset = buffers[i]->getOffset();
|
|
||||||
dynamicBarriers[i].size = buffers[i]->getSize();
|
|
||||||
}
|
|
||||||
vkCmdPipelineBarrier(srcCommand, srcStage, dstStage, 0, 0, nullptr, numBuffers, dynamicBarriers, 0, nullptr);
|
|
||||||
vkCmdPipelineBarrier(dstCommand, srcStage, dstStage, 0, 0, nullptr, numBuffers, dynamicBarriers, 0, nullptr);
|
|
||||||
sourceManager->submitCommands();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
#include "VulkanCommandBuffer.h"
|
||||||
|
#include "VulkanInitializer.h"
|
||||||
|
#include "VulkanGraphics.h"
|
||||||
|
#include "VulkanGraphicsEnums.h"
|
||||||
|
#include "VulkanFramebuffer.h"
|
||||||
|
#include "VulkanRenderPass.h"
|
||||||
|
|
||||||
|
using namespace Seele;
|
||||||
|
using namespace Seele::Vulkan;
|
||||||
|
|
||||||
|
CmdBufferBase::CmdBufferBase(WGraphics graphics, VkCommandPool cmdPool)
|
||||||
|
: graphics(graphics)
|
||||||
|
, owner(cmdPool)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CmdBufferBase::~CmdBufferBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CmdBuffer::CmdBuffer(WGraphics graphics, VkCommandPool cmdPool)
|
||||||
|
: CmdBufferBase(graphics, cmdPool)
|
||||||
|
, renderPass(nullptr)
|
||||||
|
, framebuffer(nullptr)
|
||||||
|
, subpassIndex(0)
|
||||||
|
{
|
||||||
|
VkCommandBufferAllocateInfo allocInfo =
|
||||||
|
init::CommandBufferAllocateInfo(cmdPool,
|
||||||
|
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||||
|
1);
|
||||||
|
|
||||||
|
VK_CHECK(vkAllocateCommandBuffers(graphics->getDevice(), &allocInfo, &handle))
|
||||||
|
state = State::ReadyBegin;
|
||||||
|
}
|
||||||
|
|
||||||
|
CmdBuffer::~CmdBuffer()
|
||||||
|
{
|
||||||
|
vkFreeCommandBuffers(graphics->getDevice(), owner, 1, &handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmdBuffer::begin()
|
||||||
|
{
|
||||||
|
VkCommandBufferBeginInfo beginInfo =
|
||||||
|
init::CommandBufferBeginInfo();
|
||||||
|
beginInfo.pInheritanceInfo = nullptr;
|
||||||
|
VK_CHECK(vkBeginCommandBuffer(handle, &beginInfo));
|
||||||
|
state = State::InsideBegin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmdBuffer::end()
|
||||||
|
{
|
||||||
|
VK_CHECK(vkEndCommandBuffer(handle));
|
||||||
|
state = State::Ended;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmdBuffer::beginRenderPass(WRenderPass renderPass, WFramebuffer framebuffer)
|
||||||
|
{
|
||||||
|
VkRenderPassBeginInfo beginInfo =
|
||||||
|
init::RenderPassBeginInfo();
|
||||||
|
beginInfo.clearValueCount = renderPass->getClearValueCount();
|
||||||
|
beginInfo.pClearValues = renderPass->getClearValues();
|
||||||
|
beginInfo.renderArea = renderPass->getRenderArea();
|
||||||
|
beginInfo.renderPass = renderPass->getHandle();
|
||||||
|
beginInfo.framebuffer = framebuffer->getHandle();
|
||||||
|
vkCmdBeginRenderPass(handle, &beginInfo, renderPass->getSubpassContents());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmdBuffer::endRenderPass()
|
||||||
|
{
|
||||||
|
vkCmdEndRenderPass(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondaryCmdBuffer::SecondaryCmdBuffer(WGraphics graphics, VkCommandPool cmdPool)
|
||||||
|
: CmdBufferBase(graphics, cmdPool)
|
||||||
|
{
|
||||||
|
VkCommandBufferAllocateInfo allocInfo =
|
||||||
|
init::CommandBufferAllocateInfo(cmdPool,
|
||||||
|
VK_COMMAND_BUFFER_LEVEL_SECONDARY,
|
||||||
|
1);
|
||||||
|
VK_CHECK(vkAllocateCommandBuffers(graphics->getDevice(), &allocInfo, &handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondaryCmdBuffer::~SecondaryCmdBuffer()
|
||||||
|
{
|
||||||
|
vkFreeCommandBuffers(graphics->getDevice(), owner, 1, &handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecondaryCmdBuffer::begin(WCmdBuffer parent)
|
||||||
|
{
|
||||||
|
VkCommandBufferBeginInfo beginInfo =
|
||||||
|
init::CommandBufferBeginInfo();
|
||||||
|
VkCommandBufferInheritanceInfo inheritanceInfo =
|
||||||
|
init::CommandBufferInheritanceInfo();
|
||||||
|
inheritanceInfo.framebuffer = parent->framebuffer->getHandle();
|
||||||
|
inheritanceInfo.renderPass = parent->renderPass->getHandle();
|
||||||
|
inheritanceInfo.subpass = parent->subpassIndex;
|
||||||
|
beginInfo.pInheritanceInfo = &inheritanceInfo;
|
||||||
|
VK_CHECK(vkBeginCommandBuffer(handle, &beginInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SecondaryCmdBuffer::end()
|
||||||
|
{
|
||||||
|
VK_CHECK(vkEndCommandBuffer(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandBufferManager::CommandBufferManager(WGraphics graphics, WQueue queue)
|
||||||
|
: graphics(graphics)
|
||||||
|
, queue(queue)
|
||||||
|
{
|
||||||
|
VkCommandPoolCreateInfo info =
|
||||||
|
init::CommandPoolCreateInfo();
|
||||||
|
info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
|
info.queueFamilyIndex = queue->getFamilyIndex();
|
||||||
|
|
||||||
|
VK_CHECK(vkCreateCommandPool(graphics->getDevice(), &info, nullptr, &commandPool));
|
||||||
|
|
||||||
|
activeCmdBuffer = new CmdBuffer(graphics, commandPool);
|
||||||
|
activeCmdBuffer->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandBufferManager::~CommandBufferManager()
|
||||||
|
{
|
||||||
|
vkDestroyCommandPool(graphics->getDevice(), commandPool, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
PCmdBuffer CommandBufferManager::getCommands()
|
||||||
|
{
|
||||||
|
return activeCmdBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
PSecondaryCmdBuffer CommandBufferManager::createSecondaryCmdBuffer()
|
||||||
|
{
|
||||||
|
return PSecondaryCmdBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Seele::Vulkan::CommandBufferManager::submitCommands(PSemaphore signalSemaphore)
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -1,38 +1,90 @@
|
|||||||
|
#pragma once
|
||||||
#include "VulkanGraphicsResources.h"
|
#include "VulkanGraphicsResources.h"
|
||||||
|
#include "VulkanQueue.h"
|
||||||
|
|
||||||
namespace Seele
|
namespace Seele
|
||||||
{
|
{
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
class CmdBufferBase : public RenderCommandBase
|
DECLARE_REF(RenderPass);
|
||||||
|
DECLARE_REF(Framebuffer);
|
||||||
|
class CmdBufferBase : public Gfx::RenderCommandBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
private:
|
CmdBufferBase(WGraphics graphics, VkCommandPool cmdPool);
|
||||||
|
virtual ~CmdBufferBase();
|
||||||
|
inline VkCommandBuffer getHandle()
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
void reset();
|
||||||
|
VkViewport currentViewport;
|
||||||
|
VkRect2D currentScissor;
|
||||||
|
protected:
|
||||||
|
WGraphics graphics;
|
||||||
VkCommandBuffer handle;
|
VkCommandBuffer handle;
|
||||||
|
VkCommandPool owner;
|
||||||
};
|
};
|
||||||
DEFINE_REF(CmdBuffer);
|
DEFINE_REF(CmdBufferBase);
|
||||||
|
|
||||||
|
DECLARE_REF(SecondaryCmdBuffer);
|
||||||
class CmdBuffer : public CmdBufferBase
|
class CmdBuffer : public CmdBufferBase
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
CmdBuffer(WGraphics graphics, VkCommandPool cmdPool);
|
||||||
|
virtual ~CmdBuffer();
|
||||||
|
void begin();
|
||||||
|
void end();
|
||||||
|
void beginRenderPass(WRenderPass renderPass, WFramebuffer framebuffer);
|
||||||
|
void endRenderPass();
|
||||||
|
void executeCommands(Array<WSecondaryCmdBuffer> secondaryCommands);
|
||||||
|
void addWaitSemaphore(VkPipelineStageFlags stages, PSemaphore waitSemaphore);
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
ReadyBegin,
|
||||||
|
InsideBegin,
|
||||||
|
RenderPassActive,
|
||||||
|
Ended,
|
||||||
|
Submitted,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
WRenderPass renderPass;
|
||||||
|
WFramebuffer framebuffer;
|
||||||
|
uint32 subpassIndex;
|
||||||
|
State state;
|
||||||
|
friend class SecondaryCmdBuffer;
|
||||||
};
|
};
|
||||||
DEFINE_REF(CmdBuffer);
|
DEFINE_REF(CmdBuffer);
|
||||||
|
|
||||||
|
class SecondaryCmdBuffer : public CmdBufferBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SecondaryCmdBuffer(WGraphics graphics, VkCommandPool cmdPool);
|
||||||
|
virtual ~SecondaryCmdBuffer();
|
||||||
|
void begin(WCmdBuffer parent);
|
||||||
|
void end();
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
DEFINE_REF(SecondaryCmdBuffer);
|
||||||
|
|
||||||
class CommandBufferManager
|
class CommandBufferManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CommandBufferManager(Vulkan::PGraphics graphics, PVulkanQueue queue);
|
CommandBufferManager(WGraphics graphics, WQueue queue);
|
||||||
virtual ~CommandBufferManager();
|
virtual ~CommandBufferManager();
|
||||||
PCmdBuffer getCommands();
|
PCmdBuffer getCommands();
|
||||||
PSecondaryCommandBuffer createSecondaryCmdBuffer();
|
PSecondaryCmdBuffer createSecondaryCmdBuffer();
|
||||||
void submitCommands(PSemaphore signalSemaphore = nullptr);
|
void submitCommands(PSemaphore signalSemaphore = nullptr);
|
||||||
void waitForBuffer(PCommandbuffer cmdBuffer, float timeToWait = 1.0f);
|
void waitForCommands(PCmdBuffer cmdBuffer, float timeToWait = 1.0f);
|
||||||
private:
|
private:
|
||||||
|
WGraphics graphics;
|
||||||
VkCommandPool commandPool;
|
VkCommandPool commandPool;
|
||||||
QueueType queueType;
|
WQueue queue;
|
||||||
uint32 queueFamilyIndex;
|
uint32 queueFamilyIndex;
|
||||||
Array<Vulkan::PCmdBuffer> allocatedBuffers;
|
PCmdBuffer activeCmdBuffer;
|
||||||
|
Array<PCmdBuffer> allocatedBuffers;
|
||||||
};
|
};
|
||||||
DEFINE_REF(VulkanCommandBufferManager);
|
DEFINE_REF(CommandBufferManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ void DescriptorSet::writeChanges()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DescriptorAllocator::DescriptorAllocator(PGraphics graphics, DescriptorLayout& layout)
|
DescriptorAllocator::DescriptorAllocator(WGraphics graphics, DescriptorLayout& layout)
|
||||||
: layout(layout)
|
: layout(layout)
|
||||||
, graphics(graphics)
|
, graphics(graphics)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "VulkanGraphicsResources.h"
|
||||||
|
|
||||||
|
namespace Seele
|
||||||
|
{
|
||||||
|
namespace Vulkan
|
||||||
|
{
|
||||||
|
class Framebuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Framebuffer(WGraphics graphics);
|
||||||
|
virtual ~Framebuffer();
|
||||||
|
inline VkFramebuffer getHandle() const
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
WGraphics graphics;
|
||||||
|
VkFramebuffer handle;
|
||||||
|
};
|
||||||
|
DEFINE_REF(Framebuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
#include "VulkanGraphics.h"
|
#include "VulkanGraphics.h"
|
||||||
#include "VulkanAllocator.h"
|
#include "VulkanAllocator.h"
|
||||||
|
#include "VulkanQueue.h"
|
||||||
#include "Containers/Array.h"
|
#include "Containers/Array.h"
|
||||||
#include "VulkanInitializer.h"
|
#include "VulkanInitializer.h"
|
||||||
|
#include "VulkanCommandBuffer.h"
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
using namespace Seele::Vulkan;
|
using namespace Seele::Vulkan;
|
||||||
|
|
||||||
Graphics::Graphics()
|
Graphics::Graphics()
|
||||||
: callback(VK_NULL_HANDLE)
|
: callback(VK_NULL_HANDLE), handle(VK_NULL_HANDLE), instance(VK_NULL_HANDLE), physicalDevice(VK_NULL_HANDLE)
|
||||||
, handle(VK_NULL_HANDLE)
|
|
||||||
, instance(VK_NULL_HANDLE)
|
|
||||||
, physicalDevice(VK_NULL_HANDLE)
|
|
||||||
{
|
{
|
||||||
glfwInit();
|
glfwInit();
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
@@ -18,6 +17,9 @@ Graphics::Graphics()
|
|||||||
|
|
||||||
Graphics::~Graphics()
|
Graphics::~Graphics()
|
||||||
{
|
{
|
||||||
|
vkDestroyDevice(handle, nullptr);
|
||||||
|
DestroyDebugReportCallbackEXT(instance, nullptr, callback);
|
||||||
|
vkDestroyInstance(instance, nullptr);
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +28,12 @@ void Graphics::init(GraphicsInitializer initInfo)
|
|||||||
initInstance(initInfo);
|
initInstance(initInfo);
|
||||||
setupDebugCallback();
|
setupDebugCallback();
|
||||||
pickPhysicalDevice();
|
pickPhysicalDevice();
|
||||||
allocator = new VulkanAllocator(this);
|
createDevice(initInfo);
|
||||||
|
allocator = new Allocator(this);
|
||||||
|
graphicsCommands = new CommandBufferManager(this, graphicsQueue);
|
||||||
|
computeCommands = new CommandBufferManager(this, computeQueue);
|
||||||
|
transferCommands = new CommandBufferManager(this, transferQueue);
|
||||||
|
dedicatedTransferCommands = new CommandBufferManager(this, dedicatedTransferQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::beginFrame(void *windowHandle)
|
void Graphics::beginFrame(void *windowHandle)
|
||||||
@@ -63,7 +70,8 @@ Array<const char*> Graphics::getRequiredExtensions()
|
|||||||
unsigned int glfwExtensionCount = 0;
|
unsigned int glfwExtensionCount = 0;
|
||||||
const char **glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
const char **glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < glfwExtensionCount; i++) {
|
for (unsigned int i = 0; i < glfwExtensionCount; i++)
|
||||||
|
{
|
||||||
extensions.add(glfwExtensions[i]);
|
extensions.add(glfwExtensions[i]);
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_VALIDATION
|
#ifdef ENABLE_VALIDATION
|
||||||
@@ -119,8 +127,8 @@ void Graphics::pickPhysicalDevice()
|
|||||||
for (auto physicalDevice : physicalDevices)
|
for (auto physicalDevice : physicalDevices)
|
||||||
{
|
{
|
||||||
uint32 currentRating = 0;
|
uint32 currentRating = 0;
|
||||||
VkPhysicalDeviceProperties props;
|
|
||||||
vkGetPhysicalDeviceProperties(physicalDevice, &props);
|
vkGetPhysicalDeviceProperties(physicalDevice, &props);
|
||||||
|
vkGetPhysicalDeviceFeatures(physicalDevice, &features);
|
||||||
if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||||
{
|
{
|
||||||
currentRating += 100;
|
currentRating += 100;
|
||||||
@@ -138,7 +146,104 @@ void Graphics::pickPhysicalDevice()
|
|||||||
this->physicalDevice = bestDevice;
|
this->physicalDevice = bestDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::createDevice()
|
void Graphics::createDevice(GraphicsInitializer initializer)
|
||||||
{
|
{
|
||||||
|
uint32_t numQueueFamilies = 0;
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueueFamilies, nullptr);
|
||||||
|
Array<VkQueueFamilyProperties> queueProperties(numQueueFamilies);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &numQueueFamilies, queueProperties.data());
|
||||||
|
|
||||||
|
Array<VkDeviceQueueCreateInfo> queueInfos;
|
||||||
|
int32_t graphicsQueueFamilyIndex = -1;
|
||||||
|
int32_t transferQueueFamilyIndex = -1;
|
||||||
|
int32_t dedicatedTransferQueueFamilyIndex = -1;
|
||||||
|
int32_t computeQueueFamilyIndex = -1;
|
||||||
|
int32_t asyncComputeFamilyIndex = -1;
|
||||||
|
for (int32_t familyIndex = 0; familyIndex < queueProperties.size(); ++familyIndex)
|
||||||
|
{
|
||||||
|
const VkQueueFamilyProperties currProps = queueProperties[familyIndex];
|
||||||
|
if ((currProps.queueFlags & VK_QUEUE_GRAPHICS_BIT) == VK_QUEUE_GRAPHICS_BIT)
|
||||||
|
{
|
||||||
|
if (graphicsQueueFamilyIndex == -1)
|
||||||
|
{
|
||||||
|
graphicsQueueFamilyIndex = familyIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((currProps.queueFlags & VK_QUEUE_COMPUTE_BIT) == VK_QUEUE_COMPUTE_BIT)
|
||||||
|
{
|
||||||
|
if (computeQueueFamilyIndex == -1)
|
||||||
|
{
|
||||||
|
computeQueueFamilyIndex = familyIndex;
|
||||||
|
}
|
||||||
|
if (Gfx::useAsyncCompute)
|
||||||
|
{
|
||||||
|
if (asyncComputeFamilyIndex == -1)
|
||||||
|
{
|
||||||
|
if (familyIndex == graphicsQueueFamilyIndex)
|
||||||
|
{
|
||||||
|
if (currProps.queueCount > 1)
|
||||||
|
{
|
||||||
|
asyncComputeFamilyIndex = familyIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
asyncComputeFamilyIndex = familyIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((currProps.queueFlags & VK_QUEUE_TRANSFER_BIT) == VK_QUEUE_TRANSFER_BIT)
|
||||||
|
{
|
||||||
|
if (transferQueueFamilyIndex == -1)
|
||||||
|
{
|
||||||
|
transferQueueFamilyIndex = familyIndex;
|
||||||
|
}
|
||||||
|
if ((currProps.queueFlags ^ VK_QUEUE_TRANSFER_BIT) == 0)
|
||||||
|
{
|
||||||
|
dedicatedTransferQueueFamilyIndex = familyIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VkDeviceQueueCreateInfo info =
|
||||||
|
init::DeviceQueueCreateInfo(familyIndex, 1);
|
||||||
|
queueInfos.add(info);
|
||||||
|
}
|
||||||
|
VkDeviceCreateInfo deviceInfo = init::DeviceCreateInfo(
|
||||||
|
queueInfos.data(),
|
||||||
|
(uint32)queueInfos.size(),
|
||||||
|
&features);
|
||||||
|
deviceInfo.enabledExtensionCount = (uint32)initializer.deviceExtensions.size();
|
||||||
|
deviceInfo.ppEnabledExtensionNames = initializer.deviceExtensions.data();
|
||||||
|
deviceInfo.enabledLayerCount = (uint32_t)initializer.layers.size();
|
||||||
|
deviceInfo.ppEnabledLayerNames = initializer.layers.data();
|
||||||
|
|
||||||
|
VK_CHECK(vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &handle));
|
||||||
|
|
||||||
|
graphicsQueue = new Queue(this, QueueType::GRAPHICS, graphicsQueueFamilyIndex, 0);
|
||||||
|
if (Gfx::useAsyncCompute && asyncComputeFamilyIndex != -1)
|
||||||
|
{
|
||||||
|
if (asyncComputeFamilyIndex == graphicsQueueFamilyIndex)
|
||||||
|
{
|
||||||
|
// Same family as graphics, but different queue
|
||||||
|
computeQueue = new Queue(this, QueueType::COMPUTE, asyncComputeFamilyIndex, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Different family
|
||||||
|
computeQueue = new Queue(this, QueueType::COMPUTE, asyncComputeFamilyIndex, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
computeQueue = new Queue(this, QueueType::COMPUTE, computeQueueFamilyIndex, 0);
|
||||||
|
}
|
||||||
|
transferQueue = new Queue(this, QueueType::TRANSFER, transferQueueFamilyIndex, 0);
|
||||||
|
if (dedicatedTransferQueueFamilyIndex != -1)
|
||||||
|
{
|
||||||
|
dedicatedTransferQueue = new Queue(this, QueueType::DEDICATED_TRANSFER, dedicatedTransferQueueFamilyIndex, 0);
|
||||||
|
}
|
||||||
|
queueMapping.graphicsFamily = graphicsQueue->getFamilyIndex();
|
||||||
|
queueMapping.computeFamily = computeQueue->getFamilyIndex();
|
||||||
|
queueMapping.transferFamily = transferQueue->getFamilyIndex();
|
||||||
|
queueMapping.dedicatedTransferFamily = dedicatedTransferQueue->getFamilyIndex();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
#include "Graphics/Graphics.h"
|
#include "Graphics/Graphics.h"
|
||||||
#include "VulkanGraphicsResources.h"
|
#include "VulkanGraphicsResources.h"
|
||||||
|
|
||||||
@@ -6,6 +7,8 @@ namespace Seele
|
|||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
DECLARE_REF(Allocator);
|
DECLARE_REF(Allocator);
|
||||||
|
DECLARE_REF(CommandBufferManager);
|
||||||
|
DECLARE_REF(Queue);
|
||||||
class Graphics : public Gfx::Graphics
|
class Graphics : public Gfx::Graphics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -14,6 +17,11 @@ namespace Seele
|
|||||||
VkDevice getDevice() const;
|
VkDevice getDevice() const;
|
||||||
VkPhysicalDevice getPhysicalDevice() const;
|
VkPhysicalDevice getPhysicalDevice() const;
|
||||||
|
|
||||||
|
PCommandBufferManager getGraphicsCommands();
|
||||||
|
PCommandBufferManager getComputeCommands();
|
||||||
|
PCommandBufferManager getTransferCommands();
|
||||||
|
PCommandBufferManager getDedicatedTransferCommands();
|
||||||
|
|
||||||
// Inherited via Graphics
|
// Inherited via Graphics
|
||||||
virtual void init(GraphicsInitializer initializer) override;
|
virtual void init(GraphicsInitializer initializer) override;
|
||||||
virtual void beginFrame(void* windowHandle) override;
|
virtual void beginFrame(void* windowHandle) override;
|
||||||
@@ -24,14 +32,27 @@ namespace Seele
|
|||||||
void initInstance(GraphicsInitializer initInfo);
|
void initInstance(GraphicsInitializer initInfo);
|
||||||
void setupDebugCallback();
|
void setupDebugCallback();
|
||||||
void pickPhysicalDevice();
|
void pickPhysicalDevice();
|
||||||
void createDevice();
|
void createDevice(GraphicsInitializer initInfo);
|
||||||
|
|
||||||
VkDevice handle;
|
VkDevice handle;
|
||||||
VkPhysicalDevice physicalDevice;
|
VkPhysicalDevice physicalDevice;
|
||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
|
|
||||||
|
WQueue graphicsQueue;
|
||||||
|
WQueue computeQueue;
|
||||||
|
WQueue transferQueue;
|
||||||
|
WQueue dedicatedTransferQueue;
|
||||||
|
QueueFamilyMapping queueMapping;
|
||||||
|
PCommandBufferManager graphicsCommands;
|
||||||
|
PCommandBufferManager computeCommands;
|
||||||
|
PCommandBufferManager transferCommands;
|
||||||
|
PCommandBufferManager dedicatedTransferCommands;
|
||||||
|
VkPhysicalDeviceProperties props;
|
||||||
|
VkPhysicalDeviceFeatures features;
|
||||||
VkDebugReportCallbackEXT callback;
|
VkDebugReportCallbackEXT callback;
|
||||||
Array<PViewport> viewports;
|
Array<PViewport> viewports;
|
||||||
PAllocator allocator;
|
PAllocator allocator;
|
||||||
|
|
||||||
friend class Window;
|
friend class Window;
|
||||||
};
|
};
|
||||||
DEFINE_REF(Graphics);
|
DEFINE_REF(Graphics);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
using namespace Seele::Vulkan;
|
using namespace Seele::Vulkan;
|
||||||
using namespace Seele::Gfx;
|
using namespace Seele::Gfx;
|
||||||
|
|
||||||
VkDescriptorType cast(const Seele::Gfx::SeDescriptorType& descriptorType)
|
VkDescriptorType Seele::Vulkan::cast(const Seele::Gfx::SeDescriptorType& descriptorType)
|
||||||
{
|
{
|
||||||
switch (descriptorType)
|
switch (descriptorType)
|
||||||
{
|
{
|
||||||
@@ -41,7 +41,7 @@ VkDescriptorType cast(const Seele::Gfx::SeDescriptorType& descriptorType)
|
|||||||
return VK_DESCRIPTOR_TYPE_MAX_ENUM;
|
return VK_DESCRIPTOR_TYPE_MAX_ENUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
Seele::Gfx::SeDescriptorType cast(const VkDescriptorType& descriptorType)
|
Seele::Gfx::SeDescriptorType Seele::Vulkan::cast(const VkDescriptorType& descriptorType)
|
||||||
{
|
{
|
||||||
switch (descriptorType)
|
switch (descriptorType)
|
||||||
{
|
{
|
||||||
@@ -80,7 +80,7 @@ Seele::Gfx::SeDescriptorType cast(const VkDescriptorType& descriptorType)
|
|||||||
return SE_DESCRIPTOR_TYPE_MAX_ENUM;
|
return SE_DESCRIPTOR_TYPE_MAX_ENUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkShaderStageFlagBits cast(const Seele::Gfx::SeShaderStageFlagBits& stage)
|
VkShaderStageFlagBits Seele::Vulkan::cast(const Seele::Gfx::SeShaderStageFlagBits& stage)
|
||||||
{
|
{
|
||||||
switch (stage)
|
switch (stage)
|
||||||
{
|
{
|
||||||
@@ -125,7 +125,7 @@ VkShaderStageFlagBits cast(const Seele::Gfx::SeShaderStageFlagBits& stage)
|
|||||||
return VK_SHADER_STAGE_ALL;
|
return VK_SHADER_STAGE_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Seele::Gfx::SeShaderStageFlagBits cast(const VkShaderStageFlagBits& stage)
|
Seele::Gfx::SeShaderStageFlagBits Seele::Vulkan::cast(const VkShaderStageFlagBits& stage)
|
||||||
{
|
{
|
||||||
switch (stage)
|
switch (stage)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include "VulkanGraphicsResources.h"
|
||||||
|
#include "VulkanInitializer.h"
|
||||||
|
#include "VulkanGraphics.h"
|
||||||
|
#include "VulkanGraphicsEnums.h"
|
||||||
|
|
||||||
|
using namespace Seele;
|
||||||
|
using namespace Seele::Vulkan;
|
||||||
|
|
||||||
|
Semaphore::Semaphore(WGraphics graphics)
|
||||||
|
: graphics(graphics)
|
||||||
|
{
|
||||||
|
VkSemaphoreCreateInfo info =
|
||||||
|
init::SemaphoreCreateInfo();
|
||||||
|
VK_CHECK(vkCreateSemaphore(graphics->getDevice(), &info, nullptr, &handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
Semaphore::~Semaphore()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,23 +6,38 @@ namespace Seele
|
|||||||
{
|
{
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
|
|
||||||
DECLARE_REF(DescriptorAllocator);
|
DECLARE_REF(DescriptorAllocator);
|
||||||
|
DECLARE_REF(CommandBufferManager);
|
||||||
DECLARE_REF(Graphics);
|
DECLARE_REF(Graphics);
|
||||||
|
class Semaphore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Semaphore(WGraphics graphics);
|
||||||
|
virtual ~Semaphore();
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkSemaphore handle;
|
||||||
|
WGraphics graphics;
|
||||||
|
};
|
||||||
|
DEFINE_REF(Semaphore);
|
||||||
|
|
||||||
class DescriptorLayout : public Gfx::DescriptorLayout
|
class DescriptorLayout : public Gfx::DescriptorLayout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DescriptorLayout(PGraphics graphics)
|
DescriptorLayout(WGraphics graphics)
|
||||||
: graphics(graphics)
|
: graphics(graphics), layoutHandle(VK_NULL_HANDLE)
|
||||||
, layoutHandle(VK_NULL_HANDLE)
|
{
|
||||||
{}
|
}
|
||||||
virtual ~DescriptorLayout();
|
virtual ~DescriptorLayout();
|
||||||
virtual void create();
|
virtual void create();
|
||||||
inline VkDescriptorSetLayout getHandle() const
|
inline VkDescriptorSetLayout getHandle() const
|
||||||
{
|
{
|
||||||
return layoutHandle;
|
return layoutHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PGraphics graphics;
|
WGraphics graphics;
|
||||||
Array<VkDescriptorSetLayoutBinding> bindings;
|
Array<VkDescriptorSetLayoutBinding> bindings;
|
||||||
VkDescriptorSetLayout layoutHandle;
|
VkDescriptorSetLayout layoutHandle;
|
||||||
friend class PipelineStateCacheManager;
|
friend class PipelineStateCacheManager;
|
||||||
@@ -31,11 +46,10 @@ namespace Seele
|
|||||||
class PipelineLayout : public Gfx::PipelineLayout
|
class PipelineLayout : public Gfx::PipelineLayout
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PipelineLayout(PGraphics graphics)
|
PipelineLayout(WGraphics graphics)
|
||||||
: graphics(graphics)
|
: graphics(graphics), layoutHash(0), layoutHandle(VK_NULL_HANDLE)
|
||||||
, layoutHash(0)
|
{
|
||||||
, layoutHandle(VK_NULL_HANDLE)
|
}
|
||||||
{}
|
|
||||||
virtual ~PipelineLayout();
|
virtual ~PipelineLayout();
|
||||||
virtual void create();
|
virtual void create();
|
||||||
inline VkPipelineLayout getHandle() const
|
inline VkPipelineLayout getHandle() const
|
||||||
@@ -46,11 +60,12 @@ namespace Seele
|
|||||||
{
|
{
|
||||||
return layoutHash;
|
return layoutHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Array<VkDescriptorSetLayout> vulkanDescriptorLayouts;
|
Array<VkDescriptorSetLayout> vulkanDescriptorLayouts;
|
||||||
uint32 layoutHash;
|
uint32 layoutHash;
|
||||||
VkPipelineLayout layoutHandle;
|
VkPipelineLayout layoutHandle;
|
||||||
PGraphics graphics;
|
WGraphics graphics;
|
||||||
friend class PipelineStateCacheManager;
|
friend class PipelineStateCacheManager;
|
||||||
};
|
};
|
||||||
DEFINE_REF(PipelineLayout);
|
DEFINE_REF(PipelineLayout);
|
||||||
@@ -58,11 +73,10 @@ namespace Seele
|
|||||||
class DescriptorSet : public Gfx::DescriptorSet
|
class DescriptorSet : public Gfx::DescriptorSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DescriptorSet(PGraphics graphics, PDescriptorAllocator owner)
|
DescriptorSet(WGraphics graphics, PDescriptorAllocator owner)
|
||||||
: graphics(graphics)
|
: graphics(graphics), owner(owner), setHandle(VK_NULL_HANDLE)
|
||||||
, owner(owner)
|
{
|
||||||
, setHandle(VK_NULL_HANDLE)
|
}
|
||||||
{}
|
|
||||||
virtual ~DescriptorSet();
|
virtual ~DescriptorSet();
|
||||||
virtual void updateBuffer(uint32_t binding, Gfx::PUniformBuffer uniformBuffer);
|
virtual void updateBuffer(uint32_t binding, Gfx::PUniformBuffer uniformBuffer);
|
||||||
virtual void updateBuffer(uint32_t binding, Gfx::PStructuredBuffer uniformBuffer);
|
virtual void updateBuffer(uint32_t binding, Gfx::PStructuredBuffer uniformBuffer);
|
||||||
@@ -73,6 +87,7 @@ namespace Seele
|
|||||||
{
|
{
|
||||||
return setHandle;
|
return setHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void writeChanges();
|
virtual void writeChanges();
|
||||||
Array<VkDescriptorImageInfo> imageInfos;
|
Array<VkDescriptorImageInfo> imageInfos;
|
||||||
@@ -80,7 +95,7 @@ namespace Seele
|
|||||||
Array<VkWriteDescriptorSet> writeDescriptors;
|
Array<VkWriteDescriptorSet> writeDescriptors;
|
||||||
VkDescriptorSet setHandle;
|
VkDescriptorSet setHandle;
|
||||||
PDescriptorAllocator owner;
|
PDescriptorAllocator owner;
|
||||||
PGraphics graphics;
|
WGraphics graphics;
|
||||||
friend class DescriptorAllocator;
|
friend class DescriptorAllocator;
|
||||||
};
|
};
|
||||||
DEFINE_REF(DescriptorSet);
|
DEFINE_REF(DescriptorSet);
|
||||||
@@ -88,7 +103,7 @@ namespace Seele
|
|||||||
class DescriptorAllocator : public Gfx::DescriptorAllocator
|
class DescriptorAllocator : public Gfx::DescriptorAllocator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DescriptorAllocator(PGraphics graphics, DescriptorLayout& layout);
|
DescriptorAllocator(WGraphics graphics, DescriptorLayout &layout);
|
||||||
~DescriptorAllocator();
|
~DescriptorAllocator();
|
||||||
virtual void allocateDescriptorSet(Gfx::PDescriptorSet &descriptorSet);
|
virtual void allocateDescriptorSet(Gfx::PDescriptorSet &descriptorSet);
|
||||||
|
|
||||||
@@ -96,8 +111,9 @@ namespace Seele
|
|||||||
{
|
{
|
||||||
return poolHandle;
|
return poolHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PGraphics graphics;
|
WGraphics graphics;
|
||||||
int maxSets = 512;
|
int maxSets = 512;
|
||||||
VkDescriptorPool poolHandle;
|
VkDescriptorPool poolHandle;
|
||||||
DescriptorLayout &layout;
|
DescriptorLayout &layout;
|
||||||
@@ -107,20 +123,52 @@ namespace Seele
|
|||||||
{
|
{
|
||||||
GRAPHICS = 1,
|
GRAPHICS = 1,
|
||||||
COMPUTE = 2,
|
COMPUTE = 2,
|
||||||
TRANSFER = 3
|
TRANSFER = 3,
|
||||||
|
DEDICATED_TRANSFER = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QueueFamilyMapping
|
||||||
|
{
|
||||||
|
uint32 graphicsFamily;
|
||||||
|
uint32 computeFamily;
|
||||||
|
uint32 transferFamily;
|
||||||
|
uint32 dedicatedTransferFamily;
|
||||||
|
uint32 getQueueTypeFamilyIndex(QueueType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case QueueType::GRAPHICS:
|
||||||
|
return graphicsFamily;
|
||||||
|
case QueueType::COMPUTE:
|
||||||
|
return computeFamily;
|
||||||
|
case QueueType::TRANSFER:
|
||||||
|
return transferFamily;
|
||||||
|
case QueueType::DEDICATED_TRANSFER:
|
||||||
|
return dedicatedTransferFamily;
|
||||||
|
default:
|
||||||
|
return VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool needsTransfer(QueueType src, QueueType dst)
|
||||||
|
{
|
||||||
|
uint32 srcIndex = getQueueTypeFamilyIndex(src);
|
||||||
|
uint32 dstIndex = getQueueTypeFamilyIndex(dst);
|
||||||
|
return srcIndex != dstIndex;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
class QueueOwnedResource
|
class QueueOwnedResource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QueueOwnedResource(PGraphics graphics, QueueType startQueueType);
|
QueueOwnedResource(WGraphics graphics, QueueType startQueueType);
|
||||||
~QueueOwnedResource();
|
~QueueOwnedResource();
|
||||||
CommandBufferManager* getCommands();
|
PCommandBufferManager getCommands();
|
||||||
//Preliminary checks to see if the barrier should be executed at all
|
//Preliminary checks to see if the barrier should be executed at all
|
||||||
void transferOwnership(QueueType newOwner);
|
void transferOwnership(QueueType newOwner);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void executeOwnershipBarrier(QueueType newOwner) = 0;
|
virtual void executeOwnershipBarrier(QueueType newOwner) = 0;
|
||||||
QueueType currentOwner;
|
QueueType currentOwner;
|
||||||
PGraphics graphics;
|
WGraphics graphics;
|
||||||
CommandBufferManager *cachedCmdBufferManager;
|
CommandBufferManager *cachedCmdBufferManager;
|
||||||
};
|
};
|
||||||
DEFINE_REF(QueueOwnedResource);
|
DEFINE_REF(QueueOwnedResource);
|
||||||
@@ -128,8 +176,9 @@ namespace Seele
|
|||||||
class Buffer : public QueueOwnedResource
|
class Buffer : public QueueOwnedResource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Buffer(PGraphics graphics, uint32 size, VkBufferUsageFlags usage);
|
Buffer(WGraphics graphics, uint32 size, VkBufferUsageFlags usage);
|
||||||
virtual ~Buffer();
|
virtual ~Buffer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual VkAccessFlags getSourceAccessMask() = 0;
|
virtual VkAccessFlags getSourceAccessMask() = 0;
|
||||||
virtual VkAccessFlags getDestAccessMask() = 0;
|
virtual VkAccessFlags getDestAccessMask() = 0;
|
||||||
@@ -138,26 +187,28 @@ namespace Seele
|
|||||||
};
|
};
|
||||||
DEFINE_REF(Buffer);
|
DEFINE_REF(Buffer);
|
||||||
|
|
||||||
class UniformBuffer : public Gfx::UniformBuffer
|
class UniformBuffer : public Buffer, public Gfx::UniformBuffer
|
||||||
{
|
{
|
||||||
|
|
||||||
};
|
};
|
||||||
DEFINE_REF(UniformBuffer);
|
DEFINE_REF(UniformBuffer);
|
||||||
|
|
||||||
class StructuredBuffer : public Gfx::StructuredBuffer
|
class StructuredBuffer : public Buffer, public Gfx::StructuredBuffer
|
||||||
{
|
{
|
||||||
|
|
||||||
};
|
};
|
||||||
DEFINE_REF(StructuredBuffer);
|
DEFINE_REF(StructuredBuffer);
|
||||||
|
|
||||||
class TextureBase
|
class TextureBase
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
TextureBase();
|
||||||
|
virtual ~TextureBase();
|
||||||
private:
|
private:
|
||||||
uint32 sizeX;
|
uint32 sizeX;
|
||||||
uint32 sizeY;
|
uint32 sizeY;
|
||||||
uint32 sizeZ;
|
uint32 sizeZ;
|
||||||
uint32 arrayCount;
|
uint32 arrayCount;
|
||||||
uint32 layerCount;
|
uint32 layerCount;
|
||||||
|
VkImage image;
|
||||||
};
|
};
|
||||||
DEFINE_REF(TextureBase);
|
DEFINE_REF(TextureBase);
|
||||||
|
|
||||||
@@ -188,5 +239,5 @@ namespace Seele
|
|||||||
void *windowHandle;
|
void *windowHandle;
|
||||||
};
|
};
|
||||||
DECLARE_REF(Viewport);
|
DECLARE_REF(Viewport);
|
||||||
}
|
} // namespace Vulkan
|
||||||
}
|
} // namespace Seele
|
||||||
@@ -743,11 +743,11 @@ VkPipelineShaderStageCreateInfo init::PipelineShaderStageCreateInfo(VkShaderStag
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkBool32 debugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char* layerPrefix, const char* msg, void* userDataManager) {
|
VkBool32 Seele::Vulkan::debugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char* layerPrefix, const char* msg, void* userDataManager) {
|
||||||
std::cerr << layerPrefix << ": " << msg << std::endl;
|
std::cerr << layerPrefix << ": " << msg << std::endl;
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
}
|
}
|
||||||
VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback) {
|
VkResult Seele::Vulkan::CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback) {
|
||||||
auto func = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
|
auto func = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
|
||||||
if (func != nullptr) {
|
if (func != nullptr) {
|
||||||
return func(instance, pCreateInfo, pAllocator, pCallback);
|
return func(instance, pCreateInfo, pAllocator, pCallback);
|
||||||
@@ -757,7 +757,7 @@ VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyDebugReportCallbackEXT(VkInstance instance, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT pCallback)
|
void Seele::Vulkan::DestroyDebugReportCallbackEXT(VkInstance instance, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT pCallback)
|
||||||
{
|
{
|
||||||
auto func = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
|
auto func = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
|
||||||
if (func != nullptr) {
|
if (func != nullptr) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
#include "Containers/Array.h"
|
#include "Containers/Array.h"
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#include "VulkanQueue.h"
|
||||||
|
#include "VulkanInitializer.h"
|
||||||
|
#include "VulkanGraphics.h"
|
||||||
|
|
||||||
|
using namespace Seele;
|
||||||
|
using namespace Seele::Vulkan;
|
||||||
|
|
||||||
|
Queue::Queue(WGraphics graphics, QueueType queueType, uint32 familyIndex, uint32 queueIndex)
|
||||||
|
: familyIndex(familyIndex)
|
||||||
|
, graphics(graphics)
|
||||||
|
, queueType(queueType)
|
||||||
|
{
|
||||||
|
vkGetDeviceQueue(graphics->getDevice(), familyIndex, queueIndex, &queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
Queue::~Queue()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "VulkanGraphicsResources.h"
|
||||||
|
|
||||||
|
namespace Seele
|
||||||
|
{
|
||||||
|
namespace Vulkan
|
||||||
|
{
|
||||||
|
DECLARE_REF(CmdBuffer);
|
||||||
|
DECLARE_REF(Graphics);
|
||||||
|
class Queue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Queue(WGraphics graphics, QueueType queueType, uint32 familyIndex, uint32 queueIndex);
|
||||||
|
virtual ~Queue();
|
||||||
|
void submitCommandBuffer(PCmdBuffer cmdBuffer, uint32 numSignalSemaphores = 0, VkSemaphore* signalSemaphore = nullptr);
|
||||||
|
inline void submitCommandBuffer(PCmdBuffer cmdBuffer, VkSemaphore signalSemaphore)
|
||||||
|
{
|
||||||
|
submitCommandBuffer(cmdBuffer, 1, &signalSemaphore);
|
||||||
|
}
|
||||||
|
uint32 getFamilyIndex() const
|
||||||
|
{
|
||||||
|
return familyIndex;
|
||||||
|
}
|
||||||
|
inline VkQueue getHandle() const
|
||||||
|
{
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
WGraphics graphics;
|
||||||
|
VkQueue queue;
|
||||||
|
uint32 familyIndex;
|
||||||
|
QueueType queueType;
|
||||||
|
};
|
||||||
|
DEFINE_REF(Queue)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "VulkanGraphicsResources.h"
|
||||||
|
|
||||||
|
namespace Seele
|
||||||
|
{
|
||||||
|
namespace Vulkan
|
||||||
|
{
|
||||||
|
class RenderPass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RenderPass();
|
||||||
|
virtual ~RenderPass();
|
||||||
|
inline VkRenderPass getHandle() const
|
||||||
|
{
|
||||||
|
return renderPass;
|
||||||
|
}
|
||||||
|
inline uint32 getClearValueCount() const
|
||||||
|
{
|
||||||
|
return clearValues.size();
|
||||||
|
}
|
||||||
|
inline VkClearValue* getClearValues() const
|
||||||
|
{
|
||||||
|
return clearValues.data();
|
||||||
|
}
|
||||||
|
inline VkRect2D getRenderArea() const
|
||||||
|
{
|
||||||
|
return renderArea;
|
||||||
|
}
|
||||||
|
inline VkSubpassContents getSubpassContents() const
|
||||||
|
{
|
||||||
|
return subpassContents;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
VkRenderPass renderPass;
|
||||||
|
Array<VkClearValue> clearValues;
|
||||||
|
VkRect2D renderArea;
|
||||||
|
VkSubpassContents subpassContents;
|
||||||
|
};
|
||||||
|
DEFINE_REF(RenderPass);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
Seele::WindowManager::WindowManager()
|
Seele::WindowManager::WindowManager()
|
||||||
{
|
{
|
||||||
graphics = new VulkanGraphics();
|
graphics = new Vulkan::Graphics();
|
||||||
GraphicsInitializer initializer;
|
GraphicsInitializer initializer;
|
||||||
graphics->init(initializer);
|
graphics->init(initializer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ namespace Seele
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~RefObject()
|
~RefObject()
|
||||||
{}
|
{}
|
||||||
bool operator==(const RefObject& other) const
|
bool operator==(const RefObject& other) const
|
||||||
@@ -81,6 +80,10 @@ namespace Seele
|
|||||||
{
|
{
|
||||||
object = nullptr;
|
object = nullptr;
|
||||||
}
|
}
|
||||||
|
RefPtr(nullptr_t)
|
||||||
|
{
|
||||||
|
object = nullptr;
|
||||||
|
}
|
||||||
RefPtr(T* ptr)
|
RefPtr(T* ptr)
|
||||||
{
|
{
|
||||||
object = new RefObject<T>(ptr);
|
object = new RefObject<T>(ptr);
|
||||||
@@ -160,14 +163,19 @@ namespace Seele
|
|||||||
private:
|
private:
|
||||||
RefObject<T>* object;
|
RefObject<T>* object;
|
||||||
};
|
};
|
||||||
|
//A weak pointer has no ownership over an object and thus cant delete it
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class WeakPtr
|
class WeakPtr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WeakPtr()
|
WeakPtr()
|
||||||
|
: pointer(nullptr)
|
||||||
|
{}
|
||||||
|
WeakPtr(T* ptr)
|
||||||
|
: pointer(ptr)
|
||||||
{}
|
{}
|
||||||
WeakPtr(RefPtr<T>& sharedPtr)
|
WeakPtr(RefPtr<T>& sharedPtr)
|
||||||
: pointer(sharedPtr.object)
|
: pointer(sharedPtr.object->handle)
|
||||||
{}
|
{}
|
||||||
WeakPtr& operator=(WeakPtr<T>& weakPtr)
|
WeakPtr& operator=(WeakPtr<T>& weakPtr)
|
||||||
{
|
{
|
||||||
@@ -176,17 +184,20 @@ namespace Seele
|
|||||||
}
|
}
|
||||||
WeakPtr& operator=(RefPtr<T>& sharedPtr)
|
WeakPtr& operator=(RefPtr<T>& sharedPtr)
|
||||||
{
|
{
|
||||||
pointer = sharedPtr;
|
pointer = sharedPtr.object->handle;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
RefPtr<T>& lock()
|
WeakPtr& operator=(T* ptr)
|
||||||
{
|
{
|
||||||
RefPtr<T> temp;
|
pointer = ptr;
|
||||||
temp.object = pointer;
|
return *this;
|
||||||
return temp;
|
}
|
||||||
|
inline T* operator->()
|
||||||
|
{
|
||||||
|
return pointer;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
RefObject<T>* pointer;
|
T* pointer;
|
||||||
};
|
};
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class UniquePtr
|
class UniquePtr
|
||||||
|
|||||||
Reference in New Issue
Block a user