275 lines
8.1 KiB
Markdown
275 lines
8.1 KiB
Markdown
# NewEditor D3D12 Legacy D2D Closure Plan
|
|
|
|
Date: 2026-04-22
|
|
|
|
## 1. Problem Statement
|
|
|
|
`new_editor` main-window realtime presentation has already moved onto the native `D3D12` path, but the codebase still retains a legacy `D2D / D3D11On12` bridge in the host layer.
|
|
|
|
That residual path is no longer the main realtime hot path, but it is still architecturally serious because it keeps a second rendering/composition implementation alive for the same UI draw model.
|
|
|
|
Current residual seam:
|
|
|
|
- `app/Rendering/Native/NativeRenderer.*`
|
|
- `app/Rendering/D3D12/D3D12WindowInteropContext.*`
|
|
- `app/Rendering/D3D12/D3D12WindowInteropHelpers.h`
|
|
- host/build references that still compile and link the old bridge
|
|
|
|
## 2. Confirmed Current Facts
|
|
|
|
### 2.1 Main window realtime presentation no longer depends on D2D
|
|
|
|
Main realtime presentation flows through:
|
|
|
|
- `D3D12WindowRenderer`
|
|
- `D3D12UiRenderer`
|
|
- `D3D12WindowRenderLoop`
|
|
|
|
The active main path does not call `NativeRenderer::Render(...)`.
|
|
|
|
### 2.2 Residual D2D bridge is concentrated, not scattered
|
|
|
|
The old bridge is now effectively concentrated in:
|
|
|
|
- screenshot/export flow
|
|
- dead hwnd-native D2D window rendering code that is no longer wired into the main frame loop
|
|
|
|
### 2.3 NativeRenderer is no longer the main texture host
|
|
|
|
`TexturePort` for the active editor path is already `D3D12UiTextureHost`.
|
|
|
|
This means the remaining `NativeRenderer` responsibilities can be removed instead of preserved as an active subsystem.
|
|
|
|
## 3. Root Architectural Issue
|
|
|
|
The root issue is not “some D2D symbols still exist”.
|
|
|
|
The root issue is that `new_editor` still retains two incompatible host-side ways to turn UI output into pixels:
|
|
|
|
1. Active path: native `D3D12` rendering into the swapchain backbuffer.
|
|
2. Residual path: `UIDrawData -> D2D replay`, with optional `D3D11On12` resource interop.
|
|
|
|
As long as both remain alive:
|
|
|
|
- draw semantics can drift between live output and capture/export output
|
|
- future UI/rendering changes must be kept compatible with two host backends
|
|
- dead-window code remains available to be accidentally reused
|
|
- build/link dependencies preserve obsolete platform coupling
|
|
|
|
So the correct goal is full single-path closure, not incremental patching.
|
|
|
|
## 4. Target End State
|
|
|
|
After this refactor:
|
|
|
|
1. Main-window realtime rendering remains native `D3D12`.
|
|
2. Main-window screenshot capture also uses native `D3D12` backbuffer capture.
|
|
3. `new_editor` no longer contains any host-side `D3D11On12` or `D2D` bridge code for the main window.
|
|
4. Old hwnd `D2D` renderer code is deleted, not merely disconnected.
|
|
5. `XCUIEditorHost` no longer compiles obsolete interop units.
|
|
6. Host link dependencies only retain what is still genuinely required.
|
|
|
|
## 5. Non-Goals
|
|
|
|
- Do not roll the editor back to `D2D`.
|
|
- Do not reintroduce a fallback composition backend.
|
|
- Do not change the active `D3D12UiRenderer` architecture back into draw-data replay through another API.
|
|
- Do not remove `DirectWrite` from `D3D12UiTextSystem`; text shaping/raster generation remains valid there.
|
|
|
|
## 6. Refactor Strategy
|
|
|
|
### Phase A. Replace screenshot bridge with native D3D12 capture
|
|
|
|
Introduce a native `D3D12` capture path that reads the final swapchain backbuffer and writes PNG through CPU-side WIC encoding.
|
|
|
|
This capture path must:
|
|
|
|
- capture the final composited editor frame
|
|
- avoid `UIDrawData` replay
|
|
- avoid `D3D11On12`
|
|
- avoid `D2D`
|
|
- operate on the same swapchain backbuffer the user actually sees
|
|
|
|
Preferred integration point:
|
|
|
|
- after UI rendering has finished for the active backbuffer
|
|
- after the frame has been submitted to the queue
|
|
- before `PresentFrame()`
|
|
|
|
Reason:
|
|
|
|
- the frame is already fully rendered
|
|
- the current backbuffer is still the one about to be presented
|
|
- capture remains aligned with the user-visible final image
|
|
|
|
### Phase B. Collapse screenshot orchestration around the active D3D12 path
|
|
|
|
Rework `AutoScreenshotController` so it only:
|
|
|
|
- tracks pending capture requests
|
|
- resolves output/history paths
|
|
- finalizes success/error summaries
|
|
|
|
It must no longer own the rendering backend choice.
|
|
|
|
### Phase C. Delete obsolete NativeRenderer window-render path
|
|
|
|
Delete the old hwnd `D2D` window renderer behavior:
|
|
|
|
- `Initialize(HWND)`
|
|
- `Resize(...)`
|
|
- `Render(...)`
|
|
- hwnd render-target management
|
|
- D2D draw command replay entrypoint for window presentation
|
|
|
|
If a remaining utility is still needed after this phase, it must live in a narrowly-scoped replacement component, not inside a zombie renderer class.
|
|
|
|
### Phase D. Delete D3D11On12 interop bridge
|
|
|
|
Once native `D3D12` capture is live:
|
|
|
|
- delete `D3D12WindowInteropContext.*`
|
|
- delete `D3D12WindowInteropHelpers.h`
|
|
- delete all `NativeRenderer` interop code
|
|
|
|
### Phase E. Build and link closure
|
|
|
|
Update host build definitions so obsolete units and libraries are removed.
|
|
|
|
Expected removals if no remaining consumer exists:
|
|
|
|
- `app/Rendering/Native/NativeRenderer.cpp`
|
|
- `app/Rendering/D3D12/D3D12WindowInteropContext.cpp`
|
|
- `d2d1.lib`
|
|
- `d3d11.lib`
|
|
|
|
Expected retained dependencies:
|
|
|
|
- `d3d12.lib`
|
|
- `d3dcompiler.lib`
|
|
- `dwrite.lib`
|
|
- `dxgi.lib`
|
|
- `windowscodecs.lib`
|
|
|
|
## 7. Concrete File-Level Work
|
|
|
|
### 7.1 Add new native capture unit
|
|
|
|
Add new host-side unit(s), likely under `app/Rendering/D3D12/`:
|
|
|
|
- `D3D12WindowCapture.h`
|
|
- `D3D12WindowCapture.cpp`
|
|
|
|
Responsibilities:
|
|
|
|
- copy current swapchain backbuffer to readback
|
|
- map CPU pixels
|
|
- encode PNG via WIC
|
|
- return rich error text
|
|
|
|
### 7.2 Extend window renderer / render loop
|
|
|
|
Modify:
|
|
|
|
- `app/Rendering/D3D12/D3D12WindowRenderer.h`
|
|
- `app/Rendering/D3D12/D3D12WindowRenderer.cpp`
|
|
- `app/Rendering/D3D12/D3D12WindowRenderLoop.h`
|
|
- `app/Rendering/D3D12/D3D12WindowRenderLoop.cpp`
|
|
|
|
Needed changes:
|
|
|
|
- expose a native capture operation on the active backbuffer
|
|
- extend present result with capture outcome
|
|
- allow present flow to execute capture before `PresentFrame()`
|
|
|
|
### 7.3 Rework screenshot controller boundary
|
|
|
|
Modify:
|
|
|
|
- `app/Rendering/Native/AutoScreenshot.h`
|
|
- `app/Rendering/Native/AutoScreenshot.cpp`
|
|
- `app/Platform/Win32/EditorWindowRuntimeController.h`
|
|
- `app/Platform/Win32/EditorWindowRuntimeController.cpp`
|
|
- `app/Platform/Win32/EditorWindow.cpp`
|
|
|
|
Needed changes:
|
|
|
|
- stop passing `UIDrawData` into screenshot rendering
|
|
- stop depending on `NativeRenderer`
|
|
- move screenshot triggering into the D3D12 present path
|
|
|
|
### 7.4 Delete obsolete renderer/interop code
|
|
|
|
Delete if fully unreferenced after the above:
|
|
|
|
- `app/Rendering/Native/NativeRenderer.h`
|
|
- `app/Rendering/Native/NativeRenderer.cpp`
|
|
- `app/Rendering/Native/NativeRendererHelpers.h`
|
|
- `app/Rendering/D3D12/D3D12WindowInteropContext.h`
|
|
- `app/Rendering/D3D12/D3D12WindowInteropContext.cpp`
|
|
- `app/Rendering/D3D12/D3D12WindowInteropHelpers.h`
|
|
|
|
### 7.5 Build-system cleanup
|
|
|
|
Modify:
|
|
|
|
- `new_editor/CMakeLists.txt`
|
|
|
|
Remove:
|
|
|
|
- old source units
|
|
- dead link libraries
|
|
|
|
## 8. Validation Requirements
|
|
|
|
### 8.1 Build validation
|
|
|
|
Must build:
|
|
|
|
- `XCUIEditorHost`
|
|
- `XCUIEditorAppLib`
|
|
- `XCUIEditorApp`
|
|
|
|
### 8.2 Runtime validation
|
|
|
|
Must validate:
|
|
|
|
1. editor launches normally
|
|
2. main window still presents correctly
|
|
3. manual screenshot still succeeds
|
|
4. startup auto-capture still succeeds if enabled
|
|
5. no screenshot path closes or stalls the main window unexpectedly
|
|
|
|
### 8.3 Structural validation
|
|
|
|
Searches after completion must show:
|
|
|
|
- no `NativeRenderer` references in `new_editor/app`
|
|
- no `D3D12WindowInteropContext` references in `new_editor`
|
|
- no `D3D11On12` references in `new_editor`
|
|
- no `ID2D` / `D2D1` references in `new_editor/app`
|
|
|
|
Exception:
|
|
|
|
- `DirectWrite` references inside `D3D12UiTextSystem` remain allowed
|
|
|
|
## 9. Execution Order
|
|
|
|
1. Add native `D3D12` backbuffer capture path.
|
|
2. Route `AutoScreenshotController` through that new path.
|
|
3. Remove runtime-controller dependence on `NativeRenderer`.
|
|
4. Delete `NativeRenderer` and `D3D12WindowInteropContext`.
|
|
5. Clean CMake/link dependencies.
|
|
6. Build and smoke-test.
|
|
7. Run structural grep validation.
|
|
|
|
## 10. Success Criteria
|
|
|
|
This plan is complete only if all of the following are true:
|
|
|
|
- screenshots come from the native `D3D12` backbuffer path
|
|
- no main-window host rendering code path can fall back to `D2D`
|
|
- no `D3D11On12` bridge remains in `new_editor`
|
|
- old dead window-render code is physically removed
|
|
- build and smoke validation pass
|