Add Buffer
This commit is contained in:
parent
72a5a1d901
commit
7d2b9e6f1b
@ -1,5 +1,5 @@
|
|||||||
# NF library CMakeLists.txt
|
# NF library CMakeLists.txt
|
||||||
add_library(NothinFancy STATIC "src/Engine.cpp" "src/include/nf.h" "src/pch.h" "src/util.h" "src/util/log.h" "src/util/log.cpp" "src/include/nf/config.h" "src/util/util.cpp" "src/util/file.h" "src/util/file.cpp" "src/client/Client.h" "src/client/Client.cpp" "src/client/Window.h" "src/client/Window.cpp" "src/client/render/RenderEngine.h" "src/client/render/RenderEngine.cpp" "src/client/render/ShaderModule.h" "src/client/render/ShaderModule.cpp")
|
add_library(NothinFancy STATIC "src/Engine.cpp" "src/include/nf.h" "src/pch.h" "src/util.h" "src/util/log.h" "src/util/log.cpp" "src/include/nf/config.h" "src/util/util.cpp" "src/util/file.h" "src/util/file.cpp" "src/client/Client.h" "src/client/Client.cpp" "src/client/Window.h" "src/client/Window.cpp" "src/client/render/RenderEngine.h" "src/client/render/RenderEngine.cpp" "src/client/render/ShaderModule.h" "src/client/render/ShaderModule.cpp" "src/client/render/VulkanResource.h" "src/client/render/Buffer.h" "src/client/render/Buffer.cpp")
|
||||||
|
|
||||||
# Use C++20
|
# Use C++20
|
||||||
set_property(TARGET NothinFancy PROPERTY CXX_STANDARD 20)
|
set_property(TARGET NothinFancy PROPERTY CXX_STANDARD 20)
|
||||||
|
110
NothinFancy/src/client/render/Buffer.cpp
Normal file
110
NothinFancy/src/client/render/Buffer.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// Buffer class implementation
|
||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include "Buffer.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace nf::client::render {
|
||||||
|
Buffer::Buffer(const VkDevice& device, const VkPhysicalDevice& physicalDevice, const VkCommandPool& commandPool, const VkQueue& queue, void* bufferData, size_t bufferSize)
|
||||||
|
: VulkanResource(device)
|
||||||
|
, m_handle()
|
||||||
|
, m_memory()
|
||||||
|
{
|
||||||
|
VkBuffer stagingBuffer = nullptr;
|
||||||
|
VkDeviceMemory stagingBufferMemory = nullptr;
|
||||||
|
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, physicalDevice, stagingBuffer, stagingBufferMemory);
|
||||||
|
|
||||||
|
void* bufferPointer = nullptr;
|
||||||
|
vkMapMemory(m_device, stagingBufferMemory, 0, bufferSize, 0, &bufferPointer);
|
||||||
|
std::memcpy(bufferPointer, bufferData, bufferSize);
|
||||||
|
vkUnmapMemory(m_device, stagingBufferMemory);
|
||||||
|
|
||||||
|
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, physicalDevice, m_handle, m_memory);
|
||||||
|
|
||||||
|
copyBuffer(stagingBuffer, m_handle, bufferSize, commandPool, queue);
|
||||||
|
|
||||||
|
destroyBuffer(stagingBuffer, stagingBufferMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VkBuffer& Buffer::getHandle() const {
|
||||||
|
return m_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkPhysicalDevice physicalDevice, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
|
||||||
|
VkBufferCreateInfo bufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||||
|
bufferCI.size = size;
|
||||||
|
bufferCI.usage = usage;
|
||||||
|
|
||||||
|
if (vkCreateBuffer(m_device, &bufferCI, nullptr, &buffer) != VK_SUCCESS)
|
||||||
|
NFError("Could not create vertex buffer.");
|
||||||
|
|
||||||
|
VkMemoryRequirements memoryRequirements = {};
|
||||||
|
vkGetBufferMemoryRequirements(m_device, buffer, &memoryRequirements);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||||
|
allocateInfo.allocationSize = memoryRequirements.size;
|
||||||
|
allocateInfo.memoryTypeIndex = findMemoryType(physicalDevice, memoryRequirements.memoryTypeBits, memoryProperties);
|
||||||
|
|
||||||
|
if (allocateInfo.memoryTypeIndex == -1)
|
||||||
|
NFError("Could not find suitable memory type.");
|
||||||
|
|
||||||
|
if (vkAllocateMemory(m_device, &allocateInfo, nullptr, &bufferMemory) != VK_SUCCESS)
|
||||||
|
NFError("Could not allocate buffer memory.");
|
||||||
|
|
||||||
|
vkBindBufferMemory(m_device, buffer, bufferMemory, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Buffer::findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) {
|
||||||
|
VkPhysicalDeviceMemoryProperties memoryProperties = {};
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
|
||||||
|
|
||||||
|
for (int i = 0; i < memoryProperties.memoryTypeCount; i++)
|
||||||
|
if (typeFilter & (1 << i) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::copyBuffer(VkBuffer bufferSource, VkBuffer bufferDestination, VkDeviceSize size, VkCommandPool commandPool, VkQueue queue) {
|
||||||
|
VkCommandBuffer commandBuffer = nullptr;
|
||||||
|
VkCommandBufferAllocateInfo commandBufferAI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
|
||||||
|
commandBufferAI.commandPool = commandPool;
|
||||||
|
commandBufferAI.commandBufferCount = 1;
|
||||||
|
|
||||||
|
if (vkAllocateCommandBuffers(m_device, &commandBufferAI, &commandBuffer) != VK_SUCCESS)
|
||||||
|
NFError("Could not create command buffer.");
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo commandBufferBI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||||
|
commandBufferBI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
|
||||||
|
if (vkBeginCommandBuffer(commandBuffer, &commandBufferBI) != VK_SUCCESS)
|
||||||
|
NFError("Could not begin recording command buffer.");
|
||||||
|
|
||||||
|
VkBufferCopy bufferCopyRegion = {};
|
||||||
|
bufferCopyRegion.size = size;
|
||||||
|
vkCmdCopyBuffer(commandBuffer, bufferSource, bufferDestination, 1, &bufferCopyRegion);
|
||||||
|
|
||||||
|
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS)
|
||||||
|
NFError("Could not end command buffer.");
|
||||||
|
|
||||||
|
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = &commandBuffer;
|
||||||
|
|
||||||
|
if (vkQueueSubmit(queue, 1, &submitInfo, nullptr) != VK_SUCCESS)
|
||||||
|
NFError("Could not submit to Vulkan queue.");
|
||||||
|
|
||||||
|
vkQueueWaitIdle(queue);
|
||||||
|
|
||||||
|
vkFreeCommandBuffers(m_device, commandPool, 1, &commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::destroyBuffer(VkBuffer buffer, VkDeviceMemory bufferMemory) {
|
||||||
|
vkFreeMemory(m_device, bufferMemory, nullptr);
|
||||||
|
vkDestroyBuffer(m_device, buffer, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer::~Buffer() {
|
||||||
|
destroyBuffer(m_handle, m_memory);
|
||||||
|
}
|
||||||
|
}
|
24
NothinFancy/src/client/render/Buffer.h
Normal file
24
NothinFancy/src/client/render/Buffer.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Buffer class header
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VulkanResource.h"
|
||||||
|
|
||||||
|
namespace nf::client::render {
|
||||||
|
class Buffer : VulkanResource {
|
||||||
|
public:
|
||||||
|
Buffer(const VkDevice& device, const VkPhysicalDevice& physicalDevice, const VkCommandPool& commandPool, const VkQueue& queue, void* bufferData, size_t bufferSize);
|
||||||
|
|
||||||
|
const VkBuffer& getHandle() const;
|
||||||
|
|
||||||
|
~Buffer();
|
||||||
|
private:
|
||||||
|
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkPhysicalDevice physicalDevice, VkBuffer& buffer, VkDeviceMemory& bufferMemory);
|
||||||
|
uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||||
|
void copyBuffer(VkBuffer sourceBuffer, VkBuffer destinationBuffer, VkDeviceSize size, VkCommandPool commandPool, VkQueue queue);
|
||||||
|
|
||||||
|
void destroyBuffer(VkBuffer buffer, VkDeviceMemory bufferMemory);
|
||||||
|
|
||||||
|
VkBuffer m_handle;
|
||||||
|
VkDeviceMemory m_memory;
|
||||||
|
};
|
||||||
|
}
|
@ -37,7 +37,6 @@ namespace nf::client::render {
|
|||||||
, m_frameExecutors()
|
, m_frameExecutors()
|
||||||
, m_currentFrameExecutor()
|
, m_currentFrameExecutor()
|
||||||
, m_bufferVertex()
|
, m_bufferVertex()
|
||||||
, m_memoryVertexBuffer()
|
|
||||||
{
|
{
|
||||||
NFLog("Initializing render engine");
|
NFLog("Initializing render engine");
|
||||||
m_window->setDisplay(m_display);
|
m_window->setDisplay(m_display);
|
||||||
@ -450,100 +449,8 @@ namespace nf::client::render {
|
|||||||
{{-0.5, 0.5}, {0.0, 0.0, 1.0}}
|
{{-0.5, 0.5}, {0.0, 0.0, 1.0}}
|
||||||
};
|
};
|
||||||
|
|
||||||
VkBuffer stagingBuffer = nullptr;
|
size_t triangleDataSize = sizeof(triangleData[0]) * triangleData.size();
|
||||||
VkBufferCreateInfo bufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
m_bufferVertex = new Buffer(m_device, m_physicalDevice, m_commandPool, m_queueGraphics, triangleData.data(), triangleDataSize);
|
||||||
bufferCI.size = sizeof(triangleData[0]) * triangleData.size();
|
|
||||||
bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
|
|
||||||
if (vkCreateBuffer(m_device, &bufferCI, nullptr, &stagingBuffer) != VK_SUCCESS)
|
|
||||||
NFError("Could not create vertex buffer.");
|
|
||||||
|
|
||||||
VkMemoryRequirements memoryRequirements = {};
|
|
||||||
vkGetBufferMemoryRequirements(m_device, stagingBuffer, &memoryRequirements);
|
|
||||||
|
|
||||||
VkPhysicalDeviceMemoryProperties memoryProperties = {};
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memoryProperties);
|
|
||||||
|
|
||||||
VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
|
||||||
std::optional<uint32_t> memoryTypeIndex;
|
|
||||||
for (int i = 0; i < memoryProperties.memoryTypeCount; i++)
|
|
||||||
if (memoryRequirements.memoryTypeBits & (1 << i) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
|
|
||||||
memoryTypeIndex = i;
|
|
||||||
|
|
||||||
if (!memoryTypeIndex.has_value())
|
|
||||||
NFError("Could not find suitable memory type.");
|
|
||||||
|
|
||||||
VkDeviceMemory stagingBufferMemory = nullptr;
|
|
||||||
VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
|
||||||
allocateInfo.allocationSize = memoryRequirements.size;
|
|
||||||
allocateInfo.memoryTypeIndex = memoryTypeIndex.value();
|
|
||||||
|
|
||||||
if (vkAllocateMemory(m_device, &allocateInfo, nullptr, &stagingBufferMemory) != VK_SUCCESS)
|
|
||||||
NFError("Could not allocate video memory.");
|
|
||||||
|
|
||||||
vkBindBufferMemory(m_device, stagingBuffer, stagingBufferMemory, 0);
|
|
||||||
|
|
||||||
void* bufferPointer = nullptr;
|
|
||||||
vkMapMemory(m_device, stagingBufferMemory, 0, bufferCI.size, 0, &bufferPointer);
|
|
||||||
std::memcpy(bufferPointer, triangleData.data(), bufferCI.size);
|
|
||||||
vkUnmapMemory(m_device, stagingBufferMemory);
|
|
||||||
|
|
||||||
bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
|
||||||
if (vkCreateBuffer(m_device, &bufferCI, nullptr, &m_bufferVertex) != VK_SUCCESS)
|
|
||||||
NFError("Could not create vertex buffer.");
|
|
||||||
|
|
||||||
vkGetBufferMemoryRequirements(m_device, m_bufferVertex, &memoryRequirements);
|
|
||||||
|
|
||||||
properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
|
||||||
memoryTypeIndex.reset();
|
|
||||||
for (int i = 0; i < memoryProperties.memoryTypeCount; i++)
|
|
||||||
if (memoryRequirements.memoryTypeBits & (1 << i) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
|
|
||||||
memoryTypeIndex = i;
|
|
||||||
|
|
||||||
if (!memoryTypeIndex.has_value())
|
|
||||||
NFError("Could not find suitable memory type.");
|
|
||||||
|
|
||||||
allocateInfo.allocationSize = memoryRequirements.size;
|
|
||||||
allocateInfo.memoryTypeIndex = memoryTypeIndex.value();
|
|
||||||
|
|
||||||
if (vkAllocateMemory(m_device, &allocateInfo, nullptr, &m_memoryVertexBuffer) != VK_SUCCESS)
|
|
||||||
NFError("Could not allocate video memory.");
|
|
||||||
|
|
||||||
vkBindBufferMemory(m_device, m_bufferVertex, m_memoryVertexBuffer, 0);
|
|
||||||
|
|
||||||
VkCommandBuffer commandBuffer = nullptr;
|
|
||||||
VkCommandBufferAllocateInfo commandBufferAI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
|
|
||||||
commandBufferAI.commandPool = m_commandPool;
|
|
||||||
commandBufferAI.commandBufferCount = 1;
|
|
||||||
|
|
||||||
if (vkAllocateCommandBuffers(m_device, &commandBufferAI, &commandBuffer) != VK_SUCCESS)
|
|
||||||
NFError("Could not create command buffer.");
|
|
||||||
|
|
||||||
VkCommandBufferBeginInfo commandBufferBI = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
|
||||||
commandBufferBI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
||||||
|
|
||||||
if (vkBeginCommandBuffer(commandBuffer, &commandBufferBI) != VK_SUCCESS)
|
|
||||||
NFError("Could not begin recording command buffer.");
|
|
||||||
|
|
||||||
VkBufferCopy bufferCopyRegion = {};
|
|
||||||
bufferCopyRegion.size = bufferCI.size;
|
|
||||||
vkCmdCopyBuffer(commandBuffer, stagingBuffer, m_bufferVertex, 1, &bufferCopyRegion);
|
|
||||||
|
|
||||||
if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS)
|
|
||||||
NFError("Could not end command buffer.");
|
|
||||||
|
|
||||||
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
|
||||||
submitInfo.commandBufferCount = 1;
|
|
||||||
submitInfo.pCommandBuffers = &commandBuffer;
|
|
||||||
|
|
||||||
if (vkQueueSubmit(m_queueGraphics, 1, &submitInfo, nullptr) != VK_SUCCESS)
|
|
||||||
NFError("Could not submit to Vulkan queue.");
|
|
||||||
|
|
||||||
vkQueueWaitIdle(m_queueGraphics);
|
|
||||||
|
|
||||||
vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer);
|
|
||||||
vkFreeMemory(m_device, stagingBufferMemory, nullptr);
|
|
||||||
vkDestroyBuffer(m_device, stagingBuffer, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderEngine::doFrame() {
|
void RenderEngine::doFrame() {
|
||||||
@ -595,7 +502,7 @@ namespace nf::client::render {
|
|||||||
|
|
||||||
// Bind vertex buffer
|
// Bind vertex buffer
|
||||||
VkDeviceSize vertexBufferOffset = 0;
|
VkDeviceSize vertexBufferOffset = 0;
|
||||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_bufferVertex, &vertexBufferOffset);
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_bufferVertex->getHandle(), &vertexBufferOffset);
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
|
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
|
||||||
@ -676,8 +583,7 @@ namespace nf::client::render {
|
|||||||
vkDestroySemaphore(m_device, m_frameExecutors[i].semaphoreImageAvailable, nullptr);
|
vkDestroySemaphore(m_device, m_frameExecutors[i].semaphoreImageAvailable, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
vkFreeMemory(m_device, m_memoryVertexBuffer, nullptr);
|
delete m_bufferVertex;
|
||||||
vkDestroyBuffer(m_device, m_bufferVertex, nullptr);
|
|
||||||
|
|
||||||
destroySwapchain();
|
destroySwapchain();
|
||||||
vkDestroyCommandPool(m_device, m_commandPool, nullptr);
|
vkDestroyCommandPool(m_device, m_commandPool, nullptr);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "client/Window.h"
|
#include "client/Window.h"
|
||||||
#include "nf/config.h"
|
#include "nf/config.h"
|
||||||
|
#include "Buffer.h"
|
||||||
|
|
||||||
namespace nf::client::render {
|
namespace nf::client::render {
|
||||||
struct FrameExecutor {
|
struct FrameExecutor {
|
||||||
@ -67,7 +68,6 @@ namespace nf::client::render {
|
|||||||
std::vector<FrameExecutor> m_frameExecutors;
|
std::vector<FrameExecutor> m_frameExecutors;
|
||||||
uint32_t m_currentFrameExecutor;
|
uint32_t m_currentFrameExecutor;
|
||||||
|
|
||||||
VkBuffer m_bufferVertex;
|
Buffer* m_bufferVertex;
|
||||||
VkDeviceMemory m_memoryVertexBuffer;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace nf::client::render {
|
namespace nf::client::render {
|
||||||
ShaderModule::ShaderModule(const VkDevice& device, const std::string& shaderBinary)
|
ShaderModule::ShaderModule(const VkDevice& device, const std::string& shaderBinary)
|
||||||
: m_device(device)
|
: VulkanResource(device)
|
||||||
, m_shaderModule()
|
, m_shaderModule()
|
||||||
{
|
{
|
||||||
VkShaderModuleCreateInfo shaderModuleCI = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
|
VkShaderModuleCreateInfo shaderModuleCI = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
// ShaderModule class header
|
// ShaderModule class header
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "VulkanResource.h"
|
||||||
|
|
||||||
namespace nf::client::render {
|
namespace nf::client::render {
|
||||||
class ShaderModule {
|
class ShaderModule : VulkanResource {
|
||||||
public:
|
public:
|
||||||
ShaderModule(const VkDevice& device, const std::string& shaderBinary);
|
ShaderModule(const VkDevice& device, const std::string& shaderBinary);
|
||||||
|
|
||||||
@ -10,8 +12,6 @@ namespace nf::client::render {
|
|||||||
|
|
||||||
~ShaderModule();
|
~ShaderModule();
|
||||||
private:
|
private:
|
||||||
const VkDevice& m_device;
|
|
||||||
|
|
||||||
VkShaderModule m_shaderModule;
|
VkShaderModule m_shaderModule;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
14
NothinFancy/src/client/render/VulkanResource.h
Normal file
14
NothinFancy/src/client/render/VulkanResource.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Vulkan resource base class header
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace nf::client::render {
|
||||||
|
class VulkanResource {
|
||||||
|
public:
|
||||||
|
VulkanResource(const VkDevice& device)
|
||||||
|
: m_device(device)
|
||||||
|
{}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const VkDevice& m_device;
|
||||||
|
};
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user