Skip to content

Win32 + OpenGL demo of artifact‑free, high‑FPS window resizing/moving using a background render thread (C port of Jai example).

License

Notifications You must be signed in to change notification settings

idrassi/ResponsiveWin32RenderThread

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Responsive Win32 Render Thread (OpenGL Demo)

Port of CookedNick's JaiRenderThreadExample with more complex animations: https://github.com/CookedNick/JaiRenderThreadExample

Smooth, artifact-free window resizing and moving on Windows by delegating all rendering to a background thread and synchronizing WM_PAINT with frame completion.

renderDemo.mp4

Highlights

  • Continuous 60+ FPS while sizing/moving the window (no hitching).
  • No stretch / unpainted artifacts: WM_PAINT returns only after the new-size frame is rendered.
  • Render thread sleeps when nothing animates (near 0% CPU/GPU idle).
  • Safe, minimal cross‑thread state handoff (one CRITICAL_SECTION + one CONDITION_VARIABLE).
  • OpenGL 1.1 compatible path with a few extension calls (vsync + optional ARB_sync fence).
  • Additional visuals: particles, rotating/pulsing geometric shapes, color‑cycling quads, FPS counter.
  • Alt+Enter borderless fullscreen toggle.
  • Per‑monitor DPI awareness (PER_MONITOR_AWARE_V2 if available, fallback to system DPI).

Why this exists

Typical Windows apps stutter or show artifacts during interactive resize because:

  1. The OS enters a modal loop and throttles WM_PAINT issuance.
  2. Apps often paint asynchronously relative to WM_PAINT, so the window shows old contents.

This demo blocks inside WM_PAINT until the render thread finishes a frame at the new size, guaranteeing correctness while still achieving high frame cadence thanks to continuous background rendering during animation.

Core Technique

  1. Main thread only processes messages.
  2. WM_PAINT:
    • Writes desired FrameInfo (size + flags) under lock.
    • Wakes render thread and waits on condition variable.
    • Resumes only after render thread signals completion; then EndPaint -> return.
  3. Render thread:
    • Renders continuously only while animation is active (or a frame is explicitly requested).
    • Sleeps on the same condition variable when idle.
  4. Flags (bitfield):
    • FRAME_WINDOW_SIZE_CHANGED
    • FRAME_TERMINATE_RENDER_THREAD
    • FRAME_TOGGLE_ANIM_PLAYBACK
    • FRAME_WAKE_MAIN_WHEN_COMPLETED (indicates main is blocked in WM_PAINT waiting for this frame)

Bidirectional use of a single condition variable keeps the design compact.

Data Flow (simplified)

WM_PAINT -> set flags -> wake render thread -> render thread draws -> signal -> WM_PAINT continues (SwapBuffers already done).

Thread Sync Pattern

Shared struct: FrameInfo nextFrame (simple scalar copy; double buffering unnecessary here).

OpenGL Notes

  • Legacy fixed pipeline for broad compatibility.
  • Orthographic projection adjusted per frame size.
  • Optional ARB_sync fence aligns CPU pacing with GPU completion (avoids presenting half-finished frames on some drivers).
  • Bitmap font (wglUseFontBitmaps) for FPS text (no extra dependencies).
  • Tries to choose modern pixel format with multisampling + sRGB when available, falls back gracefully.

Differences vs Original Jai Example

Aspect Jai Version This C Port
Language/runtime Jai beta ISO C + Win32
Rendering API Simp wrapper Raw WGL + GL 1.1
Demo visuals 3 moving quads Quads + particles + shapes + FPS
DPI handling N/A Per-monitor V2 (if available)
Fullscreen N/A Alt+Enter toggle
GPU sync Basic Optional ARB_sync fence

Building (Windows)

Single source file (main.c). CMake project provided.

Quick build (MSVC command line)

cl /O2 /Zi /FeResponsiveWin32RenderThread.exe main.c user32.lib gdi32.lib opengl32.lib winmm.lib

CMake (Visual Studio)

git clone https://github.com/idrassi/ResponsiveWin32RenderThread.git
cd ResponsiveWin32RenderThread
cmake -S . -B build -G "Visual Studio 17 2022"
cmake --build build --config Release
build\Release\ResponsiveWin32RenderThread.exe

CMake (NMake)

cmake -S . -B build -G "NMake Makefiles"
cmake --build build
build\ResponsiveWin32RenderThread.exe

CMake (MinGW)

cmake -S . -B build -G "MinGW Makefiles"
cmake --build build
build/ResponsiveWin32RenderThread.exe

Controls

  • Space: Pause / resume animation.
  • Alt+Enter: Toggle borderless fullscreen.
  • Resize / move window: Observe smooth, artifact-free updates.
  • Close button / Alt+F4: Graceful shutdown (render thread terminates first).

Performance / Behavior

  • When animation is paused and no resize occurs, render thread sleeps (no busy loop).
  • With vsync enabled (default), pacing comes from the GPU swap + optional fence.
  • Particle / shape counts are configurable via MAX_PARTICLES / MAX_GEOMETRIC_SHAPES.

License

Released under The Unlicense (public domain). (Provide full text if distributing.)

Acknowledgments

  • Original concept and Jai implementation: CookedNick.
  • WM_PAINT blocking inspiration: Patrik Smělý.
  • Win32 + OpenGL baseline APIs by Microsoft / Khronos.

Disclaimer

Educational demo. No warranty. For production: expand error handling, context loss recovery, robust DPI handling, logging, and graceful fallback paths.

About

Win32 + OpenGL demo of artifact‑free, high‑FPS window resizing/moving using a background render thread (C port of Jai example).

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published