FIX: Memory error fix, debug scheme

This commit is contained in:
2025-11-01 01:21:41 +09:00
parent 235d9b2f83
commit d5ff6263ee
18 changed files with 609 additions and 95 deletions

View File

@@ -809,13 +809,16 @@ void RenderGraph::add_present_chain(RGImageHandle sourceDraw,
RGImageHandle RenderGraph::import_draw_image()
{
RGImportedImageDesc d{};
d.name = "drawImage";
d.image = _context->getSwapchain()->drawImage().image;
d.imageView = _context->getSwapchain()->drawImage().imageView;
d.format = _context->getSwapchain()->drawImage().imageFormat;
d.extent = _context->getDrawExtent();
d.currentLayout = VK_IMAGE_LAYOUT_GENERAL;
RGImportedImageDesc d{};
d.name = "drawImage";
d.image = _context->getSwapchain()->drawImage().image;
d.imageView = _context->getSwapchain()->drawImage().imageView;
d.format = _context->getSwapchain()->drawImage().imageFormat;
d.extent = _context->getDrawExtent();
// Treat layout as unknown at frame start to force an explicit barrier
// into the first declared usage (compute write / color attach). This
// avoids mismatches when the previous frame ended in a different layout.
d.currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
return import_image(d);
}
@@ -942,8 +945,10 @@ RGImageHandle RenderGraph::import_swapchain_image(uint32_t index)
d.imageView = views[index];
d.format = _context->getSwapchain()->swapchainImageFormat();
d.extent = _context->getSwapchain()->swapchainExtent();
d.currentLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
return import_image(d);
// On first use after swapchain creation, images are in UNDEFINED layout.
// Start from UNDEFINED so the graph inserts the necessary transition.
d.currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
return import_image(d);
}
void RenderGraph::resolve_timings()
@@ -960,7 +965,7 @@ void RenderGraph::resolve_timings()
_context->getDevice()->device(), _timestampPool,
0, queryCount,
sizeof(uint64_t) * results.size(), results.data(), sizeof(uint64_t),
VK_QUERY_RESULT_64_BIT);
VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
// Convert ticks to ms
VkPhysicalDeviceProperties props{};
vkGetPhysicalDeviceProperties(_context->getDevice()->physicalDevice(), &props);
@@ -983,6 +988,8 @@ void RenderGraph::resolve_timings()
}
}
// Ensure any pending work that might still reference the pool is complete
vkQueueWaitIdle(_context->getDevice()->graphicsQueue());
vkDestroyQueryPool(_context->getDevice()->device(), _timestampPool, nullptr);
_timestampPool = VK_NULL_HANDLE;
}

View File

@@ -1,8 +1,11 @@
#include <render/rg_resources.h>
#include <core/engine_context.h>
#include <core/vk_resource.h>
#include <vk_mem_alloc.h>
#include <core/config.h>
#include "frame_resources.h"
#include "vk_device.h"
void RGResourceRegistry::reset()
{
@@ -53,7 +56,13 @@ RGImageHandle RGResourceRegistry::add_transient(const RGImageDesc& d)
rec.creationUsage = d.usage;
VkExtent3D size{ d.extent.width, d.extent.height, 1 };
rec.allocation = _ctx->getResources()->create_image(size, d.format, d.usage);
rec.allocation = _ctx->getResources()->create_image(size, d.format, d.usage);
// Name the allocation for diagnostics (optional)
if (vmaDebugEnabled() && _ctx && _ctx->getDevice())
{
std::string nm = std::string("rg.image:") + d.name;
vmaSetAllocationName(_ctx->getDevice()->allocator(), rec.allocation.allocation, nm.c_str());
}
rec.image = rec.allocation.image;
rec.imageView = rec.allocation.imageView;

View File

@@ -21,7 +21,8 @@ void GLTFMetallic_Roughness::build_pipelines(VulkanEngine *engine)
layoutBuilder.add_binding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
materialLayout = layoutBuilder.build(engine->_deviceManager->device(),
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
nullptr, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT);
VkDescriptorSetLayout layouts[] = {
engine->_descriptorManager->gpuSceneDataLayout(),

View File

@@ -94,6 +94,6 @@ void BackgroundPass::cleanup()
_context->pipelines->destroyComputePipeline("gradient");
_context->pipelines->destroyComputePipeline("sky");
}
fmt::print("RenderPassManager::cleanup()\n");
fmt::print("BackgroundPass::cleanup()\n");
_backgroundEffects.clear();
}

View File

@@ -30,7 +30,9 @@ void LightingPass::init(EngineContext *context)
builder.add_binding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
builder.add_binding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
builder.add_binding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
_gBufferInputDescriptorLayout = builder.build(_context->getDevice()->device(), VK_SHADER_STAGE_FRAGMENT_BIT);
_gBufferInputDescriptorLayout = builder.build(
_context->getDevice()->device(), VK_SHADER_STAGE_FRAGMENT_BIT,
nullptr, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT);
}
// Allocate and write GBuffer descriptor set
@@ -51,21 +53,22 @@ void LightingPass::init(EngineContext *context)
{
DescriptorLayoutBuilder builder;
builder.add_binding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, kShadowCascadeCount);
_shadowDescriptorLayout = builder.build(_context->getDevice()->device(), VK_SHADER_STAGE_FRAGMENT_BIT);
_shadowDescriptorLayout = builder.build(
_context->getDevice()->device(), VK_SHADER_STAGE_FRAGMENT_BIT,
nullptr, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT);
}
// Build lighting pipeline through PipelineManager
// Build lighting pipelines (RT and non-RT) through PipelineManager
VkDescriptorSetLayout layouts[] = {
_context->getDescriptorLayouts()->gpuSceneDataLayout(),
_gBufferInputDescriptorLayout,
_shadowDescriptorLayout
};
GraphicsPipelineCreateInfo info{};
info.vertexShaderPath = _context->getAssets()->shaderPath("fullscreen.vert.spv");
info.fragmentShaderPath = _context->getAssets()->shaderPath("deferred_lighting.frag.spv");
info.setLayouts.assign(std::begin(layouts), std::end(layouts));
info.configure = [this](PipelineBuilder &b) {
GraphicsPipelineCreateInfo baseInfo{};
baseInfo.vertexShaderPath = _context->getAssets()->shaderPath("fullscreen.vert.spv");
baseInfo.setLayouts.assign(std::begin(layouts), std::end(layouts));
baseInfo.configure = [this](PipelineBuilder &b) {
b.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
b.set_polygon_mode(VK_POLYGON_MODE_FILL);
b.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE);
@@ -74,13 +77,16 @@ void LightingPass::init(EngineContext *context)
b.disable_depthtest();
b.set_color_attachment_format(_context->getSwapchain()->drawImage().imageFormat);
};
_context->pipelines->createGraphicsPipeline("deferred_lighting", info);
// fetch the handles so current frame uses latest versions
MaterialPipeline mp{};
_context->pipelines->getMaterialPipeline("deferred_lighting", mp);
_pipeline = mp.pipeline;
_pipelineLayout = mp.layout;
// Non-RT variant (no TLAS required)
auto infoNoRT = baseInfo;
infoNoRT.fragmentShaderPath = _context->getAssets()->shaderPath("deferred_lighting_nort.frag.spv");
_context->pipelines->createGraphicsPipeline("deferred_lighting.nort", infoNoRT);
// RT variant (requires GL_EXT_ray_query and TLAS bound at set=0,binding=1)
auto infoRT = baseInfo;
infoRT.fragmentShaderPath = _context->getAssets()->shaderPath("deferred_lighting.frag.spv");
_context->pipelines->createGraphicsPipeline("deferred_lighting.rt", infoRT);
_deletionQueue.push_function([&]() {
// Pipelines are owned by PipelineManager; only destroy our local descriptor set layout
@@ -145,8 +151,20 @@ void LightingPass::draw_lighting(VkCommandBuffer cmd,
VkImageView drawView = resources.image_view(drawHandle);
if (drawView == VK_NULL_HANDLE) return;
// Re-fetch pipeline in case it was hot-reloaded
pipelineManager->getGraphics("deferred_lighting", _pipeline, _pipelineLayout);
// Choose RT only if TLAS is valid; otherwise fall back to non-RT.
const bool haveRTFeatures = ctxLocal->getDevice()->supportsAccelerationStructure();
const VkAccelerationStructureKHR tlas = (ctxLocal->ray ? ctxLocal->ray->tlas() : VK_NULL_HANDLE);
const VkDeviceAddress tlasAddr = (ctxLocal->ray ? ctxLocal->ray->tlasAddress() : 0);
const bool useRT = haveRTFeatures && (ctxLocal->shadowSettings.mode != 0u) && (tlas != VK_NULL_HANDLE) && (tlasAddr != 0);
const char* pipeName = useRT ? "deferred_lighting.rt" : "deferred_lighting.nort";
if (!pipelineManager->getGraphics(pipeName, _pipeline, _pipelineLayout))
{
// Try the other variant as a fallback
const char* fallback = useRT ? "deferred_lighting.nort" : "deferred_lighting.rt";
if (!pipelineManager->getGraphics(fallback, _pipeline, _pipelineLayout))
return; // Neither pipeline is ready
}
// Dynamic rendering is handled by the RenderGraph using the declared draw attachment.
@@ -168,14 +186,10 @@ void LightingPass::draw_lighting(VkCommandBuffer cmd,
deviceManager->device(), descriptorLayouts->gpuSceneDataLayout());
DescriptorWriter writer;
writer.write_buffer(0, gpuSceneDataBuffer.buffer, sizeof(GPUSceneData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
// If TLAS available and feature enabled, bind it at (set=0,binding=1)
if (ctxLocal->ray && ctxLocal->getDevice()->supportsAccelerationStructure() && ctxLocal->shadowSettings.mode != 0u)
// Only write TLAS when using the RT pipeline and we have a valid TLAS
if (useRT)
{
VkAccelerationStructureKHR tlas = ctxLocal->ray->tlas();
if (tlas != VK_NULL_HANDLE)
{
writer.write_acceleration_structure(1, tlas);
}
writer.write_acceleration_structure(1, tlas);
}
writer.update_set(deviceManager->device(), globalDescriptor);

View File

@@ -47,6 +47,7 @@ void ShadowPass::init(EngineContext *context)
b.set_multisampling_none();
b.disable_blending();
// Keep reverse-Z convention for shadow maps to match engine depth usage
b.enable_depthtest(true, VK_COMPARE_OP_GREATER_OR_EQUAL);
b.set_depth_format(VK_FORMAT_D32_SFLOAT);