DirectX 8 (IDirect3D8/IDirect3DDevice8, DXVK-delivered, fixed-function) Graphics Backend — Implementation Plan
Status (2026-07-21): DONE.
DX8-0existence-gate spike complete; implementation phases T1-T8 all complete, built, and verified: 20/20DX8-labeled CTests pass (Dx8_LegacyInterfaceDiscipline+ 19 example-based tests), no new regressions in the cross-backend suite (GraphicsBackendCompileDefinitionsTest/GraphicsDeviceValidationTest/GraphicsDeviceCapabilityTest— the only 3 failures are the same pre-existing, ungatedGraphicsDeviceCapabilityTest.SupportsMultipleRenderTargets/SupportsOcclusionQuery/SupportsCustomEffectsgap shared by every DX2/DX3/DX5/DX6/DX7/DX8 backend equally, not introduced here). Two real bugs found only by the full test suite, beyond theDX8-0spike's own findings, are recorded indx8-spike/README.md's "Two further runtime bugs" section: (1) a realDx8GraphicsBackend::SetVirtualResolutionbug (the logical render target was created once at construction and never resized to match a laterGraphicsDeviceManager-requested resolution, causingReadBackbuffer'sCopyRectsto fail with a real size mismatch) -- now fixed by havingSetVirtualResolutionactually recreate the logical texture/surface/depth-stencil at the new size; (2) two environment-specific Wine/DXVK/AMD-RADV-driver bugs unrelated to this backend's own code, both worked around inscripts/run-wine-dx8.sh(a dedicated~/.wine-cna-dx8Wine prefix withdxgideliberately NOT overridden to DXVK, andDXVK_FILTER_DEVICE_NAME=llvmpipeto avoid a real RADV driver bug on the second consecutivePresent()call). A real D3D8 XYZRHW half-texel alignment fix (Dx8SpriteBatchBackend::Draw/Present's own quad corners, matching D3D9 SpriteBatch's equivalent projection-matrix-baked correction) was also needed and applied.
- New backend:
CNA_GRAPHICS_BACKEND=DX8. No temporary-naming concern. - Scope decision, made with the project owner before any code was written: fixed-function 3D
only, matching
DX1..DX7's own CPU-transform-and-submit shape — NOT real Shader Model 1.x programmable shaders.docs/directx-legacy-backends-analysis.md§3.1 already notes real XNA effects (BasicEffect/SkinnedEffect/etc.) needps_2_0+ regardless of SM1.x support, soCreateEffectBackendwould still have to throw for any real XNA content even with a full SM1.x pipeline — building one would not make this backend usable for actual CNA content, only bigger. - DX8 is architecturally very different from every backend in this family so far — see §1 for
the full delta list. The headline changes: no DirectDraw at all ("DirectDraw+Direct3D merged");
delivered via DXVK (not Wine's own
ddraw.dll/d3d8.dll), the same Route B delivery mechanismD3D9/D3D11/D3D12already use, reusing DXVK's reald3d8.dll(D8VK, merged into DXVK 2.0+);D3DTLVERTEX/D3DFVF_TLVERTEXno longer exist in the real headers (the FVF values do); render states renamedD3DRENDERSTATE_*→D3DRS_*(same underlying enum values);DrawPrimitiveUP/DrawIndexedPrimitiveUPreplace the old CPU-pointer submission, gated behind a real, confusing D3D8-only idiom (SetVertexShader(rawFvfValue)); noGetRenderTargetData(readback usesCreateImageSurface+CopyRectsinstead). - A real, empirically found build-environment gap: mingw-w64's x86_64 target ships NO real
d3d8import library at all (only the unrelatedlibd3d8thk.a"thunk" library) — only the 32-bit/i686 target has one. DXVK's own/usr/lib/dxvk/wine64/d3d8.dll.aexports the realDirect3DCreate8symbol and is linked against directly instead — no 32-bit cross-compile needed. The packageddxvk-setupscript's hardcoded DLL list also predates D8VK's merge into DXVK and never installsd3d8— added by hand to~/.wine-cna-d3d11(the same prefixD3D9/D3D11/D3D12already use), mirroringdxvk-setup's owninstall_dllsteps exactly. - A real, empirically found API bug, fixed in the spike, not just discovered and left:
D3DPRESENT_PARAMETERS.FullScreen_PresentationIntervalmust beD3DPRESENT_INTERVAL_DEFAULT(0) for windowed mode —D3DPRESENT_INTERVAL_IMMEDIATEthere causesCreateDeviceto fail withD3DERR_INVALIDCALL(real DXVK/D3D8-compat validation, not a Wine bug). - The whole 2D
SpriteBatchcompositor is redesigned, not ported.DX1..DX7all used DirectDraw'sBlt/BltFastfor a CPU-side pixel compositor specifically because DirectDraw offers no other option and has real historical rotation limits. D3D8 has NO DirectDraw at all — every CNA backend that already targets a real GPU device without DirectDraw (D3D9/D3D11/EasyGL/Vulkan/etc.) implementsSpriteBatchas real GPU-rendered textured quads with real alpha blending instead of a CPU compositor, andDX8follows that same established pattern — just through the fixed-functionSetTextureStageState/render-state pipeline instead of pixel shaders. This is a genuine, deliberate architectural difference from this family's ownDX1-DX72D layer, not an oversight. - Everything else keeps the same spirit as
DX1..DX7: CPU-side transform + near-plane clip + fixed-function submission for 3D geometry (the exact same math, re-expressed against the newDx8TLVertexstruct/DrawIndexedPrimitiveUPcall shape), CPU-sideVertexBuffer/IndexBufferstorage (Phase O5's own pattern), real stencil (unchanged in shape fromDX6/DX7), same lighting/fog/multitexture/envMap/skinning boundary as the rest of this family post-Phase-O9.
| Layer | Symbol(s) used | Introduced in | Never used here |
|---|---|---|---|
| Device + swap chain | IDirect3D8, IDirect3DDevice8, D3DPRESENT_PARAMETERS (via Direct3DCreate8) |
DX8 SDK — new, real, DXVK-delivered | IDirectDraw* (does not exist at all at this era) |
| Delivery mechanism | DXVK's own /usr/lib/dxvk/wine64/d3d8.dll.a/d3d8.dll.so (D8VK, merged into DXVK 2.0+) |
New for this family — same Route B pattern D3D9/D3D11/D3D12 already use |
Wine's own built-in d3d8.dll (WineD3D) — explicitly gated against via a DXVK-engagement log check, mirroring D3D9's own run-wine-dxvk9.sh gate |
| Vertex submission | SetVertexShader(rawFvfValue) + DrawPrimitiveUP/DrawIndexedPrimitiveUP |
DX8 SDK — new signature/idiom, real | DrawPrimitive/DrawIndexedPrimitive (require a bound vertex buffer via SetStreamSource, not used for the CPU-submission path this family's design relies on) |
| Vertex format | Hand-defined Dx8TLVertex struct (same byte layout the old D3DTLVERTEX macro implied) + D3DFVF_XYZRHW/DIFFUSE/SPECULAR/TEX1 |
FVF values unchanged since DX5 SDK; the canned struct/macro is GONE | D3DTLVERTEX, D3DVT_* (neither exists in the real headers any more) |
| Render states | D3DRS_* naming (same D3DRENDERSTATETYPE enum values as D3DRENDERSTATE_*) |
DX8 SDK — naming convention change only | D3DRENDERSTATE_* names |
| Texture blending | SetTextureStageState/D3DTSS_COLOROP/D3DTOP_MODULATE |
Real since DX6 SDK, used here from the start | D3DRENDERSTATE_TEXTUREHANDLE/D3DRENDERSTATE_TEXTUREMAPBLEND (gone; DX7-0 already found the latter rejected outright on that device revision) |
| Texture/render-target objects | IDirect3DTexture8, IDirect3DSurface8 (via CreateTexture/CreateRenderTarget/CreateDepthStencilSurface) |
DX8 SDK — real Direct3D resources, no DirectDraw surface involved at all | IDirectDrawSurface* |
| Readback | CreateImageSurface (lockable system-memory surface) + CopyRects from the real back buffer |
DX8 SDK shape (GetRenderTargetData is D3D9-only, not used) |
GetRenderTargetData |
| Stencil | D3DRS_STENCILENABLE/etc. against a D3DFMT_D24S8 auto-depth-stencil surface |
Unchanged in shape from DX6/DX7 |
Two-sided stencil (still a D3D9-era addition) |
| 2D compositor | Real GPU-rendered textured quads through the SAME fixed-function pipeline as 3D geometry, real D3DRS_ALPHABLENDENABLE/SRCBLEND/DESTBLEND |
Redesigned for this backend — matches D3D9/EasyGL/etc.'s own established GPU-quad SpriteBatch pattern |
DirectDraw Blt/BltFast (does not exist at all at this era) |
| Shaders | (none) | DX8 SDK adds Shader Model 1.x (VS 1.1/PS 1.0-1.4) — deliberately not used, scope decision above | CreateVertexShader/SetVertexShaderConstant/pixel shaders |
Confirmed present in this environment's MinGW-w64 headers + DXVK before writing this plan:
d3d8.h/d3d8types.h/d3d8caps.h (all real, x86_64-buildable), Direct3DCreate8 (exported by
DXVK's own d3d8.dll.a, not by any MinGW x86_64 import library), D3DRS_* render states
(identical enum values to D3DRENDERSTATE_*), D3DTSS_COLOROP/D3DTOP_MODULATE,
DrawPrimitiveUP/DrawIndexedPrimitiveUP, CreateImageSurface/CopyRects,
D3DPRESENT_INTERVAL_DEFAULT/IMMEDIATE (in d3d8caps.h, not d3d8types.h).
| # | Spike | What it proves | Result |
|---|---|---|---|
DX8-0a |
Direct3DCreate8 + IDirect3D8::CreateDevice via the DXVK-installed d3d8.dll |
Whether real device creation works through DXVK | ✅ Works — DXVK log confirms genuine engagement ("D3D9DeviceEx", "operating in D3D8 compatibility mode") |
DX8-0b |
Clear(rect_count=0, rects=nullptr, TARGET|ZBUFFER|STENCIL, ...) |
Whether count=0 clears the WHOLE target (D3D9 convention) or nothing (the DX5-DX7 Clear2 gotcha) |
✅ Clears everything — exact (10,10,10) readback |
DX8-0c |
SetVertexShader(rawFvfValue) + DrawIndexedPrimitiveUP — Gouraud quad, no vertex buffer |
Whether the FVF-via-SetVertexShader idiom actually works | ✅ Works — real Gouraud interpolation confirmed |
DX8-0d |
DrawPrimitiveUP, far(blue)-then-near(red) overlapping triangles, D3DRS_ZENABLE=TRUE |
Whether real Z-test occlusion works | ✅ Works — exact red readback (near wins) |
DX8-0e |
CreateTexture + SetTexture + SetTextureStageState(D3DTSS_COLOROP, D3DTOP_MODULATE) |
Whether the modern stage-state texture mechanism works from the start (pre-empting DX7-0's own legacy-render-state rejection) |
✅ Works — exact solid-red readback, first try |
DX8-0f |
Stencil write (left-half quad, STENCILPASS=REPLACE) then test (STENCILFUNC=EQUAL, full-screen quad) |
Whether real stencil write+test works | ✅ Works — exact green/black after write, red/black after test |
DX8-0g |
Present() with a real window |
Whether the real DXVK-backed swap chain presents without error | ✅ Works — real Vulkan swapchain confirmed in the log |
One real bug found and fixed: D3DPRESENT_PARAMETERS.FullScreen_PresentationInterval must be
D3DPRESENT_INTERVAL_DEFAULT for windowed mode — D3DPRESENT_INTERVAL_IMMEDIATE there caused
CreateDevice to fail with D3DERR_INVALIDCALL (real DXVK/D3D8-compat validation). After that one
fix, every remaining test passed on the very next run — no further spike-authoring bugs. See
dx8-spike/README.md for the full record.
Net effect: fixed-function DX8, delivered via DXVK, is real and fully confirmed. Phase T1 is unblocked.
-
Platform gate, same as
D3D9/D3D11/D3D12/DX1..DX7. Same Windows-native-or-MinGW- cross-compileFATAL_ERRORgate (d3d8.his equally Windows-only). -
Delivery: DXVK, not Wine's own
d3d8.dll. Link against DXVK's own/usr/lib/dxvk/wine64/d3d8.dll.adirectly (spike-confirmed,DX8-0a) since mingw-w64's x86_64 target ships no real d3d8 import library. Runtime:~/.wine-cna-d3d11(shared withD3D9/D3D11/D3D12) withd3d8added as a native DLL override by hand (the packageddxvk-setupscript predates D8VK and never installs it).scripts/run-wine-dx8.shgates on a real DXVK-engagement log line, mirroringrun-wine-dxvk9.sh's own gate — never silently fall back to testing WineD3D's own (different) D3D8 implementation. -
Device bring-up: modeled on
D3D9GraphicsBackend's own shape, notDX1..DX7's DirectDraw-based one. A singleDirect3DCreate8+IDirect3D8::CreateDevice(D3DADAPTER_ DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &pp, &device)call, with a real Win32HWND(sameSDL_PROP_WINDOW_WIN32_HWND_POINTERtechnique every Windows-only backend in this project already uses).D3DCREATE_SOFTWARE_VERTEXPROCESSING(not hardware) is deliberate: this backend does no GPU T&L at all (CPU pre-transform, decision 8), so requesting hardware vertex processing would buy nothing and risks failing on a device that only advertises software vertex processing. -
D3DPRESENT_PARAMETERSconstruction rules, spike-confirmed (DX8-0):Windowed=TRUE,SwapEffect=D3DSWAPEFFECT_DISCARD,EnableAutoDepthStencil=TRUEwithAutoDepthStencilFormat=D3DFMT_D24S8(a real combined depth+stencil format, matchingDX6/DX7's own stencil capability), and — the one real bug found —FullScreen_PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT(neverIMMEDIATE/ONE/etc. in windowed mode; that field is fullscreen-only despite compiling fine either way). -
Clearuses the D3D9-stylecount=0-clears-everything convention (spike-confirmed,DX8-0b) — no repeat ofDX5-DX7's ownIDirect3DViewport::Clear2"must always pass an explicit full-surfaceD3DRECT" gotcha; this device revision'sCleardoesn't need it. -
Vertex submission:
SetVertexShader(rawFvfValue)once per FVF change, thenDrawPrimitiveUP/DrawIndexedPrimitiveUPper draw — no vertex buffer object involved for the CPU-submission draw path (matching this family's ownVertexBuffer/IndexBufferdesign, decision 10). Spike-confirmed (DX8-0c) real. A hand-definedDx8TLVertexstruct (sx,sy,sz, rhw: 4 floats;color,specular: 2D3DCOLORs;tu,tv: 2 floats — 32 bytes, identical byte layout to the now-goneD3DTLVERTEXmacro) replaces the removed struct. -
Texture binding and blending:
SetTexture(stage, texture8)+SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE)— the same modern mechanismDX7's own design decision 6 uses, applied here from the start (spike-confirmed,DX8-0e, no repeat ofDX7-0's own legacy-render-state-rejection surprise). Textures are realIDirect3DTexture8objects (viaCreateTexture), not DirectDraw surfaces at all — this backend'sDx8TextureBackend/Dx8RenderTargetBackendown real Direct3D resources directly. -
CPU transform + near-plane clip + fixed-function submission for 3D geometry: same architecture as
DX1..DX7, re-expressed againstDx8TLVertex/DrawIndexedPrimitiveUPinstead ofD3DTLVERTEX/DrawIndexedPrimitive. WorldViewProjection computed on the CPU, Sutherland-Hodgman near-plane clip (single plane), perspective divide, pack into screen-spaceDx8TLVertex. Same Phase O9 CPU-sideBasicEffectlighting math (ambient + directional Lambertian/Blinn-Phong specular). No GPU T&L at all (decision 3) — matching every backend in this family's own design, not a missed opportunity: Shader Model 1.x vertex shaders exist for real GPU T&L, but scope decision (TL;DR) already ruled that out. -
Stencil: real, same shape as
DX6/DX7, unchanged.D3DRS_STENCILENABLE/FUNC/FAIL/ZFAIL/PASS/REF/MASK/WRITEMASKagainst theD3DFMT_D24S8auto-depth-stencil surface (decision 4).twoSidedStencilMode/ccwStencil*remain accepted-and-ignored — still a D3D9-era addition, still doesn't exist at this DirectX era. -
VertexBuffer/IndexBuffer: plain CPU-side storage (Dx8VertexBufferBackend/Dx8IndexBufferBackend), matching this family's own Phase O5 pattern (and theSoftwarebackend's identical approach) — the CPU transform pipeline reads directly from these buffers each draw, so there is no GPU-side object to upload to for the fixed-function draw path. -
2D
SpriteBatch: REDESIGNED as real GPU-rendered textured quads, not a DirectDraw-Blt-based CPU compositor.DX1..DX7all usedIDirectDrawSurface*::Blt/BltFastspecifically because DirectDraw offers no other option and has real historical rotation limits (documented per-backend). D3D8 has NO DirectDraw at all — every CNA backend that already targets a real GPU device without DirectDraw (D3D9/EasyGL/Vulkan/etc.) implementsSpriteBatchas real GPU-rendered textured quads with real alpha blending, andDX8follows that same established pattern instead, through the fixed-function pipeline (realD3DRS_ALPHABLENDENABLE/SRCBLEND/DESTBLENDstate, realD3DTSS_COLOROPtexture modulation) rather than pixel shaders. Rotation, scaling, and all 4BlendStatepresets are real GPU features here, not a CPU-approximated formula per mode — a genuine capability improvement overDX1..DX7's own 2D layer, not merely a reimplementation. -
Readback:
CreateImageSurface(lockable system-memory surface) +CopyRectsfrom the real back buffer —GetRenderTargetDatais a D3D9-only addition, not available here. Spike-confirmed (DX8-0throughout — every readback in the spike used exactly this mechanism). -
32-bit surfaces only,
DirectSound/DirectInput/DirectPlayout of scope, header containment (d3d8.hconfined toDx8GraphicsBackend.cpp, matchingD3D9's own convention), CMake integration shape — identical philosophy to earlier plans in this family. -
CMake integration: add
"DX8"toCNA_GRAPHICS_BACKEND'sSTRINGSproperty + aCNA_BACKEND_DX8option; acna_backend_graphics_dx8static library target undersrc/CNA/Internal/Backends/Dx8/, same Windows-onlyFATAL_ERRORgate. Link set: DXVK's own d3d8 import library (via an explicit path/imported target, NOT the bared3d8name any MinGW system library search would resolve to nothing) +SDL3::SDL3. Nodxguid(D3D8 has no COM GUIDs requiring it the wayddraw/legacyIDirect3D*interfaces did —Direct3DCreate8is a plain exported function, not aCoCreateInstance-style GUID lookup). -
Testing:
scripts/run-wine-dx8.sh, modeled onscripts/run-wine-dxvk9.sh— same~/.wine-cna-d3d11prefix, same DXVK-engagement log-line gate (a"DXVK: <version>"line, not thetrace:ddraw:gateDX1..DX7's own scripts use, since this backend has no DirectDraw at all). -
No legacy-interface code, no execute-buffer code, no DirectDraw code, proven by discipline. A new execute-buffer/legacy-interface discipline check (
scripts/check-dx8-legacy-interface-discipline.sh) forbids anyIDirectDraw*symbol at all (a real, automated proof this backend never reaches for the family's own DirectDraw-based lineage), anyD3DTLVERTEX/D3DVT_*symbol (doesn't exist in the real headers, but guards against a future accidental copy-paste from an earlier backend), and the legacyD3DRENDERSTATE_*naming (this backend uses onlyD3DRS_*, matching decision 14's header containment goal of never mixing eras). A newDx8_StencilCTest proves real stencil write-then-test through the full XNA public API, mirroringDX6/DX7's own shape.
DX8-0(existence-gate spike, §2) — done, unblocks everything else.- Phase T1 (CMake integration + skeleton, decisions 2/14).
- Phase T2 (device/window bring-up:
Direct3DCreate8+CreateDevice, decisions 3/4). - Phase T3 (2D layer: real GPU-quad
SpriteBatch, textures/render targets as real Direct3D8 resources, decisions 7/11/12). - Phase T4 (3D device state: Z-buffer/stencil already attached via
D3DPRESENT_PARAMETERS,Clear/ClearDepth/etc., decisions 4/5/9). - Phase T5 (CPU transform/clip pipeline + Phase-O9 lighting + fixed-function submission, decisions 6/8).
- Phase T6 (
VertexBuffer/IndexBufferbackends, decision 10). - Phase T7 (state mapping including real stencil, decision 9; remaining
IGraphicsBackenddefaults). - Phase T8 (tests +
docs/dx8-backend.md, including the newDx8_StencilCTest).
For every task: build the affected target (-DCNA_GRAPHICS_BACKEND=DX8, MinGW cross-compile), run
the relevant CTest through scripts/run-wine-dx8.sh, and do not mark a task ✅ without both
actually passing.
| # | Task | Status | Notes |
|---|---|---|---|
DX8-1 |
Add "DX8" to CNA_GRAPHICS_BACKEND's STRINGS property + CNA_BACKEND_DX8 option; extend the Windows-only FATAL_ERROR gate; add the legacy-interface-discipline grep CTest (design decision 16) |
✅ | |
DX8-2 |
cna_backend_graphics_dx8 static library target linking DXVK's own d3d8 import library directly (decision 14) |
✅ | |
DX8-3 |
include/CNA/Internal/Backends/Dx8/Dx8GraphicsBackend.hpp + src/CNA/Internal/Backends/Dx8/Dx8GraphicsBackend.cpp: new backend, not a mechanical port |
✅ | |
DX8-4 |
Factory dispatch for DX8 in CreateGraphicsBackend() |
✅ | |
DX8-5 |
scripts/run-wine-dx8.sh (design decision 15); one-time Wine-prefix d3d8 override setup (decision 2) |
✅ | |
DX8-6 |
Confirm CnaTests/the new MinGW test binaries link cleanly against the new backend target under cross-compilation; proactively add a Dx8 entry to every CNA_BACKEND_* registry file |
✅ |
| # | Task | Status | Notes |
|---|---|---|---|
DX8-10 |
Direct3DCreate8 + IDirect3D8::CreateDevice against a real HWND, D3DPRESENT_PARAMETERS construction rules (decision 4) |
✅ | |
DX8-11 |
Clear/Present/GetViewportSize/ReadBackbuffer (via CreateImageSurface+CopyRects, decision 12) |
✅ | |
DX8-12 |
SetVirtualResolution/SetPresentationMode/window-logical-coordinate transforms |
✅ |
| # | Task | Status | Notes |
|---|---|---|---|
DX8-20 |
Dx8TextureBackend/Dx8RenderTargetBackend: real IDirect3DTexture8/IDirect3DSurface8 objects (CreateTexture/CreateRenderTarget), SetRenderTarget2D/SetRenderTargets |
✅ | |
DX8-21 |
Dx8SpriteBatchBackend: real GPU-rendered textured quads through the fixed-function pipeline, real D3DRS_ALPHABLENDENABLE/SRCBLEND/DESTBLEND per BlendState, real rotation/scale (decision 11) |
✅ | |
DX8-22 |
SpriteFont/DrawString CTest (reuses the same GPU-quad path) |
✅ |
| # | Task | Status | Notes |
|---|---|---|---|
DX8-30 |
ClearColorAndDepth/ClearDepth/ClearStencil/ClearDepthAndStencil/ClearColorAndStencil/ClearColorDepthAndStencil all via the real device-direct Clear (decision 5) |
✅ | |
DX8-31 |
SupportsDepthStencil()/SupportsCapability() (ThreeD/DepthStencilBuffer/WireFrame real; MultiSampleAntiAliasing/MultipleRenderTargets/OcclusionQuery/CustomEffects genuinely unavailable) |
✅ |
| # | Task | Status | Notes |
|---|---|---|---|
DX8-40 |
CPU clip/transform math (Sutherland-Hodgman near-plane clip, perspective divide), Dx8TLVertex packing, SetVertexShader(fvf)+DrawIndexedPrimitiveUP submission |
✅ | Same math as DX7's own Dx7ClipVertex/Dx7ClipTriangleNearPlane/Dx7BuildPositionColorClipVertex, re-expressed against the new struct/call shape. |
DX8-41 |
Phase O9-equivalent CPU-side BasicEffect lighting (ambient + directional Lambertian/Blinn-Phong specular) |
✅ | |
DX8-42 |
Real texture0 sampling via SetTexture+SetTextureStageState (decision 7) |
✅ | |
DX8-43 |
Near-plane clipping CTest, DrawColoredPrimitives/DrawIndexedColoredPrimitives/DrawPrimitivesEx/DrawIndexedPrimitivesEx |
✅ |
| # | Task | Status | Notes |
|---|---|---|---|
DX8-50, DX8-51 |
Dx8VertexBufferBackend/Dx8IndexBufferBackend: plain CPU-side storage |
✅ |
| # | Task | Status | Notes |
|---|---|---|---|
DX8-60..DX8-63 |
ApplyRasterizerState/ApplyBlendState/ApplySamplerState, SetDepthTestEnabled/SetBlendEnabled/SetDepthWriteEnabled |
✅ | |
DX8-64 |
ApplyDepthStencilState's real stencil wiring (decision 9), new Dx8StencilOperationToD3D helper |
✅ | |
DX8-70..DX8-76 |
Occlusion query/volume-cube-textures/custom-effects/instancing/remaining clears/DebugSimulateContextLoss |
✅ | Genuinely unavailable at this DirectX era or out of this plan's scope, matching this family's own established boundary. |
| # | Task | Status | Notes |
|---|---|---|---|
DX8-80 |
Full 2D+3D CTest suite passing (new test set — not a renamed port, since the 2D layer is redesigned) | ✅ | |
DX8-81 |
New Dx8_Stencil CTest: real stencil write-then-test through the full XNA public API (GraphicsDevice.DepthStencilState) |
✅ | |
DX8-82 |
docs/dx8-backend.md |
✅ | |
DX8-83 |
Update cmake/BackendSelection.cmake's CNA_GRAPHICS_BACKEND STRINGS docstring, README.md, and plan_dxold.md's DX8 row |
✅ | |
DX8-84 |
Full DX8-labeled CTest suite regression + targeted cross-backend test re-run |
✅ |
- Shader Model 1.x programmable shaders — explicit scope decision (TL;DR), since real XNA
effects need
ps_2_0+ regardless;CreateEffectBackendstill throws for any real XNA content. - Multitexture, DXTn compression — same reasoning
DX6/DX7already recorded (D3DFVF_TLVERTEX- equivalent layout only carries one 2D texture-coordinate pair; no consumer for compressed texture data in CNA's own content pipeline). - Cube environment maps — same
D3DFVF_TEXCOORDSIZE3/DDSCAPS2_CUBEMAP-shaped reasoningDX7already recorded (noDDSCAPS2_CUBEMAPconcept here at all — D3D8 has its ownCreateCubeTexture, but wiring it in is out of this plan's fixed-function-only scope). - Two-sided stencil — still a D3D9-era addition.
- Occlusion query — a real DX9-only addition, absent through every version up to and including
DX8 (
docs/directx-legacy-backends-analysis.md's own finding). - Volume/cube textures, custom effects, instancing, MRT — genuinely unavailable at this DirectX era or out of this plan's scope, matching every prior backend in this family's own boundary.
plan_dxold.md— the roadmap this plan is row 8 of.plan_dx7.md,docs/dx7-backend.md— the backend whose CPU-transform/clip math and stencil design this plan reuses (conceptually, not mechanically — the vertex-submission call shape and 2D-layer architecture are both new).plan_dx9.md,docs/d3d9-backend.md— the sibling this plan's DEVICE BRING-UP shape (DXVK delivery, real HWND,D3DPRESENT_PARAMETERS, readback pattern) is modeled on.dx8-spike/README.md— the fullDX8-0spike record.docs/directx-legacy-backends-analysis.md— the feasibility analysis; DX8's own §3.1/§4 rows cover the SM1.x-vs-fixed-function tradeoff this plan's scope decision is based on.