From 2808defc948a1f61c02a29b43802fbaac90beddc Mon Sep 17 00:00:00 2001 From: Ben Kyd Date: Sat, 30 Dec 2023 15:54:46 +0000 Subject: [PATCH] fixed rookie memory leak in rendertarget_recreate --- CMakeLists.txt | 2 +- libhart/thirdparty/yolo/yolo.hpp | 3 + src/graphics/device.hpp | 2 +- src/graphics/rendertarget.cpp | 97 ++++++++++++++++++++++++++++++-- src/graphics/vkrenderer.cpp | 8 +++ src/inferno.cpp | 1 - src/preview/renderer.cpp | 3 + src/raytracing/renderer.cpp | 5 +- 8 files changed, 109 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59ca3f5..2d54f8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ else() target_compile_options(inferno PRIVATE -std=c++20) target_compile_options(inferno PRIVATE -m64) if (CMAKE_BUILD_TYPE MATCHES "Debug") - target_compile_options(inferno PRIVATE -O1) + target_compile_options(inferno PRIVATE -O0) target_compile_options(inferno PRIVATE -Wall) target_compile_options(inferno PRIVATE -g) target_compile_options(inferno PRIVATE -D_GLIBCXX_DEBUG) diff --git a/libhart/thirdparty/yolo/yolo.hpp b/libhart/thirdparty/yolo/yolo.hpp index 8c9a728..35fdcc8 100644 --- a/libhart/thirdparty/yolo/yolo.hpp +++ b/libhart/thirdparty/yolo/yolo.hpp @@ -117,3 +117,6 @@ inline uint8_t registerModule(std::string name, std::string ANSI) } +// alias yolo to yo for less typing +namespace yo = yolo; + diff --git a/src/graphics/device.hpp b/src/graphics/device.hpp index 26901ea..cf47af1 100644 --- a/src/graphics/device.hpp +++ b/src/graphics/device.hpp @@ -6,7 +6,7 @@ namespace inferno::graphics { -// #define VALIDATION_LAYERS_ENABLED 1 +#define VALIDATION_LAYERS_ENABLED 1 #ifdef VALIDATION_LAYERS_ENABLED const std::vector VALIDATION_LAYERS = { "VK_LAYER_KHRONOS_validation", diff --git a/src/graphics/rendertarget.cpp b/src/graphics/rendertarget.cpp index 6a491b4..379f0f0 100644 --- a/src/graphics/rendertarget.cpp +++ b/src/graphics/rendertarget.cpp @@ -4,6 +4,7 @@ #include "device.hpp" #include "graphics.hpp" #include "image.hpp" +#include "vkrenderer.hpp" #include "yolo/yolo.hpp" #include @@ -44,7 +45,8 @@ RenderTarget* rendertarget_create( target->TargetImage = new ImageAttachment(); create_image(device, extent.width, extent.height, format, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, target->TargetImage->Image, target->TargetImage->Memory); @@ -54,6 +56,13 @@ RenderTarget* rendertarget_create( target->DescriptorSet = ImGui_ImplVulkan_AddTexture(target->Sampler, target->TargetImage->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + // wait for the image to be ready + graphics::renderer_submit_now( + device->RenderContext, [&](VulkanRenderer* re, VkCommandBuffer* cmd) { + transition_image_layout(re->Device, target->TargetImage->Image, format, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + }); + if (depth) { rendertarget_create_depth(target); } @@ -105,15 +114,70 @@ void rendertarget_recreate(RenderTarget* target, VkExtent2D extent, VkFormat for bool doDepth = target->TargetDepth != nullptr; - rendertarget_cleanup(target); + vkDestroyImageView( + target->Device->VulkanDevice, target->TargetImage->ImageView, nullptr); + vkDestroyImage(target->Device->VulkanDevice, target->TargetImage->Image, nullptr); + vkFreeMemory(target->Device->VulkanDevice, target->TargetImage->Memory, nullptr); + + if (doDepth) { + vkDestroyImageView( + target->Device->VulkanDevice, target->TargetDepth->ImageView, nullptr); + vkDestroyImage(target->Device->VulkanDevice, target->TargetDepth->Image, nullptr); + vkFreeMemory(target->Device->VulkanDevice, target->TargetDepth->Memory, nullptr); + } target->Extent = extent; target->Format = format; - rendertarget_create(target->Device, extent, format, doDepth); + VkSamplerCreateInfo samplerInfo {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.anisotropyEnable = VK_FALSE; + samplerInfo.maxAnisotropy = 1.0f; + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipLodBias = 0.0f; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 0.0f; - // if (doDepth) - // rendertarget_create_depth(target); + if (vkCreateSampler( + target->Device->VulkanDevice, &samplerInfo, nullptr, &target->Sampler) + != VK_SUCCESS) { + yolo::error("failed to create texture sampler!"); + } + + target->TargetImage = new ImageAttachment(); + + create_image(target->Device, extent.width, extent.height, format, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, target->TargetImage->Image, + target->TargetImage->Memory); + + target->TargetImage->ImageView = create_image_view( + target->Device, target->TargetImage->Image, format, VK_IMAGE_ASPECT_COLOR_BIT); + + target->DescriptorSet = ImGui_ImplVulkan_AddTexture(target->Sampler, + target->TargetImage->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + // wait for the image to be ready + graphics::renderer_submit_now( + target->Device->RenderContext, [&](VulkanRenderer* re, VkCommandBuffer* cmd) { + transition_image_layout(re->Device, target->TargetImage->Image, format, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + }); + + if (doDepth) { + rendertarget_create_depth(target); + } } DynamicCPUTarget* dynamic_rendertarget_create( @@ -149,7 +213,8 @@ DynamicCPUTarget* dynamic_rendertarget_create( // Create VkImage with Undefined create_image(device, extent.width, extent.height, format, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, target->Image, target->Memory); target->ImageView @@ -191,6 +256,26 @@ void dynamic_rendertarget_update(DynamicCPUTarget* target, void* data, VkExtent2 memcpy(mappedData, data, target->StagingBuffer->Size); vkUnmapMemory(target->Device->VulkanDevice, target->StagingBuffer->DeviceData); + // No we have the data in the buffer, let's move it to the image + graphics::renderer_submit_now( + target->Device->RenderContext, [&](VulkanRenderer* re, VkCommandBuffer* cmd) { + VkBufferImageCopy region {}; + region.bufferOffset = 0; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + + region.imageOffset = { 0, 0, 0 }; + region.imageExtent = { size.width, size.height, 1 }; + + vkCmdCopyBufferToImage(*cmd, target->StagingBuffer->Handle, target->Image, + VK_IMAGE_LAYOUT_GENERAL, 1, ®ion); + }); + // Sync with Fence // Transition to whatever we need diff --git a/src/graphics/vkrenderer.cpp b/src/graphics/vkrenderer.cpp index 44cb571..ceede56 100644 --- a/src/graphics/vkrenderer.cpp +++ b/src/graphics/vkrenderer.cpp @@ -200,6 +200,14 @@ bool renderer_begin_frame(VulkanRenderer* renderer) void renderer_begin_pass( VulkanRenderer* renderer, RenderTarget* target, VkRect2D renderArea, bool clear) { + // Validate that "Image" is valid + if (target == nullptr || target->TargetImage == nullptr) { + yolo::error("Target image is null"); + } + // print target details + yo::info("Target: {} {} {}", target->TargetImage->Image, target->TargetImage->Memory, + target->TargetImage->ImageView); + VkImageMemoryBarrier imageMemoryBarrier {}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; diff --git a/src/inferno.cpp b/src/inferno.cpp index 6747c76..8231697 100644 --- a/src/inferno.cpp +++ b/src/inferno.cpp @@ -352,7 +352,6 @@ int inferno_run(InfernoApp* app) } if (ImGui::Begin("Render")) { - graphics::rayr_prepare(app->RayRenderer); graphics::rayr_draw(app->RayRenderer); ImTextureID texture diff --git a/src/preview/renderer.cpp b/src/preview/renderer.cpp index d890169..7d78214 100644 --- a/src/preview/renderer.cpp +++ b/src/preview/renderer.cpp @@ -38,6 +38,7 @@ PreviewRenderer* preview_create(VulkanRenderer* vkrenderer) renderer->PreviewRenderTarget = graphics::rendertarget_create( renderer->Renderer->Device, { 1920, 1080 }, VK_FORMAT_R8G8B8A8_UNORM, true); + yolo::info("Created preview rendertarget"); // bind preview renderer to debugdraw debug_init(renderer); @@ -71,10 +72,12 @@ void preview_draw(PreviewRenderer* renderer, scene::Scene* scene) VkCommandBuffer commandBuffer = *renderer->Renderer->CommandBufferInFlight; // if changed if (renderer->HasViewportChanged) { + yolo::info("Resizing preview"); graphics::rendertarget_recreate(renderer->PreviewRenderTarget, renderer->Viewport.extent, VK_FORMAT_R8G8B8A8_UNORM); } + yolo::info("Drawing preview"); graphics::renderer_begin_pass( renderer->Renderer, renderer->PreviewRenderTarget, renderer->Viewport); diff --git a/src/raytracing/renderer.cpp b/src/raytracing/renderer.cpp index b926bdc..c73556e 100644 --- a/src/raytracing/renderer.cpp +++ b/src/raytracing/renderer.cpp @@ -96,9 +96,8 @@ void rayr_draw(RayRenderer* renderer) #pragma omp parallel for for (int x = 0; x < renderer->Viewport.extent.width; x++) { for (int y = 0; y < renderer->Viewport.extent.height; y++) { - renderer->RenderData[y * renderer->Viewport.extent.width + x] - = { 0.0f, 0.0f, 0.0f, 1.0f }; - // rays::Ray* ray = startRays.Field[x * renderer->Viewport.extent.height + y]; + rays::Ray* ray = startRays.Field[x * renderer->Viewport.extent.height + y]; + renderer->RenderData[y * renderer->Viewport.extent.width + x] = glm::vec4(ray->Direction, 1.0); // rays::HitInfo* closest_hit = nullptr; // // for (auto& obj : scene::scene_get_renderables(renderer->Scene)) {