EDIT: Docs and minor bug fixed
This commit is contained in:
23
docs/ASSETS.md
Normal file
23
docs/ASSETS.md
Normal file
@@ -0,0 +1,23 @@
|
||||
**Assets & Paths**
|
||||
|
||||
- Default locations
|
||||
- `assets/` for models/textures and `shaders/` for GLSL live at the repo root.
|
||||
- The engine auto‑detects these folders by walking up from the working directory.
|
||||
|
||||
- Override root via environment
|
||||
- Set `VKG_ASSET_ROOT` to a directory containing `assets/` and/or `shaders/`.
|
||||
- Example: `VKG_ASSET_ROOT=/home/user/vulkan-engine ./bin/vulkan_engine`
|
||||
|
||||
- API
|
||||
- Use `AssetLocator` through `EngineContext::getAssets()` helpers:
|
||||
- `shaderPath("name.spv")` resolves a shader.
|
||||
- `assetPath("relative/or/absolute")` resolves runtime assets.
|
||||
- `modelPath("some.glb")` is an alias for `assetPath`.
|
||||
|
||||
- Sample content
|
||||
- The engine loads `assets/police_office.glb` by default in `VulkanEngine::init()`.
|
||||
- Ensure this file (and any textures it references) exists under your asset root, or adjust the path used by the sample scene.
|
||||
|
||||
- Materials & sRGB
|
||||
- See `docs/asset_manager.md` for mesh/material creation and sRGB/UNORM handling.
|
||||
|
||||
38
docs/BUILD.md
Normal file
38
docs/BUILD.md
Normal file
@@ -0,0 +1,38 @@
|
||||
**Build & Environment**
|
||||
|
||||
- Prerequisites
|
||||
- Vulkan SDK installed and `VULKAN_SDK` set.
|
||||
- A C++20 compiler and CMake ≥ 3.8.
|
||||
- GPU drivers with Vulkan 1.2+.
|
||||
|
||||
- Configure
|
||||
- `cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug`
|
||||
- Re-run configure after toolchain or dependency changes.
|
||||
|
||||
- Build (single-config)
|
||||
- `cmake --build build --target vulkan_engine`
|
||||
|
||||
- Build (multi-config, e.g., MSVC)
|
||||
- `cmake --build build --config Release`
|
||||
|
||||
- Run
|
||||
- `./bin/vulkan_engine` (Linux/macOS)
|
||||
- `bin/vulkan_engine.exe` (Windows)
|
||||
|
||||
- Shaders
|
||||
- CMake compiles GLSL via `glslangValidator` to SPIR‑V targeting Vulkan 1.2:
|
||||
- Files under `shaders/*.vert|*.frag|*.comp` are rebuilt on `cmake --build`.
|
||||
- Windows helper: `./compile_shaders.ps1` uses `glslc` with `--target-env=vulkan1.3` and supports additional stages (mesh/task/ray tracing).
|
||||
- Ensure `glslangValidator`/`glslc` is on `PATH`. See `docs/SHADERS.md`.
|
||||
|
||||
- Windows SDK note
|
||||
- `CMakeLists.txt` includes a default SDK path for Windows `1.3.296.0`:
|
||||
- Update the path or set `VULKAN_SDK` accordingly if your version differs.
|
||||
|
||||
- Third‑party deps
|
||||
- Vendored under `third_party/` and brought in via CMake. Do not edit headers directly; update through targets.
|
||||
|
||||
- Validation Layers
|
||||
- Enabled in Debug (`kUseValidationLayers = true` in `src/core/config.h`).
|
||||
- Disable by building Release or toggling the flag during local experimentation.
|
||||
|
||||
34
docs/FrameResources.md
Normal file
34
docs/FrameResources.md
Normal file
@@ -0,0 +1,34 @@
|
||||
## Frame Resources: Per-Frame Command, Sync, and Transient Descriptors
|
||||
|
||||
Per-frame struct that owns the command buffer, semaphores/fence, a transient descriptor allocator, and a small deletion queue. Frames are indexed by `FRAME_OVERLAP` (currently 2) and rotated by `_frameNumber` in `VulkanEngine`.
|
||||
|
||||
- File: `src/core/frame_resources.h/.cpp`
|
||||
|
||||
### Responsibilities
|
||||
- Command recording: `_mainCommandBuffer` allocated from a per-frame `_commandPool` with RESET flag.
|
||||
- Synchronization: `_swapchainSemaphore` (image acquired), `_renderSemaphore` (render finished), `_renderFence` (CPU wait per frame).
|
||||
- Transient descriptors: `_frameDescriptors` is a `DescriptorAllocatorGrowable` cleared every frame via `clear_pools()`.
|
||||
- Lifetime: `_deletionQueue` holds lambdas for transient GPU objects created during the frame (buffers/images) and is flushed at the start of the next frame.
|
||||
|
||||
### Frame Flow (engine side)
|
||||
- Start of frame:
|
||||
- Wait on `_renderFence` (previous GPU work for this frame index), flush `_deletionQueue`, and clear `_frameDescriptors` pools.
|
||||
- Acquire swapchain image signaling `_swapchainSemaphore`.
|
||||
- Reset `_renderFence` and `_mainCommandBuffer`; begin recording.
|
||||
- Publish `currentFrame` pointer and `drawExtent` on `EngineContext`.
|
||||
- Graph build and execute:
|
||||
- Render Graph is cleared and rebuilt; `ResourceManager::register_upload_pass(...)` is added first if there are pending uploads.
|
||||
- Passes record using the published `currentFrame` to allocate transient descriptor sets and to enqueue per-frame cleanups.
|
||||
- Submit and present:
|
||||
- Submit `cmd` with wait on `_swapchainSemaphore` and signal `_renderSemaphore`, fence `_renderFence`.
|
||||
- Present waits on `_renderSemaphore`.
|
||||
|
||||
### Do/Don’t
|
||||
- Do use `currentFrame->_frameDescriptors` for descriptor sets that live only for this frame.
|
||||
- Do push transient resource destruction into `currentFrame->_deletionQueue`.
|
||||
- Don’t stash per-frame descriptor sets across frames — they are reset on `clear_pools()`.
|
||||
|
||||
### Extending
|
||||
- If a pass needs additional short-lived command buffers, allocate them from `_commandPool` and reset per frame.
|
||||
- If you add frames-in-flight, update `FRAME_OVERLAP` and verify fences/semaphores and swapchain image acquisition logic.
|
||||
|
||||
21
docs/RUNTIME.md
Normal file
21
docs/RUNTIME.md
Normal file
@@ -0,0 +1,21 @@
|
||||
**Runtime Controls & Debug UI**
|
||||
|
||||
- Camera
|
||||
- Move: `W/A/S/D`
|
||||
- Look: hold Right Mouse Button
|
||||
- Mouse wheel: adjust movement speed
|
||||
- Ctrl + wheel: adjust FOV (30°..110°)
|
||||
|
||||
- Windows (ImGui)
|
||||
- Background: choose compute background effect and `Render Scale`.
|
||||
- Stats: frame/draw/update timings, triangle and draw counts.
|
||||
- GPU/Resources: per‑frame allocations and render‑graph resource view.
|
||||
- Pipelines: list graphics pipelines and hot‑reload changed shaders.
|
||||
- Targets: swapchain/draw extent/format info.
|
||||
- PostFX: tonemap operator (Reinhard/ACES) and exposure.
|
||||
- Scene: counts of opaque/transparent draws.
|
||||
|
||||
- Shadow Modes
|
||||
- Cascaded shadow mapping (CSM) is the default; cascades are created per‑frame via the render graph.
|
||||
- If ray tracing extensions and device support are present, ray‑traced shadows can be enabled via `_context->shadowSettings.mode` (see `src/core/config.h` and usage in `LightingPass`).
|
||||
|
||||
42
docs/RayTracing.md
Normal file
42
docs/RayTracing.md
Normal file
@@ -0,0 +1,42 @@
|
||||
## Ray Tracing Manager: BLAS Cache and Per-Frame TLAS
|
||||
|
||||
Optional subsystem that enables hybrid or full ray traced shadows via Ray Query. It builds and caches BLAS per mesh and rebuilds a TLAS from the current `DrawContext` when enabled.
|
||||
|
||||
- Files: `src/core/vk_raytracing.h/.cpp`
|
||||
|
||||
### Device Feature & Extension Enablement
|
||||
- Feature detection happens in `DeviceManager::init_vulkan()` and sets:
|
||||
- `VK_KHR_acceleration_structure`, `VK_KHR_ray_query`, and `VK_KHR_deferred_host_operations` (if supported).
|
||||
- Device features are appended via `DeviceBuilder.add_pNext(...)`.
|
||||
- `DescriptorManager::gpuSceneDataLayout()` adds a TLAS binding at `(set=0, binding=1)` when AS is supported.
|
||||
|
||||
### BLAS Build & Cache
|
||||
- `AccelStructureHandle getOrBuildBLAS(const std::shared_ptr<MeshAsset>& mesh)`:
|
||||
- One GAS per `MeshAsset`, keyed by vertex buffer `VkBuffer`.
|
||||
- Populated with one triangle geometry per `GeoSurface`.
|
||||
- Built with `VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR` and device-local storage + scratch.
|
||||
- Cached in `_blasByVB` for reuse across frames.
|
||||
- Called from `AssetManager::createMesh(...)` and from GLTF loader after mesh upload.
|
||||
|
||||
### TLAS Rebuild Per Frame
|
||||
- `VkAccelerationStructureKHR buildTLASFromDrawContext(const DrawContext& dc)`:
|
||||
- Iterates `dc.OpaqueSurfaces` and creates one instance per render object.
|
||||
- Looks up BLAS by `RenderObject::vertexBuffer`; if missing, instance is skipped.
|
||||
- Uploads instances to a CPU→GPU buffer with device address.
|
||||
- Builds TLAS with `immediate_submit` and stores device address for Ray Query.
|
||||
|
||||
### Renderer Integration
|
||||
- In `VulkanEngine::draw()` before building passes:
|
||||
- If RT mode is enabled (`shadowSettings.mode != 0`) and manager exists, TLAS is rebuilt from the latest draw context.
|
||||
- Lighting pass binds the TLAS at `set=0,binding=1` when available.
|
||||
|
||||
### Modes & UI
|
||||
- Mode 0: Shadow maps only (CSM).
|
||||
- Mode 1: Hybrid — selected cascades assisted by Ray Query (configurable bitmask).
|
||||
- Mode 2: Ray Query only (no shadow maps).
|
||||
|
||||
### Notes & Caveats
|
||||
- BLAS cache key is the vertex buffer handle; if you rebuild meshes in-place, BLAS must be invalidated.
|
||||
- CPU→GPU memory is used for the TLAS instance buffer to simplify updates. On some platforms, you may prefer staging + device-local.
|
||||
- The RT path requires Vulkan 1.2+ with Ray Query and Acceleration Structure features available.
|
||||
|
||||
@@ -70,6 +70,8 @@ addPass(std::move(myPass));
|
||||
- Background (compute): Declares `ComputeWrite(drawImage)` and dispatches a selected effect instance.
|
||||
- Geometry (G-Buffer): Declares 3 color attachments and `DepthAttachment`, plus buffer reads for shared index/vertex buffers.
|
||||
- Lighting (deferred): Reads G‑Buffer as sampled images and writes to `drawImage`.
|
||||
- Shadows: Cascaded shadow maps render to per-frame transient depth images (four cascades). If Ray Query is enabled,
|
||||
the lighting pass additionally samples TLAS to evaluate shadow visibility according to the selected mode.
|
||||
- Transparent (forward): Writes to `drawImage` with depth test against `depthImage` after lighting.
|
||||
- ImGui: Inserted just before present to draw on the swapchain image.
|
||||
|
||||
|
||||
@@ -47,3 +47,7 @@ Central allocator and uploader built on VMA. Provides creation helpers, an immed
|
||||
- For tooling and one‑off setup, use `immediate_submit(lambda)` to avoid per‑frame queuing.
|
||||
- When creating transient images/buffers used only inside a pass, prefer the Render Graph’s `create_*` so destruction is automatic at frame end.
|
||||
|
||||
### Known Issue (transition after mip generation)
|
||||
|
||||
- In the Render Graph upload pass, the mipmap path should leave the image in `VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL` after `vkutil::generate_mipmaps(...)`. If you see an extra transition back to `TRANSFER_DST_OPTIMAL` after mip generation, remove it. The helper already transitions to the final sampled layout.
|
||||
|
||||
|
||||
25
docs/SHADERS.md
Normal file
25
docs/SHADERS.md
Normal file
@@ -0,0 +1,25 @@
|
||||
**Shaders & Hot Reload**
|
||||
|
||||
- Locations
|
||||
- Sources live under `shaders/` and are compiled to `.spv` next to the sources.
|
||||
|
||||
- Build integration
|
||||
- CMake invokes `glslangValidator -V` for `*.vert`, `*.frag`, `*.comp` targeting Vulkan 1.2.
|
||||
- Windows PowerShell helper `compile_shaders.ps1` uses `glslc` targeting Vulkan 1.3 and supports additional stages:
|
||||
- `.mesh` (`-fshader-stage=mesh`), `.task`, and ray tracing stages (`.rgen`, `.rmiss`, `.rchit`, `.rahit`, `.rint`, `.rcall`).
|
||||
- Keep `glslangValidator`/`glslc` on `PATH` and ensure your Vulkan SDK is installed.
|
||||
|
||||
- Hot reload
|
||||
- `PipelineManager::hotReloadChanged()` watches `.spv` modification times.
|
||||
- Pipelines rebind the next frame when a shader file timestamp changes.
|
||||
- ImGui → Pipelines window provides a manual “Reload Changed” button and lists currently registered pipelines.
|
||||
|
||||
- Conventions
|
||||
- Name SPIR‑V files with full extension, e.g. `fullscreen.vert.spv`, `deferred_lighting.frag.spv`.
|
||||
- Use `EngineContext::getAssets()->shaderPath("<name>.spv")` when registering pipelines.
|
||||
- Use sRGB formats for albedo textures and UNORM for PBR control textures (see `docs/asset_manager.md`).
|
||||
|
||||
- Adding a pipeline (graphics)
|
||||
- Fill `GraphicsPipelineCreateInfo` with shader paths, descriptor set layouts, optional push constants, and a `configure(PipelineBuilder&)` callback to set topology, raster, depth/blend, and attachment formats.
|
||||
- Register with `PipelineManager::createGraphicsPipeline(name, info)`. Retrieve via `getGraphics` or `getMaterialPipeline`.
|
||||
|
||||
26
docs/TROUBLESHOOTING.md
Normal file
26
docs/TROUBLESHOOTING.md
Normal file
@@ -0,0 +1,26 @@
|
||||
**Troubleshooting**
|
||||
|
||||
- Shader compiler not found
|
||||
- Ensure `glslangValidator` (and/or `glslc` on Windows) is on `PATH`.
|
||||
- Re‑open your terminal after installing the Vulkan SDK.
|
||||
|
||||
- Windows SDK version mismatch
|
||||
- `CMakeLists.txt` references `C:/VulkanSDK/1.3.296.0` by default.
|
||||
- Update the path or set `VULKAN_SDK` to your installed version.
|
||||
|
||||
- Validation errors on startup
|
||||
- Update GPU drivers and Vulkan SDK.
|
||||
- Try running a Release build to confirm if the issue is validation‑only.
|
||||
|
||||
- Black screen or out‑of‑date swapchain
|
||||
- Resize the window once to force a swapchain rebuild.
|
||||
- Check the ImGui “Targets” window for swapchain/draw formats and extent.
|
||||
|
||||
- No models rendering
|
||||
- Verify `assets/police_office.glb` exists (see `docs/ASSETS.md`).
|
||||
- Open the “Scene” window to confirm draw counts > 0.
|
||||
|
||||
- Shader changes not visible
|
||||
- Confirm the `.spv` file changed (timestamp) and click “Reload Changed” in the Pipelines window.
|
||||
- Ensure you are editing the correct files referenced by `shaderPath()`.
|
||||
|
||||
@@ -120,6 +120,9 @@ private:
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
// Small compute manager for one-off pipelines and persistent instances.
|
||||
// It owns a dedicated descriptor allocator and provides helpers to build
|
||||
// pipelines, set bindings, and dispatch work (immediate or on a provided cmd).
|
||||
class ComputeManager
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -309,6 +309,11 @@ bool AssetManager::removeMesh(const std::string &name)
|
||||
{
|
||||
auto it = _meshCache.find(name);
|
||||
if (it == _meshCache.end()) return false;
|
||||
if (_engine && _engine->_rayManager)
|
||||
{
|
||||
// Clean up BLAS cached for this mesh (if ray tracing is enabled)
|
||||
_engine->_rayManager->removeBLASForBuffer(it->second->meshBuffers.vertexBuffer.buffer);
|
||||
}
|
||||
if (_engine && _engine->_resourceManager)
|
||||
{
|
||||
_engine->_resourceManager->destroy_buffer(it->second->meshBuffers.indexBuffer);
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
class DeviceManager;
|
||||
|
||||
// Per-frame state used by the renderer and passes.
|
||||
// Owns a command buffer, sync primitives, a transient descriptor pool, and a
|
||||
// deletion queue for resources that should be destroyed when the frame is done.
|
||||
struct FrameResources
|
||||
{
|
||||
VkSemaphore _swapchainSemaphore = VK_NULL_HANDLE;
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#include "SDL2/SDL.h"
|
||||
#include "SDL2/SDL_vulkan.h"
|
||||
|
||||
// Create Vulkan instance/device, enable debug/validation (in Debug), pick a GPU,
|
||||
// and set up VMA with buffer device address. If available, enable Ray Query and
|
||||
// Acceleration Structure extensions + features.
|
||||
void DeviceManager::init_vulkan(SDL_Window *window)
|
||||
{
|
||||
vkb::InstanceBuilder builder;
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
// Engine bootstrap, frame loop, and render-graph wiring.
|
||||
//
|
||||
// Responsibilities
|
||||
// - Initialize SDL + Vulkan managers (device, resources, descriptors, samplers, pipelines).
|
||||
// - Create swapchain + default images and build the Render Graph each frame.
|
||||
// - Publish an EngineContext so passes and subsystems access per‑frame state uniformly.
|
||||
// - Drive ImGui + debug UIs and optional ray‑tracing TLAS rebuilds.
|
||||
//
|
||||
// See also:
|
||||
// - docs/EngineContext.md
|
||||
// - docs/RenderGraph.md
|
||||
// - docs/FrameResources.md
|
||||
// - docs/RayTracing.md
|
||||
//
|
||||
//> includes
|
||||
#include "vk_engine.h"
|
||||
#include <core/vk_images.h>
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include "render/rg_graph.h"
|
||||
#include "core/vk_raytracing.h"
|
||||
|
||||
// Number of frames-in-flight. Affects per-frame command buffers, fences,
|
||||
// semaphores, and transient descriptor pools in FrameResources.
|
||||
constexpr unsigned int FRAME_OVERLAP = 2;
|
||||
|
||||
// Compute push constants and effects are declared in compute/vk_compute.h now.
|
||||
|
||||
@@ -25,6 +25,9 @@ struct GraphicsPipelineCreateInfo
|
||||
std::function<void(PipelineBuilder &)> configure;
|
||||
};
|
||||
|
||||
// Graphics pipeline registry with hot-reload support.
|
||||
// Stores specs keyed by name, builds on demand, and can rebuild when shader
|
||||
// timestamps change. Also forwards a minimal Compute API to ComputeManager.
|
||||
class PipelineManager
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -307,3 +307,21 @@ VkAccelerationStructureKHR RayTracingManager::buildTLASFromDrawContext(const Dra
|
||||
|
||||
return _tlas.handle;
|
||||
}
|
||||
|
||||
void RayTracingManager::removeBLASForBuffer(VkBuffer vertexBuffer)
|
||||
{
|
||||
if (!vertexBuffer) return;
|
||||
VkDevice dv = _device->device();
|
||||
auto it = _blasByVB.find(vertexBuffer);
|
||||
if (it == _blasByVB.end()) return;
|
||||
|
||||
if (it->second.handle)
|
||||
{
|
||||
_vkDestroyAccelerationStructureKHR(dv, it->second.handle, nullptr);
|
||||
}
|
||||
if (it->second.storage.buffer)
|
||||
{
|
||||
_resources->destroy_buffer(it->second.storage);
|
||||
}
|
||||
_blasByVB.erase(it);
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
VkDeviceAddress deviceAddress{0};
|
||||
};
|
||||
|
||||
class RayTracingManager {
|
||||
public:
|
||||
// Ray tracing helper that caches BLAS per mesh and rebuilds TLAS per frame
|
||||
// for hybrid/full ray query shadows. See docs/RayTracing.md.
|
||||
class RayTracingManager {
|
||||
public:
|
||||
void init(DeviceManager* dev, ResourceManager* res);
|
||||
void cleanup();
|
||||
|
||||
@@ -28,6 +30,10 @@
|
||||
VkAccelerationStructureKHR tlas() const { return _tlas.handle; }
|
||||
VkDeviceAddress tlasAddress() const { return _tlas.deviceAddress; }
|
||||
|
||||
// Remove and destroy a cached BLAS associated with a vertex buffer.
|
||||
// Safe to call even if no BLAS exists for the buffer.
|
||||
void removeBLASForBuffer(VkBuffer vertexBuffer);
|
||||
|
||||
private:
|
||||
// function pointers (resolved on init)
|
||||
PFN_vkCreateAccelerationStructureKHR _vkCreateAccelerationStructureKHR{};
|
||||
|
||||
@@ -48,7 +48,12 @@ AllocatedBuffer ResourceManager::create_buffer(size_t allocSize, VkBufferUsageFl
|
||||
|
||||
VmaAllocationCreateInfo vmaallocInfo = {};
|
||||
vmaallocInfo.usage = memoryUsage;
|
||||
// Map buffers only when CPU-visible memory is requested
|
||||
if (memoryUsage == VMA_MEMORY_USAGE_CPU_TO_GPU ||
|
||||
memoryUsage == VMA_MEMORY_USAGE_CPU_ONLY)
|
||||
{
|
||||
vmaallocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
||||
}
|
||||
|
||||
AllocatedBuffer newBuffer{};
|
||||
VK_CHECK(vmaCreateBuffer(_deviceManager->allocator(), &bufferInfo, &vmaallocInfo,
|
||||
@@ -129,11 +134,33 @@ AllocatedImage ResourceManager::create_image(VkExtent3D size, VkFormat format, V
|
||||
return newImage;
|
||||
}
|
||||
|
||||
// Returns byte size per texel for a subset of common formats.
|
||||
static inline size_t bytes_per_texel(VkFormat fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case VK_FORMAT_R8_UNORM:
|
||||
case VK_FORMAT_R8_SRGB:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8_UNORM:
|
||||
case VK_FORMAT_R8G8_SRGB:
|
||||
return 2;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
return 4;
|
||||
default:
|
||||
return 4; // STB path uploads 4 channels
|
||||
}
|
||||
}
|
||||
|
||||
AllocatedImage ResourceManager::create_image(const void *data, VkExtent3D size, VkFormat format,
|
||||
VkImageUsageFlags usage,
|
||||
bool mipmapped)
|
||||
{
|
||||
size_t data_size = size.depth * size.width * size.height * 4;
|
||||
size_t bpp = bytes_per_texel(format);
|
||||
size_t data_size = static_cast<size_t>(size.depth) * size.width * size.height * bpp;
|
||||
AllocatedBuffer uploadbuffer = create_buffer(data_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VMA_MEMORY_USAGE_CPU_TO_GPU);
|
||||
|
||||
@@ -480,8 +507,10 @@ void ResourceManager::register_upload_pass(RenderGraph &graph, FrameResources &f
|
||||
|
||||
if (upload.generateMips)
|
||||
{
|
||||
// NOTE: generate_mipmaps() transitions the image to
|
||||
// VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL at the end.
|
||||
// Do not transition back to TRANSFER here. See docs/ResourceManager.md.
|
||||
vkutil::generate_mipmaps(cmd, image, VkExtent2D{upload.extent.width, upload.extent.height});
|
||||
vkutil::transition_image(cmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,6 +7,9 @@ class DeviceManager;
|
||||
class RenderGraph;
|
||||
struct FrameResources;
|
||||
|
||||
// VMA-backed allocator + upload helper.
|
||||
// Creates buffers/images, offers an immediate-submit path, and supports
|
||||
// deferring uploads into a single Render Graph transfer pass per frame.
|
||||
class ResourceManager
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
#include "vk_swapchain.h"
|
||||
|
||||
#include <SDL_video.h>
|
||||
#include "SDL2/SDL_vulkan.h"
|
||||
|
||||
#include "vk_device.h"
|
||||
#include "vk_initializers.h"
|
||||
#include "vk_resource.h"
|
||||
|
||||
// Swapchain + per-frame targets (HDR draw, depth, GBuffer) management.
|
||||
//
|
||||
// Create/resize/destroy logic keeps per-frame images in a local deletion queue
|
||||
// so they are cleaned up with the swapchain. The engine imports those images
|
||||
// into the Render Graph each frame.
|
||||
void SwapchainManager::init_swapchain()
|
||||
{
|
||||
create_swapchain(_windowExtent.width, _windowExtent.height);
|
||||
@@ -115,12 +121,13 @@ void SwapchainManager::create_swapchain(uint32_t width, uint32_t height)
|
||||
|
||||
void SwapchainManager::destroy_swapchain() const
|
||||
{
|
||||
vkDestroySwapchainKHR(_deviceManager->device(), _swapchain, nullptr);
|
||||
|
||||
for (auto _swapchainImageView: _swapchainImageViews)
|
||||
// Destroy image views before the swapchain for stricter driver orderliness.
|
||||
// (Most drivers tolerate either order, but views reference swapchain images.)
|
||||
for (auto view : _swapchainImageViews)
|
||||
{
|
||||
vkDestroyImageView(_deviceManager->device(), _swapchainImageView, nullptr);
|
||||
vkDestroyImageView(_deviceManager->device(), view, nullptr);
|
||||
}
|
||||
vkDestroySwapchainKHR(_deviceManager->device(), _swapchain, nullptr);
|
||||
}
|
||||
|
||||
void SwapchainManager::resize_swapchain(struct SDL_Window *window)
|
||||
@@ -133,7 +140,8 @@ void SwapchainManager::resize_swapchain(struct SDL_Window *window)
|
||||
_deletionQueue.flush();
|
||||
|
||||
int w, h;
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
// HiDPI-aware drawable size for correct pixel dimensions
|
||||
SDL_Vulkan_GetDrawableSize(window, &w, &h);
|
||||
_windowExtent.width = w;
|
||||
_windowExtent.height = h;
|
||||
|
||||
|
||||
@@ -59,6 +59,15 @@ RGBufferHandle RenderGraph::create_buffer(const RGBufferDesc &desc)
|
||||
return _resources.add_transient(desc);
|
||||
}
|
||||
|
||||
// Render Graph: builds a per-frame DAG from declared image/buffer accesses,
|
||||
// inserts precise barriers and layouts, and records passes using dynamic rendering.
|
||||
//
|
||||
// Key steps:
|
||||
// - add_pass(): store declarations and callbacks (build to declare, record to issue commands)
|
||||
// - compile(): topologically sort by read/write hazards and generate Vk*Barrier2 sequences
|
||||
// - execute(): emit pre-pass barriers, begin dynamic rendering if attachments exist, invoke record()
|
||||
//
|
||||
// See docs/RenderGraph.md for API overview and pass patterns.
|
||||
void RenderGraph::add_pass(const char *name, RGPassType type, BuildCallback build, RecordCallback record)
|
||||
{
|
||||
Pass p{};
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "vk_swapchain.h"
|
||||
#include "render/rg_graph.h"
|
||||
|
||||
// Basic conservative frustum test against RenderObject AABB.
|
||||
// Clip space uses Vulkan Z0 (0..w). Returns true if any part of the box is inside.
|
||||
bool is_visible(const RenderObject &obj, const glm::mat4 &viewproj)
|
||||
{
|
||||
const std::array<glm::vec3, 8> corners{
|
||||
|
||||
@@ -185,7 +185,9 @@ void LightingPass::draw_lighting(VkCommandBuffer cmd,
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipelineLayout, 1, 1,
|
||||
&_gBufferInputDescriptorSet, 0, nullptr);
|
||||
|
||||
// Allocate and write shadow descriptor set for this frame (set = 2)
|
||||
// Allocate and write shadow descriptor set for this frame (set = 2).
|
||||
// When RT is enabled, TLAS is bound in the global set at (set=0, binding=1)
|
||||
// via DescriptorManager::gpuSceneDataLayout(). See docs/RayTracing.md.
|
||||
VkDescriptorSet shadowSet = ctxLocal->currentFrame->_frameDescriptors.allocate(
|
||||
deviceManager->device(), _shadowDescriptorLayout);
|
||||
{
|
||||
|
||||
@@ -92,7 +92,9 @@ void TransparentPass::draw_transparent(VkCommandBuffer cmd,
|
||||
writer.write_buffer(0, gpuSceneDataBuffer.buffer, sizeof(GPUSceneData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
||||
writer.update_set(deviceManager->device(), globalDescriptor);
|
||||
|
||||
// Sort transparent back-to-front using camera-space depth
|
||||
// Sort transparent back-to-front using camera-space depth.
|
||||
// We approximate object depth by transforming the mesh bounds origin.
|
||||
// For better results consider using per-object center or per-draw depth range.
|
||||
std::vector<const RenderObject *> draws;
|
||||
draws.reserve(dc.TransparentSurfaces.size());
|
||||
for (const auto &r: dc.TransparentSurfaces) draws.push_back(&r);
|
||||
|
||||
@@ -576,6 +576,10 @@ void LoadedGLTF::clearAll()
|
||||
|
||||
for (auto &[k, v]: meshes)
|
||||
{
|
||||
if (creator->_rayManager)
|
||||
{
|
||||
creator->_rayManager->removeBLASForBuffer(v->meshBuffers.vertexBuffer.buffer);
|
||||
}
|
||||
creator->_resourceManager->destroy_buffer(v->meshBuffers.indexBuffer);
|
||||
creator->_resourceManager->destroy_buffer(v->meshBuffers.vertexBuffer);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user