# Double Buffer Architecture Research v1
## Date: 2026-04-30

---

## Current State (v3→v4)

```
WM_PAINT flow:

UsrFontWndProc
  ├─ s_bInsidePaint = 1
  ├─ GetUpdateRect → s_rcLastPaint
  ├─ Ghost detection (s_aDrawnCells vs screenBuffer)
  ├─ g_bSharedPaint = 1
  │
  ├─ CallWindowProcW → PaintText
  │   ├─ BeginPaint (get ps.rcPaint)
  │   ├─ hdcScreen = GetDC(hWnd)
  │   ├─ BitBlt(s_hdcPaintBuf ← hdcScreen)   ← screen capture (redundant in shared mode?)
  │   ├─ TextOut → s_hdcPaintBuf              ← ASCII to buffer
  │   ├─ [SKIP BitBlt to screen]              ← v3 change
  │   ├─ g_hPaintBuf = s_hdcPaintBuf          ← v3 export pointer
  │   ├─ ReleaseDC, EndPaint
  │   └─ return
  │
  ├─ ScanAndDrawUda
  │   ├─ hdc = GetDC(hWnd)                    ← still needed for GDI resource creation
  │   ├─ HideCaret
  │   ├─ [v3: capture g_hPaintBuf → s_hdcDblBuf, draw UDA → s_hdcDblBuf]
  │   ├─ [v4: hdcDraw = g_hPaintBuf directly, no capture, no s_hdcDblBuf]
  │   ├─ DrawUDA → g_hPaintBuf               ← UDA overlaid directly
  │   ├─ BitBlt(hdc ← g_hPaintBuf)           ← ONLY screen write
  │   ├─ Caret rebuild
  │   ├─ ReleaseDC
  │   └─ return
  │
  ├─ g_bSharedPaint = 0
  └─ s_bInsidePaint = 0
```

## Remaining Architecture Issues

| # | Issue | Impact | Difficulty |
|---|-------|--------|-----------|
| 1 | s_hdcDblBuf still created in v4 (unused) | Memory waste | Low |
| 2 | PaintText still captures screen in shared mode (redundant BitBlt) | Wasted BitBlt | Medium |
| 3 | Two buffers coexist (s_hdcPaintBuf + s_hdcDblBuf) | Double memory | Low |
| 4 | ScanAndDrawUda still GetDC for GDI resource creation | Semantic mismatch | Low |
| 5 | Caret managed inside ScanAndDrawUda (ideally after final BitBlt) | Architecture inconsistency | Medium (v1/v2 failed) |
| 6 | Two globals (g_bSharedPaint + g_hPaintBuf) could be one | Simplification | Low |

## Core Bottleneck

Issue #2 (PaintText screen capture) is the KEY to further simplification.

PaintText's `BitBlt(s_hdcPaintBuf ← hdcScreen)` captures current screen into buffer.
In shared mode, this is redundant because s_hdcPaintBuf already has previous frame content.
But removing it requires correct buffer initialization on first creation.

v1/v2 failed possibly because new buffer had no proper base content.
v3/v4 succeed because PaintText's screen capture initializes buffer content.

## Evolution Roadmap

```
v4 (current) → v4.1 (skip s_hdcDblBuf creation)
             → v4.2 (merge g_bSharedPaint + g_hPaintBuf)
             → v5  (PaintText skip screen capture) ← needs careful buffer init
             → v6  (ScanAndDrawUda skip GetDC) ← needs GDI resource refactor
```

## v1/v2 Failure Analysis

Both v1 and v2 caused "unable to input":
- v1: WndProc created new shared buffer + full-screen BitBlt after ScanAndDrawUda
- v2: Same but dirty-region BitBlt only

Root cause NOT identified. Possible causes:
1. BeginPaint/EndPaint vs external GetDC/BitBlt conflict
2. WM_PAINT infinite loop (BitBlt triggers new invalidation)
3. HideCaret/ShowCaret counter imbalance
4. Font/color not selected into shared DC

v3 worked because: NO changes to WndProc structure, NO new buffer,
NO extra screen operations. Just redirect data flow between existing buffers.
