Regenerated doc + final submit for now

This commit is contained in:
2026-07-22 17:37:01 -04:00
parent c436639ddd
commit c0d40ef3e4
101 changed files with 869 additions and 781 deletions
@@ -5,128 +5,61 @@
- Source: `Juliet\src\Graphics\D3D12\D3D12SwapChain.cpp`
## AI Description
Based on the C++ code provided, here is a structured analysis of the D3D12 Swap Chain implementation within what appears to be a game engine or graphics library (likely "Juliet").
This code snippet is a part of a graphics driver for the Juliet operating system, specifically designed to handle DirectX 12 graphics. It includes functions for creating and managing swapchains, as well as acquiring and releasing textures from these swapchains.
### 1. Core Functionality Summary
The module handles:
* **Swap Chain Creation:** Initializing DXGI swap chains with HDR support options and frame rate control.
* **Texture Management:** Managing the backing D3D12 textures for each back buffer, transitioning states between Presentation (`PRESENT`) and Rendering (`RENDER_TARGET`).
* **Fence Synchronization:** Ensuring previous frames are finished before starting new ones to prevent tearing or accessing dirty buffers during rendering.
Here's a breakdown of what each function does:
---
### `AcquireSwapChainTexture`
### 2. Detailed Code Analysis by Function
This function is responsible for acquiring a texture from the swapchain. It takes a command list, a window, and a pointer to a texture pointer. The function first checks if there are any pending fences that need to be waited on before acquiring the texture. If so, it waits for those fences.
#### A. State Transition ? Acquisition (`AcquireSwapChainTexture` / `WaitAndAcquire`)
These functions manage the lifecycle of individual back buffer textures.
Then, it creates a presentation barrier to transition the resource state from `D3D12_RESOURCE_STATE_PRESENT` to `D3D12_RESOURCE_STATE_RENDER_TARGET`. After setting up the barrier, it retrieves the swapchain texture container and acquires the active texture.
Finally, it returns the acquired texture pointer.
### `WaitAndAcquireSwapChainTexture`
This function is similar to `AcquireSwapChainTexture`, but it waits for a fence before acquiring the texture. This can be useful in scenarios where you need to ensure that certain operations are completed before proceeding with rendering.
### `WaitForSwapchain`
This function waits for the current frame to complete by checking if there are any pending fences. It then returns true if the wait was successful, otherwise false.
### `GetSwapChainTextureFormat`
This function retrieves the format of the swapchain texture based on the specified composition and present mode.
### `Internal::CreateSwapChain`
This is a private helper function that creates a swapchain for a given window and composition. It initializes the swapchain descriptor, queries the parent factory to make the window association, and then creates the swapchain object.
### `Internal::DestroySwapChain`
This is another private helper function that destroys the swapchain and frees all associated resources.
### Usage
To use this code, you would typically create a `D3D12Driver` object and pass it to the functions. You would also need to handle the window state and synchronization mechanisms for your application.
```cpp
// ... inside AcquireSwapChainTexture logic
barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; // Source state (from GPU)
barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; // Destination state (for CPU/GPU read/write)
// Create a D3D12 driver instance
auto driver = new Juliet::D3D12Driver();
// The transition barrier is issued on the command list.
d3d12CommandList-?GraphicsCommandList.CommandList-?ResourceBarrier(1, ?barrierDesc);
*swapchainTexture = reinterpret_cast?Texture*?(?windowData-?SwapChainTextureContainers[...].ActiveTexture); // Returns a pointer wrapper to access TextureDetails struct directly.
```
**Key Insight:** The code explicitly transitions the resource from `PRESENT` (owned by DXGI) back to `RENDER_TARGET`. This is standard practice because:
1. Rendering commands (`Draw`, etc.) typically operate on `RENDER_TARGET` or `COPY_SRC/DST` states depending on context, but transitioning immediately allows for faster access without additional fences if the renderer supports it.
2. It prepares the texture to be read by CPU (if using staging buffers) and written to again in subsequent frame passes via copy commands (`ResourceBarrier` with `D3D12_RESOURCE_BARRIER_FLAG_ALLOW_VISUAL_LOSS_DISCARD`).
#### B. Synchronization Logic (`WaitForSwapchain`)
Before any command list is executed on a new back buffer, this function ensures the previous frame has finished encoding and presenting.
```cpp
if (windowData-?InFlightFences[windowData-?WindowFrameCounter] != nullptr) {
if (!Wait(d3d12Driver, true, ?windowData-?InFlightFences[...], 1 JULIET_DEBUG_PARAM(...))) return false;
// Create a swapchain for a window
NonNullPtr?Window? window = ...; // Initialize your window object
SwapChainComposition composition = SwapChainComposition::SDR;
PresentMode presentMode = PresentMode::FIFO;
if (!Internal::CreateSwapChain(driver, windowData, composition, presentMode))
{
LogError(LogCategory::Graphics, "Failed to create swapchain");
}
return true;
```
**Key Insight:** This checks the fence associated with the specific frame being processed. If a fence exists (meaning previous work is pending), it waits for that fence to signal completion before proceeding.
#### C. Format Resolution ? Metadata (`GetSwapChainTextureFormat`)
This helper determines the pixel format used by the swap chain, which is crucial for shader compilation and resource generation.
```cpp
// Returns TextureFormat enum derived from DXGI_FORMAT of active buffer
auto* d3d12Driver = static_cast?D3D12Driver*?(driver.Get());
return windowData-?SwapChainTextureContainers[windowData-?WindowFrameCounter].Header.CreateInfo.Format;
```
**Key Insight:** It accesses the `CreateInfo` header stored within the texture container to ensure consistent format handling throughout the engine, rather than querying DXGI directly every time.
#### D. Swap Chain Creation (`Internal::CreateSwapChain`)
This is the heavy lifter that interfaces with Windows API and DirectX 12 factories. Notable features:
**1. Configuration:**
* **Resolution:** Uses `0` for width/height, implying full screen usage where the factory determines size based on window client area.
* **Present Mode ? Composition:** Supports SDR (`BG8`) or HDR via a mapping table `SwapchainCompositionToColorSpace`. It dynamically sets color space and format (e.g., RGB10A2 for HDR).
* **Tearing Support:** Checks `driver-?IsTearingSupported` to set the `DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING` flag if present, preventing frame skips when V-Sync is off.
**2. Factory Interactions ? WMA (Windows Meta Association):**
```cpp
// Queries for IDXGISwapChain3 interface needed for HDR settings and specific behaviors.
IDXGISwapChain3* swapChain3 = nullptr;
...
swapChain-?QueryInterface(IID_IDXGISwapChain3, ...); // Note: The original CreateSwapChainForHwnd returns a 1 pointer usually, but here it queries then releases the old one?
// Correction in logic analysis: The code does 'query', assigns to swapChain3 variable, and calls Release on swapChain immediately. This implies swapChain returned by QueryInterface was temporary or they are managing two pointers (original + queried) briefly before swapping roles.
if (!parentFactory-?MakeWindowAssociation(windowHandle, DXGI_MWA_NO_WINDOW_CHANGES))
Log(LogLevel::Warning, ... "Cannot handle window resizing"); // IMPORTANT: Disables automatic resize messages to D3D12 logic?
```
**Key Insight on WMA:** The code calls `DXGI_MWA_NO_WINDOW_CHANGES`. This tells the system **not** to send a `WM_SIZE` message when the user resizes or moves the window.
* *Why?* If the app handles resizing by simply calling `Resize` functions internally without checking Win32 events, this is an optimization (avoiding extra logic). However, if dynamic re-resizing is needed externally, this needs to be reconsidered based on how else size changes are handled in your engine.
**3. HDR Setup:**
It specifically sets the color space only for `SwapChainComposition::HDR` or other non-SDR types:
```cpp
if (composition != SwapChainComposition::SDR) {
swapChain3-?SetColorSpace1(SwapchainCompositionToColorSpace[...]);
}
```
---
### 3. Critical Logic Check ? Observations
#### 🚨 Potential Issue in `CreateSwapChain` Interface Handling
There is a slight logical flow quirk regarding the Swap Chain pointer assignment:
```cpp
IDXGISwapChain1* swapChain = nullptr;
// Creates chain, returns as IDXGISwapChain1 (or higher if capabilities met)
HRESULT result = driver-?DXGIFactory-?CreateSwapChainForHwnd(..., ?swapChain);
// Queries for the specific interface immediately after creation
result = swapChain-?QueryInterface(IID_IDXGISwapChain3, reinterpret_cast?void**?(?swapChain3));
swapChain-?Release(); // ?--- Releases the original pointer passed by reference?
if (FAILED(result)) { ... }
```
* **Behavior:** `CreateSwapChainForHwnd` creates an interface and returns it. The caller is expected to release *one* copy of that interface eventually. By calling `QueryInterface`, you create a new handle (`swapChain3`). If the original return value from Create doesn't support QueryInterface directly (unlikely) or if memory management isn't strict, releasing via Release() on the temporary variable might be premature depending on D3D12 ownership rules here.
* **Standard Pattern:** Usually: `Create...(?SwapChain)`, then use it until done with all interfaces required for HDR/Feature queries before doing cleanup logic in other parts of your engine's destroy sequence (like `DestroySwapChain`).
#### 🚨 Memory Management ? Cleanup (`Internal::DestroySwapChain`)
The destructor releases staging resources and frees D3D12 texture objects manually. This indicates a custom resource pool system rather than just relying on DXGI to clean up everything at shutdown, which is good for performance profiling but requires careful `Free` implementations (likely global Free lists common in Rust/Juliet ecosystems).
#### 📝 Resource Barrier Nuance
In the transition block:
```cpp
barrierDesc.Transition.pResource = ...; // Pointer math looks correct based on struct layout.
barrierDesc.Transition.Subresource = 0;
// Note: Since this is not a multi-sub-resource texture (like video textures), Subresource=0 covers everything.
```
### 4. Recommendations / Improvements
1. **Validate WMA Logic:** Ensure `DXGI_MWA_NO_WINDOW_CHANGES` doesn't break dynamic resolution support in your game engine. If the window moves/resizes but you don't update texture dimensions, it could cause black screens or crashes upon resize.
2. **Interface Management:** The immediate release of the original Swap Chain pointer after acquiring `IDXGISwapChain3` looks unusual if the engine expects to keep using generic features later without re-acquisition every time (e.g., in a destructor). Consider storing the generic interface and only converting up/down when HDR is specifically accessed or during teardown.
3. **Error Handling:** The `CreateSwapChainForHwnd` call checks for failure, but if it fails due to invalid window handle (`IsWindow` check passed earlier), ensure robust logging regarding *why* (e.g., focus lost, incompatible OS version).
### Conclusion
This is a well-structured implementation of D3D12 Swap Chain logic tailored for an engine that likely supports HDR and custom resolution scaling. The explicit fence waiting and manual state transitions indicate high control over the rendering pipeline to ensure frame timing consistency and prevent visual
// Acquire a texture from the swapchain
NonNullPtr?CommandList? commandList = ...; // Initialize your command list object
Texture* swapChainTexture;
if (!AcquireSwapChainTexture(commandList, window, ?swapChainTexture))
{
LogError(LogCategory::Graphics, "Failed
## Symbols