Use allocator for buffers/images
everything now uses VulkanAllocator for allocations (through VulkanInstance::createXXX functions)
This commit is contained in:
parent
e8f736d27f
commit
2bc7fe05f2
@ -13,7 +13,7 @@ CXXFLAGS += $(IFLAGS)
|
|||||||
# SETTINGS
|
# SETTINGS
|
||||||
OBJECT_DIR = ../build
|
OBJECT_DIR = ../build
|
||||||
EXEC = ../vulkan_test
|
EXEC = ../vulkan_test
|
||||||
LOG_LEVEL = LOG_LEVEL_2
|
LOG_LEVEL = LOG_LEVEL_0
|
||||||
|
|
||||||
CXXFLAGS += -D $(LOG_LEVEL)
|
CXXFLAGS += -D $(LOG_LEVEL)
|
||||||
|
|
||||||
|
@ -64,13 +64,13 @@ namespace gz::vk {
|
|||||||
try {
|
try {
|
||||||
uint32_t imageIndex;
|
uint32_t imageIndex;
|
||||||
/* std::chrono::time_point now = std::chrono::system_clock::now(); */
|
/* std::chrono::time_point now = std::chrono::system_clock::now(); */
|
||||||
while (! glfwWindowShouldClose(vulkanInstance.window)) {
|
while (! glfwWindowShouldClose(vulkanInstance.getWindow())) {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
imageIndex = vulkanInstance.beginFrameDraw();
|
imageIndex = vulkanInstance.beginFrameDraw();
|
||||||
r2D.drawFrame(imageIndex);
|
r2D.drawFrame(imageIndex);
|
||||||
r3D.drawFrame(imageIndex);
|
r3D.drawFrame(imageIndex);
|
||||||
vulkanInstance.endFrameDraw(imageIndex);
|
vulkanInstance.endFrameDraw(imageIndex);
|
||||||
auto SLEEP_TIME = std::chrono::milliseconds(1000 / vulkanInstance.settings.get<uint32_t>("framerate"));
|
auto SLEEP_TIME = std::chrono::milliseconds(1000 / vulkanInstance.getSettings().get<uint32_t>("framerate"));
|
||||||
std::this_thread::sleep_for(SLEEP_TIME);
|
std::this_thread::sleep_for(SLEEP_TIME);
|
||||||
/* std::chrono::time_point now2 = std::chrono::system_clock::now(); */
|
/* std::chrono::time_point now2 = std::chrono::system_clock::now(); */
|
||||||
/* std::chrono::nanoseconds dur = std::chrono::duration_cast<std::chrono::nanoseconds>(now2 - now); */
|
/* std::chrono::nanoseconds dur = std::chrono::duration_cast<std::chrono::nanoseconds>(now2 - now); */
|
||||||
|
@ -43,6 +43,9 @@ namespace gz::vk {
|
|||||||
|
|
||||||
|
|
||||||
void Renderer2D::cleanup() {
|
void Renderer2D::cleanup() {
|
||||||
|
rLog.log0("cleanup: cleaning up");
|
||||||
|
// UPDATE DOC ON CHANGES!
|
||||||
|
|
||||||
/* vk.destroyCommandBuffers(commandBuffers); */
|
/* vk.destroyCommandBuffers(commandBuffers); */
|
||||||
cleanupSwapChainDependantResources();
|
cleanupSwapChainDependantResources();
|
||||||
cleanup_();
|
cleanup_();
|
||||||
@ -68,9 +71,8 @@ namespace gz::vk {
|
|||||||
vk.destroyFramebuffers(framebuffers);
|
vk.destroyFramebuffers(framebuffers);
|
||||||
|
|
||||||
for (size_t i = 0; i < images.size(); i++) {
|
for (size_t i = 0; i < images.size(); i++) {
|
||||||
vkDestroyImageView(vk.getDevice(), imageViews[i], nullptr);
|
vk.destroyImageView(imageViews[i]);
|
||||||
vkDestroyImage(vk.getDevice(), images[i], nullptr);
|
vk.destroyImage(images[i], imageMemory[i]);
|
||||||
vkFreeMemory(vk.getDevice(), imageMemory[i], nullptr);
|
|
||||||
}
|
}
|
||||||
vkDestroyRenderPass(vk.getDevice(), renderPass, nullptr);
|
vkDestroyRenderPass(vk.getDevice(), renderPass, nullptr);
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
|
|
||||||
#include "shape.hpp"
|
#include "shape.hpp"
|
||||||
|
#include "vulkan_allocator.hpp"
|
||||||
#include "vulkan_util.hpp"
|
#include "vulkan_util.hpp"
|
||||||
|
|
||||||
namespace gz::vk {
|
namespace gz::vk {
|
||||||
@ -67,7 +68,7 @@ namespace gz::vk {
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
std::vector<VkImage> images;
|
std::vector<VkImage> images;
|
||||||
std::vector<VkDeviceMemory> imageMemory;
|
std::vector<MemoryInfo> imageMemory;
|
||||||
std::vector<VkImageView> imageViews;
|
std::vector<VkImageView> imageViews;
|
||||||
/**
|
/**
|
||||||
* @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images
|
* @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "renderer3D.hpp"
|
#include "renderer3D.hpp"
|
||||||
|
|
||||||
#include "vertex.hpp"
|
#include "vertex.hpp"
|
||||||
|
#include "vulkan_allocator.hpp"
|
||||||
#include "vulkan_instance.hpp"
|
#include "vulkan_instance.hpp"
|
||||||
#include "texture_manager.hpp"
|
#include "texture_manager.hpp"
|
||||||
#include "exceptions.hpp"
|
#include "exceptions.hpp"
|
||||||
@ -49,10 +50,14 @@ namespace gz::vk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Renderer3D::cleanup() {
|
void Renderer3D::cleanup() {
|
||||||
|
rLog.log0("cleanup: cleaning up");
|
||||||
|
// UPDATE DOC ON CHANGES!
|
||||||
for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) {
|
for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) {
|
||||||
vkDestroyBuffer(vk.getDevice(), uniformBuffers[i], nullptr);
|
vk.destroyBuffer(uniformBuffers[i], uniformBuffersMemory[i]);
|
||||||
vkFreeMemory(vk.getDevice(), uniformBuffersMemory[i], nullptr);
|
|
||||||
}
|
}
|
||||||
|
vkDestroyDescriptorSetLayout(vk.getDevice(), descriptorSetLayout, NO_ALLOC);
|
||||||
|
vkDestroyDescriptorPool(vk.getDevice(), descriptorPool, NO_ALLOC);
|
||||||
|
|
||||||
cleanupSwapChainDependantResources();
|
cleanupSwapChainDependantResources();
|
||||||
cleanup_();
|
cleanup_();
|
||||||
}
|
}
|
||||||
@ -77,9 +82,8 @@ namespace gz::vk {
|
|||||||
vk.destroyFramebuffers(framebuffers);
|
vk.destroyFramebuffers(framebuffers);
|
||||||
|
|
||||||
for (size_t i = 0; i < images.size(); i++) {
|
for (size_t i = 0; i < images.size(); i++) {
|
||||||
vkDestroyImageView(vk.getDevice(), imageViews[i], nullptr);
|
vk.destroyImageView(imageViews[i]);
|
||||||
vkDestroyImage(vk.getDevice(), images[i], nullptr);
|
vk.destroyImage(images[i], imageMemory[i]);
|
||||||
vkFreeMemory(vk.getDevice(), imageMemory[i], nullptr);
|
|
||||||
}
|
}
|
||||||
vkDestroyRenderPass(vk.getDevice(), renderPass, nullptr);
|
vkDestroyRenderPass(vk.getDevice(), renderPass, nullptr);
|
||||||
|
|
||||||
@ -313,32 +317,28 @@ namespace gz::vk {
|
|||||||
// copy to vertexBuffer
|
// copy to vertexBuffer
|
||||||
// create staging buffer
|
// create staging buffer
|
||||||
VkBuffer stagingBuffer;
|
VkBuffer stagingBuffer;
|
||||||
VkDeviceMemory stagingBufferMemory;
|
MemoryInfo stagingBufferMemory;
|
||||||
vk.createBuffer(requiredVertexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
|
vk.createBuffer(requiredVertexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
|
||||||
// fill staging buffer
|
// fill staging buffer
|
||||||
void* data;
|
void* data;
|
||||||
vkMapMemory(vk.getDevice(), stagingBufferMemory, NO_OFFSET, requiredVertexBufferSize, NO_FLAGS, &data);
|
vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, requiredVertexBufferSize, NO_FLAGS, &data);
|
||||||
memcpy(data, model.vertices.data(), requiredVertexBufferSize);
|
memcpy(data, model.vertices.data(), requiredVertexBufferSize);
|
||||||
vkUnmapMemory(vk.getDevice(), stagingBufferMemory);
|
vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory);
|
||||||
// fill vertex buffer
|
// fill vertex buffer
|
||||||
vk.copyBuffer(stagingBuffer, vertexBuffer, requiredVertexBufferSize);
|
vk.copyBuffer(stagingBuffer, vertexBuffer, requiredVertexBufferSize);
|
||||||
vkDestroyBuffer(vk.getDevice(), stagingBuffer, nullptr);
|
vk.destroyBuffer(stagingBuffer, stagingBufferMemory);
|
||||||
vkFreeMemory(vk.getDevice(), stagingBufferMemory, nullptr);
|
|
||||||
|
|
||||||
rLog.log0("Renderer3D: loadModel: filling index buffer");
|
rLog.log0("Renderer3D: loadModel: filling index buffer");
|
||||||
data = nullptr;
|
data = nullptr;
|
||||||
stagingBuffer = VK_NULL_HANDLE;
|
|
||||||
stagingBufferMemory = VK_NULL_HANDLE;
|
|
||||||
// copy to index buffer
|
// copy to index buffer
|
||||||
vk.createBuffer(requiredIndexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
|
vk.createBuffer(requiredIndexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
|
||||||
// fill staging buffer
|
// fill staging buffer
|
||||||
vkMapMemory(vk.getDevice(), stagingBufferMemory, NO_OFFSET, requiredIndexBufferSize, NO_FLAGS, &data);
|
vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, requiredIndexBufferSize, NO_FLAGS, &data);
|
||||||
memcpy(data, model.indices.data(), requiredIndexBufferSize);
|
memcpy(data, model.indices.data(), requiredIndexBufferSize);
|
||||||
vkUnmapMemory(vk.getDevice(), stagingBufferMemory);
|
vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory);
|
||||||
// fill index buffer
|
// fill index buffer
|
||||||
vk.copyBuffer(stagingBuffer, indexBuffer, requiredIndexBufferSize);
|
vk.copyBuffer(stagingBuffer, indexBuffer, requiredIndexBufferSize);
|
||||||
vkDestroyBuffer(vk.getDevice(), stagingBuffer, nullptr);
|
vk.destroyBuffer(stagingBuffer, stagingBufferMemory);
|
||||||
vkFreeMemory(vk.getDevice(), stagingBufferMemory, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -434,10 +434,11 @@ namespace gz::vk {
|
|||||||
/* ubo.view = glm::mat4(1); */
|
/* ubo.view = glm::mat4(1); */
|
||||||
/* ubo.projection = glm::mat4(1); */
|
/* ubo.projection = glm::mat4(1); */
|
||||||
/* ubo.projection[1][1] *= -1; // y coordinate inverted in opengl */
|
/* ubo.projection[1][1] *= -1; // y coordinate inverted in opengl */
|
||||||
|
MemoryInfo& uniformBufferMI = uniformBuffersMemory[vk.getCurrentFrame()];
|
||||||
void* data;
|
void* data;
|
||||||
vkMapMemory(vk.getDevice(), uniformBuffersMemory[vk.getCurrentFrame()], NO_OFFSET, sizeof(ubo), NO_FLAGS, &data);
|
vkMapMemory(vk.getDevice(), uniformBufferMI.memory, uniformBufferMI.offset, sizeof(ubo), NO_FLAGS, &data);
|
||||||
memcpy(data, &ubo, sizeof(ubo));
|
memcpy(data, &ubo, sizeof(ubo));
|
||||||
vkUnmapMemory(vk.getDevice(), uniformBuffersMemory[vk.getCurrentFrame()]);
|
vkUnmapMemory(vk.getDevice(), uniformBufferMI.memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
|
|
||||||
|
#include "vulkan_allocator.hpp"
|
||||||
#include "vulkan_util.hpp"
|
#include "vulkan_util.hpp"
|
||||||
|
|
||||||
namespace gz::vk {
|
namespace gz::vk {
|
||||||
@ -34,7 +35,7 @@ namespace gz::vk {
|
|||||||
private:
|
private:
|
||||||
void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame);
|
void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame);
|
||||||
std::vector<VkBuffer> uniformBuffers;
|
std::vector<VkBuffer> uniformBuffers;
|
||||||
std::vector<VkDeviceMemory> uniformBuffersMemory;
|
std::vector<MemoryInfo> uniformBuffersMemory;
|
||||||
void createUniformBuffers();
|
void createUniformBuffers();
|
||||||
void updateUniformBuffer();
|
void updateUniformBuffer();
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ namespace gz::vk {
|
|||||||
*/
|
*/
|
||||||
/// @{
|
/// @{
|
||||||
std::vector<VkImage> images;
|
std::vector<VkImage> images;
|
||||||
std::vector<VkDeviceMemory> imageMemory;
|
std::vector<MemoryInfo> imageMemory;
|
||||||
std::vector<VkImageView> imageViews;
|
std::vector<VkImageView> imageViews;
|
||||||
/**
|
/**
|
||||||
* @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images
|
* @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images
|
||||||
@ -137,6 +138,7 @@ namespace gz::vk {
|
|||||||
* @details:
|
* @details:
|
||||||
* Does:
|
* Does:
|
||||||
* -# destroy uniform buffers
|
* -# destroy uniform buffers
|
||||||
|
* -# destroy descriptor set layout and pool
|
||||||
* -# call cleanupSwapChainDependantResources()
|
* -# call cleanupSwapChainDependantResources()
|
||||||
* -# call Renderer::cleanup_()
|
* -# call Renderer::cleanup_()
|
||||||
*/
|
*/
|
||||||
|
@ -20,17 +20,28 @@ std::string TextureImageArea::toString() const {
|
|||||||
return "<(" + gz::toString(x) + "," + gz::toString(y) + "), (" + gz::toString(width) + "x" + gz::toString(height) + ")>";
|
return "<(" + gz::toString(x) + "," + gz::toString(y) + "), (" + gz::toString(width) + "x" + gz::toString(height) + ")>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// INIT & CLEANUP
|
// INIT & CLEANUP
|
||||||
//
|
//
|
||||||
TextureAtlas::TextureAtlas(VulkanInstance& instance, uint16_t slotWidth, uint16_t slotHeight, uint16_t slotCountX, uint16_t slotCountY)
|
TextureAtlas::TextureAtlas(VulkanInstance& instance, uint16_t slotWidth, uint16_t slotHeight, uint16_t slotCountX, uint16_t slotCountY)
|
||||||
: vk(instance), slotWidth(slotWidth), slotHeight(slotHeight), slotCountX(slotCountX), slotCountY(slotCountY)
|
: vk(instance),
|
||||||
|
slotWidth(slotWidth), slotHeight(slotHeight),
|
||||||
|
slotCountX(slotCountX), slotCountY(slotCountY)
|
||||||
{
|
{
|
||||||
|
#ifdef LOG_LEVEL_0
|
||||||
|
LogCreateInfo logCI{};
|
||||||
|
logCI.logfile = "textureAtlas.log";
|
||||||
|
logCI.storeLog = false;
|
||||||
|
logCI.prefix = "TextureAtlas (" + gz::toString(slotCountX) + "x" + gz::toString(slotCountY) + ")X(" + gz::toString(slotWidth) + "x" + gz::toString(slotHeight) + ")";
|
||||||
|
logCI.prefixColor = Color::GREEN;
|
||||||
|
logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR;
|
||||||
|
tLog = Log(std::move(logCI));
|
||||||
|
#endif
|
||||||
|
|
||||||
// whole image
|
// whole image
|
||||||
freeAreas.insert({ 0, 0, slotCountX, slotCountY});
|
freeAreas.insert({ 0, 0, slotCountX, slotCountY});
|
||||||
createImageResources();
|
createImageResources();
|
||||||
vk.registerCleanupCallback(std::bind(&TextureAtlas::cleanup, this));
|
/* vk.registerCleanupCallback(std::bind(&TextureAtlas::cleanup, this)); */
|
||||||
VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan(std::string("TextureAtlas-") + gz::toString(slotWidth) + "x" + gz::toString(slotHeight),
|
VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan(std::string("TextureAtlas-") + gz::toString(slotWidth) + "x" + gz::toString(slotHeight),
|
||||||
{ &textureImage, &textureImageMemory, &textureImageView, &textureSampler },
|
{ &textureImage, &textureImageMemory, &textureImageView, &textureSampler },
|
||||||
{}));
|
{}));
|
||||||
@ -38,11 +49,12 @@ TextureAtlas::TextureAtlas(VulkanInstance& instance, uint16_t slotWidth, uint16_
|
|||||||
|
|
||||||
|
|
||||||
void TextureAtlas::cleanup() {
|
void TextureAtlas::cleanup() {
|
||||||
VulkanInstance::vLog("TextureAtlas::cleanup, textureSampler", reinterpret_cast<uint64_t>(textureSampler), "textureImageView", reinterpret_cast<uint64_t>(textureImageView));
|
#ifdef LOG_LEVEL_0
|
||||||
vkDestroySampler(vk.getDevice(), textureSampler, nullptr);
|
tLog.log0("cleanup: cleaning up");
|
||||||
vkDestroyImageView(vk.getDevice(), textureImageView, nullptr);
|
#endif
|
||||||
vkDestroyImage(vk.getDevice(), textureImage, nullptr);
|
vk.destroyTextureSampler(textureSampler);
|
||||||
vkFreeMemory(vk.getDevice(), textureImageMemory, nullptr);
|
vk.destroyImageView(textureImageView);
|
||||||
|
vk.destroyImage(textureImage, textureImageMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -51,7 +63,7 @@ void TextureAtlas::createImageResources() {
|
|||||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
textureImage, textureImageMemory);
|
textureImage, textureImageMemory);
|
||||||
VkCommandBuffer cmdBuffer = vk.beginSingleTimeCommands(vk.commandPoolGraphics);
|
VkCommandBuffer cmdBuffer = vk.beginSingleTimeCommands(POOL_GRAPHICS);
|
||||||
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cmdBuffer);
|
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cmdBuffer);
|
||||||
VkImageSubresourceRange subresourceRange{};
|
VkImageSubresourceRange subresourceRange{};
|
||||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
@ -61,7 +73,7 @@ void TextureAtlas::createImageResources() {
|
|||||||
subresourceRange.layerCount = 1;
|
subresourceRange.layerCount = 1;
|
||||||
vkCmdClearColorImage(cmdBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &missingTextureColor, 1, &subresourceRange);
|
vkCmdClearColorImage(cmdBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &missingTextureColor, 1, &subresourceRange);
|
||||||
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &cmdBuffer);
|
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &cmdBuffer);
|
||||||
vk.endSingleTimeCommands(cmdBuffer, vk.commandPoolGraphics, vk.graphicsQ);
|
vk.endSingleTimeCommands(cmdBuffer, POOL_GRAPHICS);
|
||||||
|
|
||||||
vk.createImageView(VK_FORMAT_R8G8B8A8_SRGB, textureImage, textureImageView, VK_IMAGE_ASPECT_COLOR_BIT);
|
vk.createImageView(VK_FORMAT_R8G8B8A8_SRGB, textureImage, textureImageView, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
vk.createTextureSampler(textureSampler);
|
vk.createTextureSampler(textureSampler);
|
||||||
@ -135,7 +147,9 @@ std::pair<glm::vec2, glm::vec2> TextureAtlas::addTexture(uint8_t* pixels, uint16
|
|||||||
freeAreas.insert(std::move(node));
|
freeAreas.insert(std::move(node));
|
||||||
}
|
}
|
||||||
mergeFreeAreas();
|
mergeFreeAreas();
|
||||||
VulkanInstance::vLog("TextureAtlas::addTexture: Adding texture at position x,y=(", x, y, "), with slotCountX,Y=(", slotsX, slotsY, "), with dimensions w,h=(", width, height, ")");
|
#ifdef LOG_LEVEL_0
|
||||||
|
tLog.log0("addTexture: Adding texture at position x,y=(", x, y, "), with slotCountX,Y=(", slotsX, slotsY, "), with dimensions w,h=(", width, height, ")");
|
||||||
|
#endif
|
||||||
blitTextureOnImage(pixels, x, y, width, height);
|
blitTextureOnImage(pixels, x, y, width, height);
|
||||||
// topleft normalized: slot / slotCount
|
// topleft normalized: slot / slotCount
|
||||||
// bottomright normalized: (slot + (textureSize/slotCountize)) / slotCount
|
// bottomright normalized: (slot + (textureSize/slotCountize)) / slotCount
|
||||||
@ -149,14 +163,14 @@ void TextureAtlas::blitTextureOnImage(uint8_t* pixels, uint16_t slotX, uint16_t
|
|||||||
constexpr size_t BYTES_PER_PIXEL = 4;
|
constexpr size_t BYTES_PER_PIXEL = 4;
|
||||||
VkDeviceSize imageSize = textureWidth * textureHeight * BYTES_PER_PIXEL;
|
VkDeviceSize imageSize = textureWidth * textureHeight * BYTES_PER_PIXEL;
|
||||||
VkBuffer stagingBuffer;
|
VkBuffer stagingBuffer;
|
||||||
VkDeviceMemory stagingBufferMemory;
|
MemoryInfo stagingBufferMemory;
|
||||||
vk.createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
vk.createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
stagingBuffer, stagingBufferMemory);
|
stagingBuffer, stagingBufferMemory);
|
||||||
void* data;
|
void* data;
|
||||||
vkMapMemory(vk.getDevice(), stagingBufferMemory, NO_OFFSET, imageSize, NO_FLAGS, &data);
|
vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, imageSize, NO_FLAGS, &data);
|
||||||
memcpy(data, pixels, static_cast<size_t>(imageSize));
|
memcpy(data, pixels, static_cast<size_t>(imageSize));
|
||||||
vkUnmapMemory(vk.getDevice(), stagingBufferMemory);
|
vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory);
|
||||||
|
|
||||||
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
vk.copyBufferToImage(stagingBuffer, textureImage,
|
vk.copyBufferToImage(stagingBuffer, textureImage,
|
||||||
@ -164,14 +178,15 @@ void TextureAtlas::blitTextureOnImage(uint8_t* pixels, uint16_t slotX, uint16_t
|
|||||||
static_cast<uint32_t>(textureWidth), static_cast<uint32_t>(textureHeight)); // dimensions
|
static_cast<uint32_t>(textureWidth), static_cast<uint32_t>(textureHeight)); // dimensions
|
||||||
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
|
||||||
vkDestroyBuffer(vk.getDevice(), stagingBuffer, nullptr);
|
vk.destroyBuffer(stagingBuffer, stagingBufferMemory);
|
||||||
vkFreeMemory(vk.getDevice(), stagingBufferMemory, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TextureAtlas::mergeFreeAreas() {
|
void TextureAtlas::mergeFreeAreas() {
|
||||||
begin:
|
begin:
|
||||||
VulkanInstance::vLog("TextureAtlas::mergeFreeAreas before merge:", freeAreas);
|
#ifdef LOG_LEVEL_0
|
||||||
|
tLog.log0("mergeFreeAreas before merge:", freeAreas);
|
||||||
|
#endif
|
||||||
// surely not the most efficient way, but it should only be run at load time and thus not be too problematic
|
// surely not the most efficient way, but it should only be run at load time and thus not be too problematic
|
||||||
// iterate over the areas for each area
|
// iterate over the areas for each area
|
||||||
for (auto it = freeAreas.begin(); it != freeAreas.end(); it++) {
|
for (auto it = freeAreas.begin(); it != freeAreas.end(); it++) {
|
||||||
@ -195,8 +210,9 @@ begin:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VulkanInstance::vLog("TextureAtlas::mergeFreeAreas after merge:", freeAreas);
|
#ifdef LOG_LEVEL_0
|
||||||
|
tLog.log0("mergeFreeAreas after merge:", freeAreas);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TextureAtlas::toString() const {
|
std::string TextureAtlas::toString() const {
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "vulkan_allocator.hpp"
|
||||||
|
#include <gz-util/log.hpp>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
// only log when trace
|
||||||
|
#ifdef LOG_LEVEL_0
|
||||||
|
#include <gz-util/log.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace gz::vk {
|
namespace gz::vk {
|
||||||
/**
|
/**
|
||||||
@ -34,6 +41,7 @@ namespace gz::vk {
|
|||||||
|
|
||||||
/// Defined in vulkan_instance.hpp
|
/// Defined in vulkan_instance.hpp
|
||||||
class VulkanInstance;
|
class VulkanInstance;
|
||||||
|
|
||||||
class TextureAtlas {
|
class TextureAtlas {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -58,12 +66,14 @@ namespace gz::vk {
|
|||||||
|
|
||||||
std::string toString() const;
|
std::string toString() const;
|
||||||
|
|
||||||
private:
|
|
||||||
VulkanInstance& vk;
|
|
||||||
/**
|
/**
|
||||||
* @brief Destroy all vulkan objects owned by this object
|
* @brief Destroy all vulkan objects owned by this object
|
||||||
|
* @note This function has to be called manually (by TextureManager). This class does not register a cleanupCallback with the instance!
|
||||||
*/
|
*/
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
|
private:
|
||||||
|
VulkanInstance& vk;
|
||||||
void blitTextureOnImage(uint8_t* pixels, uint16_t slotX, uint16_t slotY, uint16_t textureWidth, uint16_t textureHeight);
|
void blitTextureOnImage(uint8_t* pixels, uint16_t slotX, uint16_t slotY, uint16_t textureWidth, uint16_t textureHeight);
|
||||||
/**
|
/**
|
||||||
* @brief Create textureImage, textureImageView and textureSampler
|
* @brief Create textureImage, textureImageView and textureSampler
|
||||||
@ -72,7 +82,7 @@ namespace gz::vk {
|
|||||||
*/
|
*/
|
||||||
void createImageResources();
|
void createImageResources();
|
||||||
VkImage textureImage;
|
VkImage textureImage;
|
||||||
VkDeviceMemory textureImageMemory;
|
MemoryInfo textureImageMemory;
|
||||||
VkImageView textureImageView;
|
VkImageView textureImageView;
|
||||||
VkSampler textureSampler;
|
VkSampler textureSampler;
|
||||||
|
|
||||||
@ -87,5 +97,10 @@ namespace gz::vk {
|
|||||||
uint16_t slotHeight;
|
uint16_t slotHeight;
|
||||||
uint16_t slotCountX;
|
uint16_t slotCountX;
|
||||||
uint16_t slotCountY;
|
uint16_t slotCountY;
|
||||||
|
|
||||||
|
/// Use log only with trace
|
||||||
|
#ifdef LOG_LEVEL_0
|
||||||
|
Log tLog;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
} // namespace gz::vk
|
} // namespace gz::vk
|
||||||
|
@ -9,6 +9,14 @@ namespace gz::vk {
|
|||||||
TextureManager::TextureManager(VulkanInstance& instance)
|
TextureManager::TextureManager(VulkanInstance& instance)
|
||||||
: vk(instance)
|
: vk(instance)
|
||||||
{
|
{
|
||||||
|
LogCreateInfo logCI{};
|
||||||
|
logCI.logfile = "textureManager.log";
|
||||||
|
logCI.storeLog = false;
|
||||||
|
logCI.prefix = "Texture";
|
||||||
|
logCI.prefixColor = Color::GREEN;
|
||||||
|
logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR;
|
||||||
|
tLog = Log(std::move(logCI));
|
||||||
|
|
||||||
vk.registerCleanupCallback(std::bind(&TextureManager::cleanup, this));
|
vk.registerCleanupCallback(std::bind(&TextureManager::cleanup, this));
|
||||||
atlases.insert({ 0, TextureAtlas(vk, 24, 24, 24, 24) });
|
atlases.insert({ 0, TextureAtlas(vk, 24, 24, 24, 24) });
|
||||||
createDescriptorSetLayout();
|
createDescriptorSetLayout();
|
||||||
@ -21,9 +29,14 @@ namespace gz::vk {
|
|||||||
|
|
||||||
|
|
||||||
void TextureManager::cleanup() {
|
void TextureManager::cleanup() {
|
||||||
|
tLog.log0("cleanup: cleaning up");
|
||||||
/* vkFreeDescriptorSets(vk.getDevice(), descriptorPool, 1, &descriptorSet); */
|
/* vkFreeDescriptorSets(vk.getDevice(), descriptorPool, 1, &descriptorSet); */
|
||||||
vkDestroyDescriptorSetLayout(vk.getDevice(), descriptorSetLayout, NO_ALLOC);
|
vkDestroyDescriptorSetLayout(vk.getDevice(), descriptorSetLayout, NO_ALLOC);
|
||||||
vkDestroyDescriptorPool(vk.getDevice(), descriptorPool, NO_ALLOC);
|
vkDestroyDescriptorPool(vk.getDevice(), descriptorPool, NO_ALLOC);
|
||||||
|
for (auto& [i, atlas] : atlases) {
|
||||||
|
atlas.cleanup();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -32,7 +45,7 @@ namespace gz::vk {
|
|||||||
loadTextureFromFile(textureName);
|
loadTextureFromFile(textureName);
|
||||||
}
|
}
|
||||||
TextureInfo& texI = textureInfos[textureName];
|
TextureInfo& texI = textureInfos[textureName];
|
||||||
VulkanInstance::vLog("getTexCoords", texCoords, "textureInfo: topleft", texI.texCoordTopLeft, "botright", texI.texCoordBottomRight);
|
tLog.log0("getTexCoords", texCoords, "textureInfo: topleft", texI.texCoordTopLeft, "botright", texI.texCoordBottomRight);
|
||||||
/* texCoords.x = texI.texCoordTopLeft.x + texCoords.x * (texI.texCoordBottomRight.x - texI.texCoordTopLeft.x); */
|
/* texCoords.x = texI.texCoordTopLeft.x + texCoords.x * (texI.texCoordBottomRight.x - texI.texCoordTopLeft.x); */
|
||||||
/* texCoords.y = texI.texCoordTopLeft.y + texCoords.y * (texI.texCoordBottomRight.y - texI.texCoordTopLeft.y); */
|
/* texCoords.y = texI.texCoordTopLeft.y + texCoords.y * (texI.texCoordBottomRight.y - texI.texCoordTopLeft.y); */
|
||||||
texCoords = texI.texCoordTopLeft + texCoords * (texI.texCoordBottomRight - texI.texCoordTopLeft);
|
texCoords = texI.texCoordTopLeft + texCoords * (texI.texCoordBottomRight - texI.texCoordTopLeft);
|
||||||
@ -49,10 +62,10 @@ namespace gz::vk {
|
|||||||
texI.atlas = 0;
|
texI.atlas = 0;
|
||||||
auto texCoords = atlases.at(0).addTexture(pixels, textureWidth, textureHeight);
|
auto texCoords = atlases.at(0).addTexture(pixels, textureWidth, textureHeight);
|
||||||
stbi_image_free(pixels);
|
stbi_image_free(pixels);
|
||||||
VulkanInstance::vLog("TextureManager::loadTextureFromFile: TexCoords of new image:", texCoords.first, texCoords.second);
|
tLog.log0("TextureManager::loadTextureFromFile: TexCoords of new image:", texCoords.first, texCoords.second);
|
||||||
texI.texCoordTopLeft = std::move(texCoords.first);
|
texI.texCoordTopLeft = std::move(texCoords.first);
|
||||||
texI.texCoordBottomRight = std::move(texCoords.second);
|
texI.texCoordBottomRight = std::move(texCoords.second);
|
||||||
VulkanInstance::vLog("TextureManager::loadTextureFromFile: After loading:", atlases.at(0));
|
tLog.log0("TextureManager::loadTextureFromFile: After loading:", atlases.at(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -84,9 +97,9 @@ void TextureManager::createDescriptorSetLayout() {
|
|||||||
void TextureManager::createDescriptorPool() {
|
void TextureManager::createDescriptorPool() {
|
||||||
std::array<VkDescriptorPoolSize, 1> poolSizes;
|
std::array<VkDescriptorPoolSize, 1> poolSizes;
|
||||||
/* poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; */
|
/* poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; */
|
||||||
/* poolSizes[0].descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT); */
|
/* poolSizes[0].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight()); */
|
||||||
poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
poolSizes[0].descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
|
poolSizes[0].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight());
|
||||||
|
|
||||||
VkDescriptorPoolCreateInfo poolCI{};
|
VkDescriptorPoolCreateInfo poolCI{};
|
||||||
poolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
poolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
@ -102,16 +115,16 @@ void TextureManager::createDescriptorPool() {
|
|||||||
|
|
||||||
|
|
||||||
void TextureManager::createDescriptorSet() {
|
void TextureManager::createDescriptorSet() {
|
||||||
/* std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout); */
|
/* std::vector<VkDescriptorSetLayout> layouts(vk.getMaxFramesInFlight(), descriptorSetLayout); */
|
||||||
VkDescriptorSetAllocateInfo setAI{};
|
VkDescriptorSetAllocateInfo setAI{};
|
||||||
setAI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
setAI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
setAI.descriptorPool = descriptorPool;
|
setAI.descriptorPool = descriptorPool;
|
||||||
/* setAI.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT); */
|
/* setAI.descriptorSetCount = static_cast<uint32_t>(vk.getMaxFramesInFlight()); */
|
||||||
/* setAI.pSetLayouts = layouts.data(); */
|
/* setAI.pSetLayouts = layouts.data(); */
|
||||||
setAI.descriptorSetCount = 1;
|
setAI.descriptorSetCount = 1;
|
||||||
setAI.pSetLayouts = &descriptorSetLayout;
|
setAI.pSetLayouts = &descriptorSetLayout;
|
||||||
|
|
||||||
/* descriptorSets.resize(MAX_FRAMES_IN_FLIGHT); */
|
/* descriptorSets.resize(vk.getMaxFramesInFlight()); */
|
||||||
/* VkResult result = vkAllocateDescriptorSets(vk.getDevice(), &setAI, descriptorSets.data()); */
|
/* VkResult result = vkAllocateDescriptorSets(vk.getDevice(), &setAI, descriptorSets.data()); */
|
||||||
VkResult result = vkAllocateDescriptorSets(vk.getDevice(), &setAI, &descriptorSet);
|
VkResult result = vkAllocateDescriptorSets(vk.getDevice(), &setAI, &descriptorSet);
|
||||||
if (result != VK_SUCCESS) {
|
if (result != VK_SUCCESS) {
|
||||||
|
@ -3,8 +3,11 @@
|
|||||||
#include "texture_atlas.hpp"
|
#include "texture_atlas.hpp"
|
||||||
|
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
#include <gz-util/util/string.hpp>
|
#include <gz-util/util/string.hpp>
|
||||||
|
#include <gz-util/log.hpp>
|
||||||
#include <glm/fwd.hpp>
|
#include <glm/fwd.hpp>
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace gz::vk {
|
namespace gz::vk {
|
||||||
@ -38,6 +41,7 @@ namespace gz::vk {
|
|||||||
std::unordered_map<uint32_t, TextureAtlas> atlases;
|
std::unordered_map<uint32_t, TextureAtlas> atlases;
|
||||||
util::unordered_string_map<TextureInfo> textureInfos;
|
util::unordered_string_map<TextureInfo> textureInfos;
|
||||||
VulkanInstance& vk;
|
VulkanInstance& vk;
|
||||||
|
Log tLog;
|
||||||
/**
|
/**
|
||||||
* @name Create desciptors
|
* @name Create desciptors
|
||||||
* @details These functions create a desciptor with bindings for
|
* @details These functions create a desciptor with bindings for
|
||||||
|
@ -95,6 +95,28 @@ namespace gz::vk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void getBufferMemoryRequirements(const VkDevice& device, const VkBuffer& buffer, VkBufferMemoryRequirementsInfo2& bufMemReq, VkMemoryRequirements2& memReq) {
|
||||||
|
bufMemReq.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2;
|
||||||
|
bufMemReq.pNext = nullptr;
|
||||||
|
bufMemReq.buffer = buffer;
|
||||||
|
|
||||||
|
memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
|
||||||
|
memReq.pNext = nullptr;
|
||||||
|
vkGetBufferMemoryRequirements2(device, &bufMemReq, &memReq);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void getImageMemoryRequirements(const VkDevice& device, const VkImage& image, VkImageMemoryRequirementsInfo2& imMemReq, VkMemoryRequirements2& memReq) {
|
||||||
|
imMemReq.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
|
||||||
|
imMemReq.pNext = nullptr;
|
||||||
|
imMemReq.image = image;
|
||||||
|
|
||||||
|
memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
|
||||||
|
memReq.pNext = nullptr;
|
||||||
|
vkGetImageMemoryRequirements2(device, &imMemReq, &memReq);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -127,6 +127,20 @@ namespace gz::vk {
|
|||||||
* @brief Get a VkDependencyInfo struct for a single image memory barrier
|
* @brief Get a VkDependencyInfo struct for a single image memory barrier
|
||||||
*/
|
*/
|
||||||
VkDependencyInfo getDepInfo(const VkImageMemoryBarrier2& barrier);
|
VkDependencyInfo getDepInfo(const VkImageMemoryBarrier2& barrier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill bufMeqReq and memReq
|
||||||
|
* @details
|
||||||
|
* Fill the structs and call vkGetBufferMemoryRequirements2()
|
||||||
|
*/
|
||||||
|
void getBufferMemoryRequirements(const VkDevice& device, const VkBuffer& buffer, VkBufferMemoryRequirementsInfo2& bufMemReq, VkMemoryRequirements2& memReq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill imMemReq and memReq
|
||||||
|
* @details
|
||||||
|
* Fill the structs and call vkGetImageMemoryRequirements2()
|
||||||
|
*/
|
||||||
|
void getImageMemoryRequirements(const VkDevice& device, const VkImage& image, VkImageMemoryRequirementsInfo2& imMemReq, VkMemoryRequirements2& memReq);
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,29 +4,22 @@
|
|||||||
#include "vulkan_instance.hpp"
|
#include "vulkan_instance.hpp"
|
||||||
|
|
||||||
#include <glm/vector_relational.hpp>
|
#include <glm/vector_relational.hpp>
|
||||||
|
#include <gz-util/util/string_conversion.hpp>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
namespace gz::vk {
|
namespace gz::vk {
|
||||||
struct MemoryBlock {
|
std::string MemoryBlock::toString() const {
|
||||||
size_t size;
|
return std::string("<offset: " + gz::toHexString(offset, 0) + ", size: " + gz::toHexString(size, 0) + ", free: " + gz::toString(free) + ">");
|
||||||
size_t offset;
|
}
|
||||||
bool free;
|
|
||||||
|
|
||||||
|
DeviceMemory::DeviceMemory(VkDeviceSize size_) {
|
||||||
|
size = size_;
|
||||||
|
memory = VK_NULL_HANDLE;
|
||||||
|
blocks.emplace_back(MemoryBlock{size, 0, true});
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DeviceMemory {
|
|
||||||
DeviceMemory() = delete;
|
|
||||||
DeviceMemory(VkDeviceSize size_) {
|
|
||||||
size = size_;
|
|
||||||
memory = VK_NULL_HANDLE;
|
|
||||||
blocks.emplace_back(MemoryBlock{size, 0, true});
|
|
||||||
};
|
|
||||||
|
|
||||||
VkDeviceSize size;
|
|
||||||
VkDeviceMemory memory;
|
|
||||||
std::list<MemoryBlock> blocks;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
VulkanAllocator::VulkanAllocator(VulkanInstance& instance)
|
VulkanAllocator::VulkanAllocator(VulkanInstance& instance)
|
||||||
: vk(instance)
|
: vk(instance)
|
||||||
{
|
{
|
||||||
@ -40,30 +33,46 @@ namespace gz::vk {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanAllocator::allocate(const VkMemoryAllocateInfo& allocI, MemoryInfo& memoryInfo) {
|
void VulkanAllocator::allocate(const VkMemoryAllocateInfo& allocI, const VkMemoryRequirements2& memReq, MemoryInfo& memoryInfo) {
|
||||||
|
aLog.log0("allocate: Requesting memory with ( size", toHexString(allocI.allocationSize),
|
||||||
|
"), ( memoryTypeIndex", allocI.memoryTypeIndex,
|
||||||
|
"), ( alignment", toHexString(memReq.memoryRequirements.alignment), ")");
|
||||||
// go through allocated memories with matching memoryType
|
// go through allocated memories with matching memoryType
|
||||||
for (auto& deviceMemory : memory[allocI.memoryTypeIndex]) {
|
for (auto deviceMemory = memory[allocI.memoryTypeIndex].begin(); deviceMemory != memory[allocI.memoryTypeIndex].end(); deviceMemory++) {
|
||||||
/* auto bestBlockIt = deviceMemory.blocks.end(); */
|
/* auto bestBlockIt = deviceMemory.blocks.end(); */
|
||||||
// go through blocks in memory
|
// go through blocks in memory
|
||||||
for (auto block = deviceMemory.blocks.begin(); block != deviceMemory.blocks.end(); block++) {
|
for (auto block = deviceMemory->blocks.begin(); block != deviceMemory->blocks.end(); block++) {
|
||||||
if (!block->free) { continue; }
|
if (!block->free) { continue; }
|
||||||
if (block->size >= allocI.allocationSize) {
|
if (block->size >= allocI.allocationSize) {
|
||||||
aLog.log0("allocate: memoryTypeIndex:", allocI.memoryTypeIndex,
|
// check if alignment is ok
|
||||||
"size:", allocI.allocationSize, "block size:", block->size, "block offset:", block->offset);
|
if (block->offset % memReq.memoryRequirements.alignment != 0) {
|
||||||
|
// move non-aligned space to previous block
|
||||||
|
// new offset === offset + (align - offset % align)
|
||||||
|
size_t moveToPreviousBlock = memReq.memoryRequirements.alignment - block->offset % memReq.memoryRequirements.alignment;
|
||||||
|
// check if still large enough
|
||||||
|
if (block->size - moveToPreviousBlock < allocI.allocationSize) { continue; }
|
||||||
|
block--;
|
||||||
|
block->size += moveToPreviousBlock;
|
||||||
|
block++;
|
||||||
|
block->offset += moveToPreviousBlock;
|
||||||
|
block->size -= moveToPreviousBlock;
|
||||||
|
}
|
||||||
// if the block is larger than the needed size, split the block
|
// if the block is larger than the needed size, split the block
|
||||||
if (block->size > allocI.allocationSize) {
|
if (block->size > allocI.allocationSize) {
|
||||||
// emplace free part of block after used part of block
|
// emplace free part of block after used part of block
|
||||||
auto newBlock = ++block;
|
auto newBlock = ++block;
|
||||||
block--;
|
block--;
|
||||||
deviceMemory.blocks.emplace(newBlock,
|
deviceMemory->blocks.emplace(newBlock,
|
||||||
MemoryBlock{ block->size - allocI.allocationSize, block->offset + allocI.allocationSize, true });
|
MemoryBlock{ block->size - allocI.allocationSize, block->offset + allocI.allocationSize, true });
|
||||||
block--;
|
/* block--; */
|
||||||
block->size = allocI.allocationSize;
|
block->size = allocI.allocationSize;
|
||||||
}
|
}
|
||||||
block->free = false;
|
block->free = false;
|
||||||
memoryInfo.memory = deviceMemory.memory;
|
memoryInfo.memory = deviceMemory->memory;
|
||||||
memoryInfo.offset = block->offset;
|
memoryInfo.offset = block->offset;
|
||||||
memoryInfo.memoryTypeIndex = allocI.memoryTypeIndex;
|
memoryInfo.memoryTypeIndex = allocI.memoryTypeIndex;
|
||||||
|
|
||||||
|
aLog.log0("allocate: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Blocks:", deviceMemory->blocks);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,7 +84,7 @@ namespace gz::vk {
|
|||||||
allocI_.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
allocI_.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
allocI_.memoryTypeIndex = allocI.memoryTypeIndex;
|
allocI_.memoryTypeIndex = allocI.memoryTypeIndex;
|
||||||
allocI_.allocationSize = memory[allocI.memoryTypeIndex].back().size;
|
allocI_.allocationSize = memory[allocI.memoryTypeIndex].back().size;
|
||||||
aLog.log0("allocate: Allocating new memory of size:", allocI_.allocationSize, " and memoryTypeIndex:", allocI.memoryTypeIndex);
|
aLog.log0("allocate: Allocating new memory of size:", gz::toHexString(allocI_.allocationSize, 0), "(memory", memoryInfo.memoryTypeIndex, "-", gz::toString(memory[memoryInfo.memoryTypeIndex].size()) + ")");
|
||||||
VkResult result = vkAllocateMemory(vk.getDevice(), &allocI_, NO_ALLOC, &memory[allocI.memoryTypeIndex].back().memory);
|
VkResult result = vkAllocateMemory(vk.getDevice(), &allocI_, NO_ALLOC, &memory[allocI.memoryTypeIndex].back().memory);
|
||||||
if (result != VK_SUCCESS) {
|
if (result != VK_SUCCESS) {
|
||||||
throw getVkException(result, "Failed to allocate memory", "VulkanAllocator::allocate");
|
throw getVkException(result, "Failed to allocate memory", "VulkanAllocator::allocate");
|
||||||
@ -87,9 +96,11 @@ namespace gz::vk {
|
|||||||
deviceMemory.blocks.front().size -= allocI.allocationSize;
|
deviceMemory.blocks.front().size -= allocI.allocationSize;
|
||||||
deviceMemory.blocks.emplace_front(MemoryBlock{ allocI.allocationSize, 0, false });
|
deviceMemory.blocks.emplace_front(MemoryBlock{ allocI.allocationSize, 0, false });
|
||||||
|
|
||||||
|
// alignment always satisfied with vkAllocateMemory() and offset 0
|
||||||
memoryInfo.memory = deviceMemory.memory;
|
memoryInfo.memory = deviceMemory.memory;
|
||||||
memoryInfo.offset = 0;
|
memoryInfo.offset = 0;
|
||||||
memoryInfo.memoryTypeIndex = allocI.memoryTypeIndex;
|
memoryInfo.memoryTypeIndex = allocI.memoryTypeIndex;
|
||||||
|
aLog.log0("allocate: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(memory[memoryInfo.memoryTypeIndex].size()) + ") Blocks:", deviceMemory.blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -100,29 +111,35 @@ namespace gz::vk {
|
|||||||
// go through blocks in memory
|
// go through blocks in memory
|
||||||
for (auto block = deviceMemory->blocks.begin(); block != deviceMemory->blocks.end(); block++) {
|
for (auto block = deviceMemory->blocks.begin(); block != deviceMemory->blocks.end(); block++) {
|
||||||
if (block->offset != memoryInfo.offset) { continue; }
|
if (block->offset != memoryInfo.offset) { continue; }
|
||||||
aLog.log0("free: Freeing block at offset", memoryInfo.offset);
|
aLog.log0("free: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Freeing block at offset:", gz::toHexString(memoryInfo.offset, 0));
|
||||||
block->free = true;
|
block->free = true;
|
||||||
// merge with previous block, if free
|
if (block != deviceMemory->blocks.begin()) {
|
||||||
auto otherBlock = block;
|
// merge with previous block, if free
|
||||||
otherBlock--;
|
auto otherBlock = block;
|
||||||
if (otherBlock->free) {
|
otherBlock--;
|
||||||
otherBlock->size += block->size;
|
if (otherBlock->free) {
|
||||||
deviceMemory->blocks.erase(block);
|
otherBlock->size += block->size;
|
||||||
block = otherBlock;
|
deviceMemory->blocks.erase(block);
|
||||||
|
block = otherBlock;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// merge with next block, if free
|
if (block != --(deviceMemory->blocks.end())) {
|
||||||
otherBlock = block;
|
// merge with next block, if free
|
||||||
otherBlock++;
|
auto otherBlock = block;
|
||||||
if (otherBlock->free) {
|
otherBlock++;
|
||||||
block->size += otherBlock->size;
|
if (otherBlock->free) {
|
||||||
deviceMemory->blocks.erase(otherBlock);
|
block->size += otherBlock->size;
|
||||||
|
deviceMemory->blocks.erase(otherBlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memoryInfo.memory = VK_NULL_HANDLE;
|
memoryInfo.memory = VK_NULL_HANDLE;
|
||||||
memoryInfo.offset = 0;
|
memoryInfo.offset = 0;
|
||||||
|
|
||||||
|
aLog.log0("free: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Blocks:", deviceMemory->blocks);
|
||||||
// if now there is only one free block, everything is free -> deallocate memory
|
// if now there is only one free block, everything is free -> deallocate memory
|
||||||
if (deviceMemory->blocks.size() == 1) {
|
if (deviceMemory->blocks.size() == 1) {
|
||||||
aLog.log0("free: Deallocting memory of size:", deviceMemory->size, "and memoryTypeIndex:", memoryInfo.memoryTypeIndex);
|
aLog.log0("free: Deallocating (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") of size:", gz::toHexString(deviceMemory->size, 0));
|
||||||
vkFreeMemory(vk.getDevice(), deviceMemory->memory, NO_ALLOC);
|
vkFreeMemory(vk.getDevice(), deviceMemory->memory, NO_ALLOC);
|
||||||
memory[memoryInfo.memoryTypeIndex].erase(deviceMemory);
|
memory[memoryInfo.memoryTypeIndex].erase(deviceMemory);
|
||||||
}
|
}
|
||||||
@ -133,4 +150,21 @@ namespace gz::vk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VulkanAllocator::cleanup() {
|
||||||
|
aLog.log0("cleanup: cleaning up");
|
||||||
|
for (auto memType = memory.begin(); memType != memory.end(); memType++) {
|
||||||
|
for (auto deviceMemory = memType->second.begin(); deviceMemory != memType->second.end(); deviceMemory++) {
|
||||||
|
// check if all blocks are free
|
||||||
|
for (auto block = deviceMemory->blocks.begin(); block != deviceMemory->blocks.end(); block++) {
|
||||||
|
if (block->free) { continue; }
|
||||||
|
aLog.warning("cleanup: (memory", memType->first, "-", gz::toString(deviceMemory - memType->second.begin()) + ") Block not freed: ", *block);
|
||||||
|
}
|
||||||
|
aLog.log0("free: Deallocating (memory", memType->first, "-", gz::toString(deviceMemory - memType->second.begin()) + ") of size:", gz::toHexString(deviceMemory->size, 0));
|
||||||
|
vkFreeMemory(vk.getDevice(), deviceMemory->memory, NO_ALLOC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memory.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace gz::vk
|
} // namespace gz::vk
|
||||||
|
@ -13,20 +13,99 @@
|
|||||||
/* #include <vulkan/vulkan_core.h> */
|
/* #include <vulkan/vulkan_core.h> */
|
||||||
|
|
||||||
namespace gz::vk {
|
namespace gz::vk {
|
||||||
|
/**
|
||||||
|
* @brief Contains information about a subsection (block) of a VkDeviceMemory
|
||||||
|
*/
|
||||||
struct MemoryInfo {
|
struct MemoryInfo {
|
||||||
|
/**
|
||||||
|
* @brief Handle of the memory
|
||||||
|
*/
|
||||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||||
|
/**
|
||||||
|
* @brief Offset into memory
|
||||||
|
*/
|
||||||
VkDeviceSize offset = 0;
|
VkDeviceSize offset = 0;
|
||||||
|
/**
|
||||||
|
* @brief The memoryTypeIndex memory was allocated from. Needed for VulkanAllocator::free()
|
||||||
|
*/
|
||||||
uint32_t memoryTypeIndex = 0;
|
uint32_t memoryTypeIndex = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Information on a single block of memory
|
||||||
|
*/
|
||||||
|
struct MemoryBlock {
|
||||||
|
size_t size;
|
||||||
|
size_t offset;
|
||||||
|
bool free;
|
||||||
|
std::string toString() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Manage a single VkDeviceMemory chunk
|
||||||
|
*/
|
||||||
|
struct DeviceMemory {
|
||||||
|
DeviceMemory() = delete;
|
||||||
|
DeviceMemory(VkDeviceSize size_);
|
||||||
|
|
||||||
|
VkDeviceSize size;
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
std::list<MemoryBlock> blocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// if no memory is available, allocate a chunk of multiplier * requested size
|
// if no memory is available, allocate a chunk of multiplier * requested size
|
||||||
constexpr VkDeviceSize TODO_ALLOCATION_SIZE_MULTIPLIIER = 10;
|
constexpr VkDeviceSize TODO_ALLOCATION_SIZE_MULTIPLIIER = 10;
|
||||||
|
|
||||||
|
|
||||||
// defined in vulkan_instance.hpp
|
// defined in vulkan_instance.hpp
|
||||||
class VulkanInstance;
|
class VulkanInstance;
|
||||||
// defined in vulkan_allocator.cpp
|
|
||||||
struct DeviceMemory;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocator for device local memory
|
||||||
|
* @details
|
||||||
|
* Allocates larger chunks of VkDeviceMemory from which blocks can be @ref allocate() "allocated".
|
||||||
|
*
|
||||||
|
* This class is for device local memory only, not for host memory.
|
||||||
|
* You can not use it for vulkan memory allocation callbacks (pAllocator).
|
||||||
|
*
|
||||||
|
* @subsection usage How to use
|
||||||
|
* The usage is explained with the example of creating and destroying a single buffer.
|
||||||
|
* @code
|
||||||
|
* // Create buffer handle
|
||||||
|
* VkBuffer buffer;
|
||||||
|
* // Create empty memory info struct
|
||||||
|
* MemoryInfo bufferMI;
|
||||||
|
*
|
||||||
|
* VkBufferCreateInfo bufferCI{}
|
||||||
|
* ...
|
||||||
|
* vkCreateBuffer(...);
|
||||||
|
*
|
||||||
|
* // get memory requirements
|
||||||
|
* VkMemoryRequirements2 memReq;
|
||||||
|
* VkBufferMemoryRequirementsInfo2 bufMemReq;
|
||||||
|
* // from vulkan_util.hpp, same exists for imageMemoryRequirements
|
||||||
|
* getBufferMemoryRequirements(device, buffer, bufMemReq, memReq);
|
||||||
|
*
|
||||||
|
* // set allocation info
|
||||||
|
* VkMemoryAllocateInfo memAI{};
|
||||||
|
* ...
|
||||||
|
* memAI.memoryTypeIndex = VulkanInstance::findMemoryType(memReq.memoryRequirements.memoryTypeBits, wantedProperties);
|
||||||
|
*
|
||||||
|
* // allocate memory for the buffer
|
||||||
|
* VulkanAllocator::allocate(memAI, memReq, bufferMI);
|
||||||
|
*
|
||||||
|
* // bind the buffer to the memory
|
||||||
|
* vkBindBufferMemory(device, buffer, bufferMI.memory, bufferMI.offset);
|
||||||
|
*
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* vkDestroyBuffer(device, buffer);
|
||||||
|
* VulkanAllocator::free(bufferMemoryInfo);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* You will of course have to use a VulkanAllocator and VulkanInstance object, since the used methods are not static.
|
||||||
|
*/
|
||||||
class VulkanAllocator {
|
class VulkanAllocator {
|
||||||
public:
|
public:
|
||||||
VulkanAllocator(VulkanInstance& instance);
|
VulkanAllocator(VulkanInstance& instance);
|
||||||
@ -39,8 +118,10 @@ namespace gz::vk {
|
|||||||
* You can then bind something of size allocI.allocationSize to memoryInfo.memory at offset memoryInfo.offset.
|
* You can then bind something of size allocI.allocationSize to memoryInfo.memory at offset memoryInfo.offset.
|
||||||
* @throws VkException when a call to vkAllocateMemory is needed and fails
|
* @throws VkException when a call to vkAllocateMemory is needed and fails
|
||||||
* @todo Determine the size of new allocations
|
* @todo Determine the size of new allocations
|
||||||
|
* @todo alignment, maybe use VkMemoryRequirements instead of VkMemoryAllocateInfo?
|
||||||
|
* @todo maybe increase the block size of the allocated block so that the following blocks is already 16-aligned?
|
||||||
*/
|
*/
|
||||||
void allocate(const VkMemoryAllocateInfo& allocI, MemoryInfo& memoryInfo);
|
void allocate(const VkMemoryAllocateInfo& allocI, const VkMemoryRequirements2& memReq, MemoryInfo& memoryInfo);
|
||||||
/**
|
/**
|
||||||
* @brief Free a block allocated with allocate()
|
* @brief Free a block allocated with allocate()
|
||||||
*
|
*
|
||||||
@ -48,10 +129,21 @@ namespace gz::vk {
|
|||||||
* @throws VkUserError if memoryInfo was not allocated from this allocator
|
* @throws VkUserError if memoryInfo was not allocated from this allocator
|
||||||
*/
|
*/
|
||||||
void free(MemoryInfo& memoryInfo);
|
void free(MemoryInfo& memoryInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deallocate all memory
|
||||||
|
* @details
|
||||||
|
* Prints warnings if blocks have not been freed.
|
||||||
|
*
|
||||||
|
* @note This function has to be called manually (by VulkanInstance). This class does not register a cleanupCallback with the instance!
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void cleanup();
|
||||||
private:
|
private:
|
||||||
/// allocated memory for memoryIndexType
|
/// Allocated memory for memoryIndexType
|
||||||
std::map<uint32_t, std::vector<DeviceMemory>> memory;
|
std::map<uint32_t, std::vector<DeviceMemory>> memory;
|
||||||
Log aLog;
|
Log aLog;
|
||||||
|
/// Needed for access to logical device
|
||||||
VulkanInstance& vk;
|
VulkanInstance& vk;
|
||||||
|
|
||||||
}; // class VulkanAllocator
|
}; // class VulkanAllocator
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "vk_enum_string.h"
|
#include "vk_enum_string.h"
|
||||||
#include "vulkan_allocator.hpp"
|
#include "vulkan_allocator.hpp"
|
||||||
|
#include "vulkan_util.hpp"
|
||||||
#include <bits/types/cookie_io_functions_t.h>
|
#include <bits/types/cookie_io_functions_t.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <glm/vector_relational.hpp>
|
#include <glm/vector_relational.hpp>
|
||||||
@ -248,6 +249,8 @@ using std::uint32_t;
|
|||||||
vkDestroyCommandPool(device, commandPoolGraphics, nullptr);
|
vkDestroyCommandPool(device, commandPoolGraphics, nullptr);
|
||||||
vkDestroyCommandPool(device, commandPoolTransfer, nullptr);
|
vkDestroyCommandPool(device, commandPoolTransfer, nullptr);
|
||||||
|
|
||||||
|
allocator.cleanup();
|
||||||
|
|
||||||
vkDestroyDevice(device, nullptr);
|
vkDestroyDevice(device, nullptr);
|
||||||
vkDestroySurfaceKHR(instance, surface, nullptr);
|
vkDestroySurfaceKHR(instance, surface, nullptr);
|
||||||
cleanupDebugMessenger();
|
cleanupDebugMessenger();
|
||||||
@ -465,6 +468,43 @@ using std::uint32_t;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VulkanInstance::loadModel(VerticesAndIndices<uint32_t>& model) {
|
||||||
|
tinyobj::attrib_t attrib;
|
||||||
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
|
std::vector<tinyobj::material_t> materials;
|
||||||
|
std::string warnings, errors;
|
||||||
|
if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warnings, &errors, MODEL_PATH.c_str())) {
|
||||||
|
vLog.warning("Warning from tinyobj::LoadObj: ", warnings);
|
||||||
|
throw gz::Exception("Error loading obj: " + errors, "loadModel");
|
||||||
|
}
|
||||||
|
if (!warnings.empty()) {
|
||||||
|
vLog.warning("Warning from tinyobj::LoadObj: ", warnings);
|
||||||
|
}
|
||||||
|
std::unordered_map<Vertex3D, uint32_t> uniqueVertices;
|
||||||
|
for (const auto& shape : shapes) {
|
||||||
|
for (const auto& index : shape.mesh.indices) {
|
||||||
|
Vertex3D vertex;
|
||||||
|
vertex.pos = {
|
||||||
|
attrib.vertices[3 * index.vertex_index + 0],
|
||||||
|
attrib.vertices[3 * index.vertex_index + 1],
|
||||||
|
attrib.vertices[3 * index.vertex_index + 2]
|
||||||
|
};
|
||||||
|
vertex.texCoord = {
|
||||||
|
attrib.vertices[2 * index.texcoord_index + 0],
|
||||||
|
// obj: y = 0 means bottom, vulkan: y = 0 means top
|
||||||
|
1.0f - attrib.vertices[2 * index.texcoord_index + 1],
|
||||||
|
};
|
||||||
|
vertex.color = { 1.0f, 1.0f, 1.0f };
|
||||||
|
if (!uniqueVertices.contains(vertex)) {
|
||||||
|
uniqueVertices.insert({ vertex, model.vertices.size() });
|
||||||
|
model.vertices.push_back(vertex);
|
||||||
|
}
|
||||||
|
/* model.vertices.push_back(vertex); */
|
||||||
|
model.indices.push_back(uniqueVertices[vertex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// DEPTH
|
// DEPTH
|
||||||
/* VkFormat VulkanInstance::findDepthFormat() { */
|
/* VkFormat VulkanInstance::findDepthFormat() { */
|
||||||
@ -702,7 +742,7 @@ using std::uint32_t;
|
|||||||
|
|
||||||
|
|
||||||
// BUFFER
|
// BUFFER
|
||||||
void VulkanInstance::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, MemoryInfo& memI, VkSharingMode sharingMode, std::vector<uint32_t>* qFamiliesWithAccess) {
|
void VulkanInstance::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, MemoryInfo& bufferMI, VkSharingMode sharingMode, std::vector<uint32_t>* qFamiliesWithAccess) {
|
||||||
VkBufferCreateInfo bufferCI{};
|
VkBufferCreateInfo bufferCI{};
|
||||||
bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
bufferCI.size = size;
|
bufferCI.size = size;
|
||||||
@ -722,18 +762,23 @@ using std::uint32_t;
|
|||||||
throw getVkException(result, "Failed to create buffer", "createBuffer");
|
throw getVkException(result, "Failed to create buffer", "createBuffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
VkMemoryRequirements memoryRequirements{};
|
VkMemoryRequirements2 memReq;
|
||||||
vkGetBufferMemoryRequirements(device, buffer, &memoryRequirements);
|
VkBufferMemoryRequirementsInfo2 bufMemReq;
|
||||||
|
getBufferMemoryRequirements(device, buffer, bufMemReq, memReq);
|
||||||
|
|
||||||
VkMemoryAllocateInfo memoryAI{};
|
VkMemoryAllocateInfo memoryAI{};
|
||||||
memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
memoryAI.allocationSize = memoryRequirements.size;
|
memoryAI.allocationSize = memReq.memoryRequirements.size;
|
||||||
VkMemoryPropertyFlags wantedProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
VkMemoryPropertyFlags wantedProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||||
memoryAI.memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, wantedProperties);
|
memoryAI.memoryTypeIndex = findMemoryType(memReq.memoryRequirements.memoryTypeBits, wantedProperties);
|
||||||
|
|
||||||
allocator.allocate(memoryAI, memI);
|
allocator.allocate(memoryAI, memReq, bufferMI);
|
||||||
|
|
||||||
vkBindBufferMemory(device, buffer, memI.memory, memI.offset);
|
result = vkBindBufferMemory(device, buffer, bufferMI.memory, bufferMI.offset);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
throw getVkException(result, "Failed to bind buffer to its memory", "createBuffer");
|
||||||
|
}
|
||||||
|
vLog.log0("createBuffer: created and bound buffer of size", memoryAI.allocationSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -843,8 +888,15 @@ using std::uint32_t;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VulkanInstance::destroyTextureSampler(VkSampler& sampler) {
|
||||||
|
vkDestroySampler(device, sampler, NO_ALLOC);
|
||||||
|
sampler = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// PUBLIC INTERFACE: IMAGE UTILITY
|
// PUBLIC INTERFACE: IMAGE UTILITY
|
||||||
void VulkanInstance::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkImage& image, VkDeviceMemory& imageMemory) {
|
void VulkanInstance::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkImage& image, MemoryInfo& imageMI) {
|
||||||
VkImageCreateInfo imageCI{};
|
VkImageCreateInfo imageCI{};
|
||||||
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
||||||
@ -866,25 +918,32 @@ using std::uint32_t;
|
|||||||
throw getVkException(result, "Failed to create image", "createImage");
|
throw getVkException(result, "Failed to create image", "createImage");
|
||||||
}
|
}
|
||||||
|
|
||||||
VkMemoryRequirements memoryRequirements;
|
VkMemoryRequirements2 memReq;
|
||||||
vkGetImageMemoryRequirements(device, image, &memoryRequirements);
|
VkImageMemoryRequirementsInfo2 imMemReq;
|
||||||
|
getImageMemoryRequirements(device, image, imMemReq, memReq);
|
||||||
|
|
||||||
VkMemoryAllocateInfo memoryAI{};
|
VkMemoryAllocateInfo memoryAI{};
|
||||||
memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
memoryAI.allocationSize = memoryRequirements.size;
|
memoryAI.allocationSize = memReq.memoryRequirements.size;
|
||||||
memoryAI.memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, memoryProperties);
|
memoryAI.memoryTypeIndex = findMemoryType(memReq.memoryRequirements.memoryTypeBits, memoryProperties);
|
||||||
|
|
||||||
MemoryInfo memI;
|
allocator.allocate(memoryAI, memReq, imageMI);
|
||||||
allocator.allocate(memoryAI, memI);
|
|
||||||
/* result = vkAllocateMemory(device, &memoryAI, NO_ALLOC, &imageMemory); */
|
|
||||||
|
|
||||||
result = vkBindImageMemory(device, image, memI.memory, memI.offset);
|
result = vkBindImageMemory(device, image, imageMI.memory, imageMI.offset);
|
||||||
if (result != VK_SUCCESS) {
|
if (result != VK_SUCCESS) {
|
||||||
throw getVkException(result, "Failed to create image", "createImage");
|
throw getVkException(result, "Failed to bind image to its memory", "createImage");
|
||||||
}
|
}
|
||||||
|
vLog.log0("createImage: created and bound image of size", memoryAI.allocationSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VulkanInstance::destroyImage(VkImage& image, MemoryInfo& imageMemory) {
|
||||||
|
vkDestroyImage(device, image, NO_ALLOC);
|
||||||
|
allocator.free(imageMemory);
|
||||||
|
image = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// IMAGE VIEW
|
// IMAGE VIEW
|
||||||
void VulkanInstance::createImageView(VkFormat format, VkImage& image, VkImageView& imageView, VkImageAspectFlags aspectFlags) {
|
void VulkanInstance::createImageView(VkFormat format, VkImage& image, VkImageView& imageView, VkImageAspectFlags aspectFlags) {
|
||||||
VkImageViewCreateInfo imageViewCI{};
|
VkImageViewCreateInfo imageViewCI{};
|
||||||
@ -908,6 +967,12 @@ using std::uint32_t;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VulkanInstance::destroyImageView(VkImageView& imageView) {
|
||||||
|
vkDestroyImageView(device, imageView, NO_ALLOC);
|
||||||
|
imageView = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void VulkanInstance::copyBufferToImage(VkBuffer buffer, VkImage image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height) {
|
void VulkanInstance::copyBufferToImage(VkBuffer buffer, VkImage image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height) {
|
||||||
VkCommandBuffer cmdBuffer = beginSingleTimeCommands(POOL_TRANSFER);
|
VkCommandBuffer cmdBuffer = beginSingleTimeCommands(POOL_TRANSFER);
|
||||||
VkBufferImageCopy region{};
|
VkBufferImageCopy region{};
|
||||||
@ -1724,45 +1789,6 @@ using std::uint32_t;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MODEL
|
|
||||||
void VulkanInstance::loadModel(VerticesAndIndices<uint32_t>& model) {
|
|
||||||
tinyobj::attrib_t attrib;
|
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
|
||||||
std::vector<tinyobj::material_t> materials;
|
|
||||||
std::string warnings, errors;
|
|
||||||
if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warnings, &errors, MODEL_PATH.c_str())) {
|
|
||||||
vLog.warning("Warning from tinyobj::LoadObj: ", warnings);
|
|
||||||
throw gz::Exception("Error loading obj: " + errors, "loadModel");
|
|
||||||
}
|
|
||||||
if (!warnings.empty()) {
|
|
||||||
vLog.warning("Warning from tinyobj::LoadObj: ", warnings);
|
|
||||||
}
|
|
||||||
std::unordered_map<Vertex3D, uint32_t> uniqueVertices;
|
|
||||||
for (const auto& shape : shapes) {
|
|
||||||
for (const auto& index : shape.mesh.indices) {
|
|
||||||
Vertex3D vertex;
|
|
||||||
vertex.pos = {
|
|
||||||
attrib.vertices[3 * index.vertex_index + 0],
|
|
||||||
attrib.vertices[3 * index.vertex_index + 1],
|
|
||||||
attrib.vertices[3 * index.vertex_index + 2]
|
|
||||||
};
|
|
||||||
vertex.texCoord = {
|
|
||||||
attrib.vertices[2 * index.texcoord_index + 0],
|
|
||||||
// obj: y = 0 means bottom, vulkan: y = 0 means top
|
|
||||||
1.0f - attrib.vertices[2 * index.texcoord_index + 1],
|
|
||||||
};
|
|
||||||
vertex.color = { 1.0f, 1.0f, 1.0f };
|
|
||||||
if (!uniqueVertices.contains(vertex)) {
|
|
||||||
uniqueVertices.insert({ vertex, model.vertices.size() });
|
|
||||||
model.vertices.push_back(vertex);
|
|
||||||
}
|
|
||||||
/* model.vertices.push_back(vertex); */
|
|
||||||
model.indices.push_back(uniqueVertices[vertex]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
void VulkanInstance::setupDebugMessenger() {
|
void VulkanInstance::setupDebugMessenger() {
|
||||||
// get the address of the vkCreateDebugUtilsMessengerEXT function
|
// get the address of the vkCreateDebugUtilsMessengerEXT function
|
||||||
|
@ -97,8 +97,25 @@ namespace gz::vk {
|
|||||||
*/
|
*/
|
||||||
uint32_t beginFrameDraw();
|
uint32_t beginFrameDraw();
|
||||||
void endFrameDraw(uint32_t imageIndex);
|
void endFrameDraw(uint32_t imageIndex);
|
||||||
|
/**
|
||||||
|
* @brief Cleanup the instance
|
||||||
|
* @details
|
||||||
|
* -# wait for the device to idle
|
||||||
|
* -# call @ref registerCleanupCallback() "cleanup callbacks" in reverse order to the registration
|
||||||
|
* -# destroy command buffers
|
||||||
|
* -# call cleanupSwapChain()
|
||||||
|
* -# destroy @ref createSyncObjects() "synchronization objects"
|
||||||
|
* -# destroy @ref createCommandPools() "command pools"
|
||||||
|
* -# call VulkanAllocator::cleanup()
|
||||||
|
* -# destroy device
|
||||||
|
* -# destroy surface
|
||||||
|
* -# call cleanupDebugMessenger()
|
||||||
|
* -# destroy instance
|
||||||
|
* -# call glfwDestroyWindow()
|
||||||
|
* -# call glfwTerminate()
|
||||||
|
*/
|
||||||
void cleanup();
|
void cleanup();
|
||||||
const GLFWwindow* getWindow() const { return window; }
|
GLFWwindow* getWindow() { return window; }
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,21 +159,22 @@ namespace gz::vk {
|
|||||||
public:
|
public:
|
||||||
/// @{
|
/// @{
|
||||||
const VkDevice& getDevice() const { return device; }
|
const VkDevice& getDevice() const { return device; }
|
||||||
const SettingsManager<SettingsTypes>& getSettings() const { return settings; }
|
|
||||||
const VkExtent2D& getScExtent() const { return scExtent; }
|
const VkExtent2D& getScExtent() const { return scExtent; }
|
||||||
const std::vector<VkImage>& getScImages() const { return scImages; }
|
const std::vector<VkImage>& getScImages() const { return scImages; }
|
||||||
const VkFormat& getScImageFormat() const { return scImageFormat; }
|
const VkFormat& getScImageFormat() const { return scImageFormat; }
|
||||||
|
|
||||||
|
SettingsManager<SettingsTypes>& getSettings() { return settings; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the maximum number of frames in flight
|
* @brief Get the maximum number of frames in flight
|
||||||
* @see MAX_FRAMES_IN_FLIGHT
|
* @see MAX_FRAMES_IN_FLIGHT
|
||||||
*/
|
*/
|
||||||
const uint32_t getMaxFramesInFlight() const { return MAX_FRAMES_IN_FLIGHT; }
|
uint32_t getMaxFramesInFlight() const { return MAX_FRAMES_IN_FLIGHT; }
|
||||||
/**
|
/**
|
||||||
* @brief Get the frame that is currently in flight
|
* @brief Get the frame that is currently in flight
|
||||||
* @see currentFrame
|
* @see currentFrame
|
||||||
*/
|
*/
|
||||||
const uint32_t getCurrentFrame() const { return currentFrame; }
|
uint32_t getCurrentFrame() const { return currentFrame; }
|
||||||
|
|
||||||
void submitThisFrame(VkCommandBuffer& cmdBuffer);
|
void submitThisFrame(VkCommandBuffer& cmdBuffer);
|
||||||
|
|
||||||
@ -178,6 +196,8 @@ namespace gz::vk {
|
|||||||
* @param commandPool: The same pool as passed to beginSingleTimeCommands()
|
* @param commandPool: The same pool as passed to beginSingleTimeCommands()
|
||||||
*/
|
*/
|
||||||
void endSingleTimeCommands(VkCommandBuffer cmdBuffer, InstanceCommandPool commandPool);
|
void endSingleTimeCommands(VkCommandBuffer cmdBuffer, InstanceCommandPool commandPool);
|
||||||
|
|
||||||
|
void loadModel(VerticesAndIndices<uint32_t>& model);
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -234,6 +254,9 @@ namespace gz::vk {
|
|||||||
* @param buffer The (null) handle to the buffer
|
* @param buffer The (null) handle to the buffer
|
||||||
* @param bufferMemory Reference to an (uninitialized) MemoryInfo struct. It will be valid when the function returns
|
* @param bufferMemory Reference to an (uninitialized) MemoryInfo struct. It will be valid when the function returns
|
||||||
* @param properties Properties that the buffers memory needs to satisfy
|
* @param properties Properties that the buffers memory needs to satisfy
|
||||||
|
* @details
|
||||||
|
* The memory the buffer will be bound to is HOST_VISIBLE and HOST_COHERENT
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, MemoryInfo& bufferMemory, VkSharingMode sharingMode=VK_SHARING_MODE_EXCLUSIVE, std::vector<uint32_t>* qFamiliesWithAccess=nullptr);
|
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, MemoryInfo& bufferMemory, VkSharingMode sharingMode=VK_SHARING_MODE_EXCLUSIVE, std::vector<uint32_t>* qFamiliesWithAccess=nullptr);
|
||||||
/**
|
/**
|
||||||
@ -284,6 +307,8 @@ namespace gz::vk {
|
|||||||
*/
|
*/
|
||||||
void createTextureSampler(VkSampler& sampler);
|
void createTextureSampler(VkSampler& sampler);
|
||||||
|
|
||||||
|
void destroyTextureSampler(VkSampler& sampler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Public Interface: Image utility
|
* @name Public Interface: Image utility
|
||||||
* @details
|
* @details
|
||||||
@ -292,13 +317,16 @@ namespace gz::vk {
|
|||||||
*/
|
*/
|
||||||
/// @{
|
/// @{
|
||||||
/**
|
/**
|
||||||
* @brief Create the image, allocate the imageMemory and bind the image to it
|
* @brief Create a 2D image, allocate the imageMemory and bind the image to it
|
||||||
*/
|
*/
|
||||||
void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkImage& image, VkDeviceMemory& imageMemory);
|
void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkImage& image, MemoryInfo& imageMI);
|
||||||
|
void destroyImage(VkImage& image, MemoryInfo& imageMemory);
|
||||||
/**
|
/**
|
||||||
* @brief Create a 2D imageView with format for image.
|
* @brief Create a 2D imageView with format for image.
|
||||||
*/
|
*/
|
||||||
void createImageView(VkFormat format, VkImage& image, VkImageView& imageView, VkImageAspectFlags aspectFlags);
|
void createImageView(VkFormat format, VkImage& image, VkImageView& imageView, VkImageAspectFlags aspectFlags);
|
||||||
|
void destroyImageView(VkImageView& imageView);
|
||||||
|
|
||||||
void copyBufferToImage(VkBuffer buffer, VkImage image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height);
|
void copyBufferToImage(VkBuffer buffer, VkImage image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height);
|
||||||
/**
|
/**
|
||||||
* @todo make a version using vkCmdResolveImage for multisampled images
|
* @todo make a version using vkCmdResolveImage for multisampled images
|
||||||
@ -601,14 +629,6 @@ namespace gz::vk {
|
|||||||
static std::vector<char> readFile(const std::string& filename);
|
static std::vector<char> readFile(const std::string& filename);
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/**
|
|
||||||
* @name Models
|
|
||||||
*/
|
|
||||||
/// @{
|
|
||||||
void loadModel(VerticesAndIndices<uint32_t>& model);
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Utility
|
* @name Utility
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Written by writeKeyValueFile
|
# Written by writeKeyValueFile
|
||||||
|
max_frames_in_flight = 3
|
||||||
max_anisotropy = 1
|
max_anisotropy = 1
|
||||||
anisotropy_enable = false
|
anisotropy_enable = false
|
||||||
framerate = 60
|
framerate = 60
|
||||||
|
Loading…
Reference in New Issue
Block a user