|
| 1 | +# IRenderBackend / DX9Ex — branch base and known gaps |
| 2 | + |
| 3 | +`topic/dx9ex` is currently stacked on `bobtista/feat/render-backend-interface-skeleton` |
| 4 | +(the 11-commit foundational IRenderBackend + DX8Backend adapter), **not** on |
| 5 | +`bobtista/topic/render-backend-interface` (PR #2613). This file tracks why, and |
| 6 | +what that trade gives up so it can be picked back up deliberately instead of |
| 7 | +by accident. |
| 8 | + |
| 9 | +## Why skeleton instead of PR #2613's branch |
| 10 | + |
| 11 | +`topic/render-backend-interface` has a real bug on its current tip |
| 12 | +(`c2435cbb5`, confirmed against a fresh fetch, not a stale local ref): |
| 13 | +`W3DShaderManager.cpp` calls `g_renderBackend->Override_Terrain_Blend(...)`, |
| 14 | +`Override_Texcoord_Index(...)`, `Override_Alpha_Blend_Enable(...)`, and |
| 15 | +`Override_Blend(...)` (introduced in commit `6a5409977`, |
| 16 | +"feat(ww3d2): extend IRenderBackend with ZBias/FillMode/DepthTest/DepthFunc/ColorWriteMask |
| 17 | +and migrate callers"), but none of those four methods were ever declared on |
| 18 | +`IRenderBackend`. It does not compile on Windows/MSVC as-is. |
| 19 | + |
| 20 | +Given a choice between fixing that upstream bug in place vs. starting the |
| 21 | +DX9Ex work clean, the decision was to rebuild the small DX9Ex-specific surface |
| 22 | +(`DX9ExBackend.cpp/h`, `RenderBackend.cpp` factory wiring, `GlobalData.h` |
| 23 | +selection enum, `cmake/dx9.cmake`) directly against skeleton, mirroring |
| 24 | +`DX8Backend.cpp/h` 1:1, rather than merge/cherry-pick the old work forward. |
| 25 | + |
| 26 | +## What skeleton does NOT have (known gaps, in case they matter later) |
| 27 | + |
| 28 | +### Caller migrations (the actual reason topic/render-backend-interface exists) |
| 29 | + |
| 30 | +These commits, present on `topic/render-backend-interface` but **not** on |
| 31 | +skeleton, migrated dozens of call sites off `DX8Wrapper::Set_DX8_Render_State` |
| 32 | +and onto `g_renderBackend`. Without them, terrain shading, shroud rendering, |
| 33 | +and screen filters in `W3DShaderManager.cpp` / `W3DShroud.cpp` still talk to |
| 34 | +`DX8Wrapper`/D3D8 directly, so a non-DX8 backend (bgfx, or eventually a real |
| 35 | +DX9Ex device) will not actually intercept those draws: |
| 36 | + |
| 37 | +- `cf12396ea` — route W3D subsystems and shadow/scene callers through |
| 38 | + `g_renderBackend`; extends `IRenderBackend` with blend/stencil/cursor/alpha |
| 39 | + state (`Set_Blend_Op`, `Set_Blend_Factors`, `Set_Color_Write_Enable`, |
| 40 | + `Set_Alpha_Blend_Enable`, `Show_Hardware_Cursor`, |
| 41 | + `Set_Hardware_Cursor_Image/Position`, `Set_Stencil_*`). |
| 42 | +- `10d5d6636` — deprecate remaining `DX8Wrapper` game-code callers in favor of |
| 43 | + `IRenderBackend`. |
| 44 | +- `6a5409977` — extends `IRenderBackend` with `Set_Z_Bias`, `Set_Fill_Mode`, |
| 45 | + `Set_Depth_Test_Enable`, `Set_Depth_Write_Enable`, `Set_Depth_Func`, |
| 46 | + `Set_Color_Write_Mask`; migrates `W3DShaderManager.cpp` callers. **Also |
| 47 | + introduces the four undeclared `Override_*` calls — the bug above.** |
| 48 | +- `b0084567c` — routes `W3DShroud`'s texture upload through |
| 49 | + `IRenderBackend::Upload_Texture_Region` (POOL_DEFAULT surfaces can't be |
| 50 | + locked directly). |
| 51 | +- `951a79613` — null-guards `g_renderBackend` in `addShadow` and shroud |
| 52 | + render paths. |
| 53 | + |
| 54 | +Net effect: skeleton's `IRenderBackend` has **52 virtual methods**; the |
| 55 | +current PR #2613 tip has **74** (plus the 4 that should exist but don't). |
| 56 | + |
| 57 | +### General upstream drift (unrelated to rendering) |
| 58 | + |
| 59 | +Skeleton's merge-base with `upstream/main` is the same commit as its |
| 60 | +merge-base with `topic/render-backend-interface` (`fe72137f3`) — skeleton was |
| 61 | +branched once and never rebased forward. As of this writing it is **42 |
| 62 | +commits behind `upstream/main`**, vs. 14 for the PR #2613 branch (which has |
| 63 | +been periodically rebased — its commits carry "(cherry picked from commit |
| 64 | +...)" notes). Notable things missing from skeleton as a result, in case a |
| 65 | +conflict or missing symbol traces back here: |
| 66 | + |
| 67 | +- SDL3 windowing backend (`GeneralsMD/Code/Main/SDL3Main.cpp`, ~286 lines, |
| 68 | + doesn't exist on skeleton at all). |
| 69 | +- OpenAL audio manager (device/source/stream management, decoded-PCM sample |
| 70 | + cache) and FFmpeg movie-audio wiring. |
| 71 | +- macOS build/deploy scripts (`scripts/build/macos/*`), `docs/BUILD/GETTING_THE_GAME_FILES.md`. |
| 72 | +- `cmake/bgfx.cmake`, `cmake/openal.cmake`, `cmake/sdl3.cmake`. |
| 73 | +- A batch of `unify(*)`: Move-to-Core commits (ww3d2, particlesys, bezier, |
| 74 | + commandline, precompiled, etc.) and assorted bugfixes (see |
| 75 | + `git log --oneline remotes/bobtista/bobtista/feat/render-backend-interface-skeleton..upstream/main` |
| 76 | + for the full list of 42). |
| 77 | +- `BgfxBackend.cpp/h` exist on skeleton as files but are **not wired into** |
| 78 | + `RenderBackend.cpp`'s factory (no `#if defined(GGC_RENDER_BACKEND_BGFX)` |
| 79 | + branch there, unlike PR #2613). |
| 80 | + |
| 81 | +## Current state of DX9ExBackend (as of this handoff) |
| 82 | + |
| 83 | +`Backend/DX9ExBackend.cpp/h` now has a **real device lifecycle**: |
| 84 | +`Initialize(window, width, height)` dynamically loads `d3d9.dll`, resolves |
| 85 | +`Direct3DCreate9Ex` via `GetProcAddress`, and calls it — **forced, no |
| 86 | +fallback to plain `Direct3DCreate9`** (explicit decision: systems without |
| 87 | +D3D9Ex support should select `-dx8`/`GraphicsBackend=DX8` instead of silently |
| 88 | +downgrading). On success it calls `CreateDeviceEx` with |
| 89 | +`D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | |
| 90 | +D3DCREATE_FPU_PRESERVE`, windowed-only, backbuffer format taken from |
| 91 | +`GetAdapterDisplayModeEx`, depth/stencil `D3DFMT_D24S8` with a `D3DFMT_D16` |
| 92 | +fallback if the driver can't do D24S8. `Shutdown()` releases both the device |
| 93 | +and the `IDirect3D9Ex` interface. This is entirely self-contained — it does |
| 94 | +**not** touch `DX8Wrapper`'s device or any of its static state. |
| 95 | + |
| 96 | +Also implemented for real against the D3D9Ex device: `Begin_Scene`/ |
| 97 | +`End_Scene` (via `PresentEx`, device-lost detected from the `HRESULT`)/ |
| 98 | +`Clear`/`Set_Viewport`/`Set_Transform`/`Get_Transform` (world/view/projection, |
| 99 | +using the existing backend-agnostic `To_D3DMATRIX`/`To_Matrix4x4` helpers |
| 100 | +from `WWMath/matrix4.h` — those already work with D3D9's `D3DMATRIX` since |
| 101 | +the struct layout is identical between the D3D8 and D3D9 headers)/ |
| 102 | +`Set_Light`/`Set_Ambient`/`Set_Fog`/`Set_Gamma`. World/view identity tracking |
| 103 | +is a plain bool pair owned by the backend instance (not shared with |
| 104 | +`DX8Wrapper::render_state`, deliberately — see Phase 0 in |
| 105 | +`BACKEND_AGNOSTIC_RESOURCES_PLAN.md`). |
| 106 | + |
| 107 | +**Still stubbed (empty bodies), matching `BgfxBackend`'s precedent, because |
| 108 | +they need real D3D9 resources and `VertexBufferClass`/`IndexBufferClass`/ |
| 109 | +`TextureBaseClass`/`SurfaceClass` are still hard-typed to D3D8 COM |
| 110 | +interfaces:** `Set_Vertex_Buffer` (both overloads), `Set_Index_Buffer` (both |
| 111 | +overloads), `Set_Index_Buffer_Index_Offset`, `Set_Shader`, `Get_Shader`, |
| 112 | +`Set_Material`, `Set_Texture`, `Apply_Render_State_Changes`, |
| 113 | +`Invalidate_Cached_Render_States`, `Draw_Triangles` (both overloads), |
| 114 | +`Draw_Strip`, `Set_Vertex_Shader`, `Set_Pixel_Shader`, `Create_Render_Target`, |
| 115 | +`Set_Render_Target_With_Z`, `Is_Render_To_Texture`, `Set_Shadow_Map`, |
| 116 | +`Get_Shadow_Map`. `Get_Back_Buffer`/`Get_Back_Buffer_Format` are also stubbed |
| 117 | +for the same reason (would need to wrap `IDirect3DSurface9`/convert |
| 118 | +`D3DFORMAT` — no `SurfaceClass`/`WW3DFormat` conversion path exists for D3D9 |
| 119 | +yet). |
| 120 | + |
| 121 | +## NOT done yet — explicit gaps at handoff |
| 122 | + |
| 123 | +1. **`cmake/dx9.cmake` is not wired into the build at all.** Nothing includes |
| 124 | + it from top-level `CMakeLists.txt` (unlike `cmake/dx8.cmake`, included at |
| 125 | + line ~55 next to `miles.cmake`/`bink.cmake`), and nothing links its |
| 126 | + exposed `d3d9`/`dx9` targets into `corei_ww3d2` |
| 127 | + (`Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt`). **This means |
| 128 | + `DX9ExBackend.cpp`'s `#include <d3d9.h>` will not resolve and the current |
| 129 | + commit has NOT been compile-verified.** This is the first thing the next |
| 130 | + session needs to fix before anything else here can be trusted. |
| 131 | +2. **VC6 guard is not in place.** `Backend/DX9ExBackend.cpp/h` are |
| 132 | + unconditionally listed in `Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt` |
| 133 | + — nothing excludes them from `IS_VS6_BUILD`. VC6 cannot compile against |
| 134 | + modern D3D9 headers; these two files (and the `cmake/dx9.cmake` include |
| 135 | + once wired) need to be gated the same way `cmake/dx8.cmake` vs. |
| 136 | + `cmake/stlport.cmake` already branch on `IS_VS6_BUILD` in the top-level |
| 137 | + `CMakeLists.txt`. |
| 138 | +3. **Default backend selection is not implemented.** The requested behavior |
| 139 | + (DX9Ex default on modern compilers, DX8 the only option on VC6, both |
| 140 | + available as a build/runtime option on modern compilers) has no code yet. |
| 141 | + `RenderBackend.cpp`'s `#if defined(GGC_RENDER_BACKEND_DX9EX)` exists but |
| 142 | + nothing defines that macro anywhere — today every build silently gets |
| 143 | + `DX8Backend` regardless of compiler. Needs a `cmake` option (e.g. in |
| 144 | + `cmake/config-build.cmake`) that defaults ON when `NOT IS_VS6_BUILD` and |
| 145 | + is forced OFF (or not even offered) when `IS_VS6_BUILD`. |
| 146 | +4. **The `-dx8`/`-dx9ex` command-line flags and `Options.ini` |
| 147 | + `GraphicsBackend` runtime parsing** (item 3 of the original implementation |
| 148 | + plan) still don't exist — `GlobalData::m_renderBackend` is declared but |
| 149 | + nothing reads or writes it. Right now backend selection can only ever be |
| 150 | + compile-time (once item 3 above lands). |
| 151 | +5. **Resource-class work** (`BACKEND_AGNOSTIC_RESOURCES_PLAN.md` Phases 1-2) |
| 152 | + hasn't started. Until then, `DX9ExBackend` can create a real device, clear |
| 153 | + the screen, and set transforms/lights, but cannot draw any actual game |
| 154 | + geometry (no vertex/index/texture binding). |
| 155 | +6. **Caller-migration gap** (this file's earlier section) is unchanged: even |
| 156 | + once resource classes are fixed, `W3DShaderManager.cpp`/`W3DShroud.cpp` |
| 157 | + etc. still call `DX8Wrapper` directly for blend/stencil/cursor/terrain |
| 158 | + state, bypassing `g_renderBackend` entirely, because skeleton never got |
| 159 | + those caller-migration commits. |
| 160 | + |
| 161 | +## Next steps, roughly in order |
| 162 | + |
| 163 | +1. Wire `cmake/dx9.cmake` into the top-level `CMakeLists.txt` (guarded by |
| 164 | + `NOT IS_VS6_BUILD`, next to `include(cmake/dx8.cmake)`) and link its |
| 165 | + exposed target(s) into `corei_ww3d2`. **Compile-verify `DX9ExBackend.cpp` |
| 166 | + for the first time** — it has not built successfully yet. |
| 167 | +2. Exclude `Backend/DX9ExBackend.cpp/h` from VC6 builds in |
| 168 | + `Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt`. |
| 169 | +3. Add the cmake option + `#define GGC_RENDER_BACKEND_DX9EX` default-on for |
| 170 | + modern compilers, off for VC6, so `RenderBackend.cpp`'s existing |
| 171 | + `#if`/`#else` actually does something. |
| 172 | +4. Add the `-dx8`/`-dx9ex` command-line flags and `Options.ini` |
| 173 | + `GraphicsBackend` parsing that select `GGC_RENDER_BACKEND_DX9EX` / |
| 174 | + `TheGlobalData->m_renderBackend` at runtime. |
| 175 | +5. Start `BACKEND_AGNOSTIC_RESOURCES_PLAN.md` Phase 1 (`VertexBufferClass`/ |
| 176 | + `IndexBufferClass` — additive, no base-class changes needed) so |
| 177 | + `DX9ExBackend` can actually bind and draw geometry. |
| 178 | +6. Decide whether to re-derive the caller-migration commits (blend/stencil/ |
| 179 | + cursor/terrain-override plumbing) on top of this branch, or accept that |
| 180 | + DX9Ex — like skeleton's DX8Backend — won't actually see those draw calls |
| 181 | + until that's done. |
0 commit comments