initial commit-moved from vulkan_guide

This commit is contained in:
2025-10-10 22:53:54 +09:00
commit 8853429937
2484 changed files with 973414 additions and 0 deletions

90
docs/EngineContext.md Normal file
View File

@@ -0,0 +1,90 @@
## Engine Context: Access to Managers + PerFrame State
Central DI-style handle that modules use to access device/managers, per-frame state, and convenience data without depending directly on `VulkanEngine`.
### Overview
- Ownership: Holds shared owners for `DeviceManager`, `ResourceManager`, and a growable `DescriptorAllocatorGrowable` used across modules.
- Global managers: Non-owning pointers to `SwapchainManager`, `DescriptorManager` (prebuilt layouts), `SamplerManager`, and `SceneManager`.
- Per-frame state: `currentFrame` (command buffer, per-frame descriptor pool, deletion queue), `stats`, and `drawExtent`.
- Subsystems: `compute` (`ComputeManager`) and `pipelines` (`PipelineManager`) exposed for unified graphics/compute API.
- Window + content: `window` (SDL handle) and convenience meshes (`cubeMesh`, `sphereMesh`).
Context is wired in `VulkanEngine::init()` and refreshed each frame before passes execute.
### Render Graph Note
- Builtin passes no longer call `vkCmdBeginRendering` or perform image layout transitions directly.
- Use your pass `register_graph(graph, ...)` to declare attachments and resource accesses; the Render Graph inserts barriers and begins/ends dynamic rendering.
- See `docs/RenderGraph.md` for the builder API and scheduling.
### Quick Start — In a Render Pass (essentials)
```c++
void MyPass::init(EngineContext* context) {
_context = context;
// Use common descriptor layouts provided by DescriptorManager
VkDescriptorSetLayout sceneLayout = _context->getDescriptorLayouts()->gpuSceneDataLayout();
// Build a pipeline via PipelineManager (re-fetch on draw for hot reload)
GraphicsPipelineCreateInfo info{};
info.vertexShaderPath = "../shaders/fullscreen.vert.spv";
info.fragmentShaderPath = "../shaders/my_pass.frag.spv";
info.setLayouts = { sceneLayout };
info.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);
b.set_multisampling_none();
b.disable_depthtest();
b.set_color_attachment_format(_context->getSwapchain()->drawImage().imageFormat);
};
_context->pipelines->createGraphicsPipeline("my_pass", info);
}
void MyPass::execute(VkCommandBuffer cmd) {
// Fetch latest pipeline in case of hot reload
VkPipeline p{}; VkPipelineLayout l{};
_context->pipelines->getGraphics("my_pass", p, l);
// Per-frame uniform buffer via currentFrame allocator
AllocatedBuffer ubuf = _context->getResources()->create_buffer(
sizeof(GPUSceneData), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
_context->currentFrame->_deletionQueue.push_function([=, this]{ _context->getResources()->destroy_buffer(ubuf); });
VmaAllocationInfo ai{}; vmaGetAllocationInfo(_context->getDevice()->allocator(), ubuf.allocation, &ai);
*static_cast<GPUSceneData*>(ai.pMappedData) = _context->getSceneData();
VkDescriptorSet set = _context->currentFrame->_frameDescriptors.allocate(
_context->getDevice()->device(), _context->getDescriptorLayouts()->gpuSceneDataLayout());
DescriptorWriter writer;
writer.write_buffer(0, ubuf.buffer, sizeof(GPUSceneData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
writer.update_set(_context->getDevice()->device(), set);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, p);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, l, 0, 1, &set, 0, nullptr);
// Viewport/scissor from context draw extent
VkViewport vp{0,0,(float)_context->getDrawExtent().width,(float)_context->getDrawExtent().height,0.f,1.f};
vkCmdSetViewport(cmd, 0, 1, &vp);
VkRect2D sc{{0,0},{_context->getDrawExtent().width,_context->getDrawExtent().height}};
vkCmdSetScissor(cmd, 0, 1, &sc);
vkCmdDraw(cmd, 3, 1, 0, 0);
}
```
### Life Cycle
- Init: `VulkanEngine` constructs managers, initializes `_context`, then assigns `pipelines`, `compute`, `scene`, etc.
- Per-frame: Engine sets `currentFrame` and `drawExtent`, optionally triggers `PipelineManager::hotReloadChanged()`.
- Cleanup: Managers own their resources; modules should free layouts/sets they create and push per-frame deletions to `currentFrame->_deletionQueue`.
### Best Practices
- Prefer `EngineContext` accessors (`getDevice()`, `getResources()`, `getSwapchain()`) for clarity and testability.
- Re-fetch pipeline/layout by key every frame if using hot reload.
- Use `currentFrame->_frameDescriptors` for transient sets; use `context->descriptors` for longer-lived sets.
- Push resource cleanup to the frame or pass deletion queues to match lifetime with usage.