app.dhover×279 error×79all
// F04 — vsync / frame pacing, Win32 (../../f04-frame-pacing.md).
//
// Implements the Win32 half of ../../../features/f04-frame-pacing.md on top
// of the scaffold (../scaffold/app.d): drive a trivially cheap redraw (solid
// color flip) from the platform frame clock — no sleep, no busy loop — and
// measure how steady it actually is.
//
//   * Primary pacing source: DwmFlush() from dwmapi.dll, which blocks until
//     the next DWM composition pass (≈ the next vblank when composition is
//     active). DwmIsCompositionEnabled() is checked first, then a 10-call
//     probe measures whether DwmFlush actually *blocks* — a broken/stubbed
//     DwmFlush that returns immediately (or errors) would otherwise turn the
//     pacing loop into a busy spin. Whatever the probe finds is the finding.
//   * Documented fallback chain: DwmFlush -> SetTimer at 16 ms. The chosen
//     path is logged (`pacing_path path=dwm|timer reason=...`) and stamped on
//     every frame. WSI_FORCE_TIMER=1 / WSI_FORCE_DWM=1 override the choice so
//     both paths stay reachable on any host.
//   * 600 frames of `frame_callback t=...` are collected; at exit the
//     inter-frame deltas' min/p50/p99/max and a coarse jitter histogram are
//     printed to *stdout* (the instrumentation stream stays on stderr).
//   * Occlusion probe (WSI_AUTO_EXIT=1): at frame 300 the window is minimized
//     (ShowWindow(SW_MINIMIZE), `vis_change state=minimized`) and restored
//     ~3 s later — does the pacing source keep ticking while the window is
//     hidden? The frame log answers directly.
//   * A stall watchdog thread aborts (exit 2) if no frame lands for 10 s, so
//     the bounded mode can never hang CI even if a pacing source wedges.
//
// The DXGI waitable-swapchain path (the real-Windows gold path) is
// documented in ../../f04-frame-pacing.md but deliberately out of scope here:
// it needs COM + D3D11/DXGI interface bring-up that core.sys.windows does not
// carry. Only druntime's built-in bindings are used — plus two hand-declared
// dwmapi entry points (druntime ships no dwmapi module).
module 
(module) app
app
;
import
(package) core
core
.
(module) core.atomic

The atomic module provides basic support for lock-free concurrent programming.

Use the -preview=nosharedaccess compiler flag to detect unsafe individual read or write operations on shared data.

Source

core/atomic.d

Examples

int y = 2;
shared int x = y; // OK

//x++; // read modify write error
x.atomicOp!"+="(1); // OK
//y = x; // read error with preview flag
y = x.atomicLoad(); // OK
assert(y == 3);
//x = 5; // write error with preview flag
x.atomicStore(5); // OK
assert(x.atomicLoad() == 5);
@copyrightCopyright Sean Kelly 2005 - 2016.@licenseBoost License 1.0@authorsSean Kelly, Alex Rønne Petersen, Manu Evans
atomic
:
(alias template) app.atomicLoad = core.atomic.atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(auto ref return scope const T val) if (!is(T == shared(U), U) && !is(T == shared(inout(U)), U) && !is(T == shared(const(U)), U))

Loads 'val' from memory and returns it. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq, and MemoryOrder.seq.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
,
(alias template) app.atomicStore = core.atomic.atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval) if (!is(T == shared) && !is(V == shared))

Writes 'newval' into 'val'. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.rel, and MemoryOrder.seq.

@paramval The target variable.@paramnewval The value to store.
atomicStore
;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.stdio

D header file for C99 <stdio.h>

pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html, stdio.h

Source

core/stdc/stdio.d

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly, Alex Rønne Petersen@standardsISO/IEC 9899:1999 (E)
stdio
:
(alias) app.fflush = int core.stdc.stdio.fflush(shared(core.stdc.stdio._IO_FILE)* stream) nothrow @nogc @trusted
fflush
,
(alias) app.printf = int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
,
(alias shared global) app.stdout = shared(core.stdc.stdio._IO_FILE*) core.stdc.stdio.stdout
stdout
;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.stdlib

D header file for C99.

pubs.opengroup.org/onlinepubs/009695399/basedefs/stdlib.h.html, stdlib.h

Source

core/stdc/stdlib.d

@copyrightCopyright Sean Kelly 2005 - 2014.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly@standardsISO/IEC 9899:1999 (E)
stdlib
:
(alias) app.qsort = void core.stdc.stdlib.qsort(void* base, ulong nmemb, ulong size, extern (C) int function(const(void*), const(void*)) compar) nothrow @nogc
qsort
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.windows
windows
.
(module) core.sys.windows.windows

Windows API header module

Translated from MinGW API for MS-Windows 4.0

Source

core/sys/windows/windows.d

windows
;
import instrument;
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
// druntime has no core.sys.windows.dwmapi — declare the two entry points. // pragma(lib) emits /DEFAULTLIB:dwmapi, resolved against the SDK import libs. pragma(lib, "dwmapi"); extern (Windows) nothrow @nogc { HRESULT
app.DwmIsCompositionEnabled
DwmIsCompositionEnabled
(BOOL* pfEnabled);
undefined identifier `HRESULT`
undefined identifier `BOOL`
HRESULT
app.DwmFlush
DwmFlush
();
undefined identifier `HRESULT`
} enum
(constant) int app.FRAMES_TOTAL = 600
FRAMES_TOTAL
= 600; // F04 requirement 2
enum
(constant) int app.TIMER_MS = 16
TIMER_MS
= 16; // the documented fallback cadence
enum UINT_PTR
(constant) _error_ app.FRAME_TIMER_ID = __error
FRAME_TIMER_ID
= 1;
undefined identifier `UINT_PTR`
enum
(constant) int app.MINIMIZE_AT_FRAME = 300
MINIMIZE_AT_FRAME
= 300; // occlusion probe (requirement 3)
enum
(constant) int app.MINIMIZED_HOLD_US = 3000000
MINIMIZED_HOLD_US
= 3_000_000;
struct
(struct) app.Demo
Demo
{ HDC
(field) _error_ app.Demo.memDc
memDc
;
undefined identifier `HDC`
HBITMAP
(field) _error_ app.Demo.dib
dib
;
undefined identifier `HBITMAP`
HBITMAP
(field) _error_ app.Demo.stockBmp
stockBmp
;
undefined identifier `HBITMAP`
uint*
(field) uint* app.Demo.pixels
pixels
;
int
(field) int app.Demo.width
width
,
(field) int app.Demo.height
height
;
uint
(field) uint app.Demo.frame
frame
; // frame_callback counter
const(char)*
(field) const(char)* app.Demo.path
path
= "unset"; // dwm | timer
long[
(constant) int app.FRAMES_TOTAL = 600
FRAMES_TOTAL
]
(field) long[600] app.Demo.frameTimes
frameTimes
; // µs timestamps, [0 .. frame)
bool
(field) bool app.Demo.autoExit
autoExit
;
bool
(field) bool app.Demo.forceTimer
forceTimer
,
(field) bool app.Demo.forceDwm
forceDwm
;
bool
(field) bool app.Demo.minimized
minimized
;
long
(field) long app.Demo.minimizedAtUs
minimizedAtUs
;
bool
(field) bool app.Demo.occlusionDone
occlusionDone
;
bool
(field) bool app.Demo.statsDone
statsDone
;
} __gshared
(struct) app.Demo
Demo
_error_ app.g
g
;
__gshared HWND
_error_ app.g_hwnd
g_hwnd
;
undefined identifier `HWND`
shared long
(shared global) shared(long) app.s_lastFrameUs
s_lastFrameUs
; // stall watchdog heartbeat
shared bool
(shared global) shared(bool) app.s_done
s_done
;
// --------------------------------------------------------------------------- // Backbuffer (scaffold strategy: realloc on client-size change). void
void app.createBackbuffer(int w, int h) nothrow
createBackbuffer
(int
(parameter) int w
w
, int
(parameter) int h
h
) nothrow
{ if (g.
(field) _error_ g.dib
dib
!is null)
{ SelectObject(g.
g.memDc
memDc
, g.
g.stockBmp
stockBmp
);
undefined identifier `SelectObject`
DeleteObject(g.
g.dib
dib
);
undefined identifier `DeleteObject`
g.
g.dib
dib
= null;
g.
g.pixels
pixels
= null;
g.
g.width
width
= g.
g.height
height
= 0;
} if (
(parameter) int w
w
<= 0 ||
(parameter) int h
h
<= 0)
return; BITMAPINFO
(local variable) _error_ bmi
bmi
;
undefined identifier `BITMAPINFO`
bmi.bmiHeader.biSize = BITMAPINFOHEADER.
BITMAPINFOHEADER.sizeof
sizeof
;
bmi.bmiHeader.biWidth = w; bmi.bmiHeader.biHeight = -h; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; void*
(local variable) void* bits
bits
;
g.
g.dib
dib
= CreateDIBSection(null, &bmi, DIB_RGB_COLORS, &bits, null, 0);
if (g.
(field) _error_ g.dib
dib
is null)
{ logEvent("error what=CreateDIBSection code=%lu", GetLastError());
undefined identifier `logEvent`
return; } g.
g.pixels
pixels
= cast(uint*) bits;
g.
g.width
width
= w;
g.
g.height
height
= h;
g.
g.stockBmp
stockBmp
= cast(HBITMAP) SelectObject(g.
g.memDc
memDc
, g.
g.dib
dib
);
logEvent("buffer_alloc size=%dx%d bytes=%d", w, h, w * h * 4);
undefined identifier `logEvent`
} // --------------------------------------------------------------------------- // One paced frame: flip between two solid colors (trivially cheap), log the // callback, drive the occlusion probe, present synchronously. void
void app.onFrame() nothrow
onFrame
() nothrow
{ const
(local variable) const(_error_) t
t
= nowUs();
undefined identifier `nowUs`
if (g.
(field) _error_ g.frame
frame
< FRAMES_TOTAL)
g.
(field) _error_ g.frameTimes
frameTimes
[g.
g.frame
frame
] = t;
++g.
(field) _error_ g.frame
frame
;
(template function) core.atomic.atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval) if (!is(T == shared) && !is(V == shared))
atomicStore
(
(shared global) shared(long) app.s_lastFrameUs
s_lastFrameUs
, t);
logEvent("frame_callback t=%lld frame=%u path=%s", t, g.
g.frame
frame
, g.
g.path
path
);
undefined identifier `logEvent`
if (g.
(field) _error_ g.pixels
pixels
!is null)
{ const
(local variable) const(_error_) color
color
= (g.
(field) _error_ g.frame
frame
& 1) ? 0x2060c0 : 0xc06020; // the solid flip
const
(local variable) const(_error_) n
n
= cast(
(alias) object.size_t = ulong
size_t
) g.
(field) _error_ g.width
width
* g.
(field) _error_ g.height
height
;
foreach (
(parameter) i
i
; 0 .. n)
g.
g.pixels
pixels
[i] = color;
} InvalidateRect(g_hwnd, null, FALSE);
undefined identifier `InvalidateRect`
UpdateWindow(g_hwnd);
undefined identifier `UpdateWindow`
// Occlusion probe: minimize mid-run, restore after ~3 s. Both transitions // happen from inside the pacing callback — if the pacing source stops // while minimized, the restore never runs and the stall watchdog reports. if (g.
(field) _error_ g.autoExit
autoExit
&& !g.
(field) _error_ g.occlusionDone
occlusionDone
)
{ if (!g.
(field) _error_ g.minimized
minimized
&& g.
(field) _error_ g.frame
frame
== MINIMIZE_AT_FRAME)
{ g.
g.minimized
minimized
= true;
g.
g.minimizedAtUs
minimizedAtUs
= t;
logEvent("vis_change state=minimized t=%lld frame=%u", t, g.
g.frame
frame
);
undefined identifier `logEvent`
ShowWindow(g_hwnd, SW_MINIMIZE);
undefined identifier `ShowWindow`
} else if (g.
(field) _error_ g.minimized
minimized
&& t - g.
(field) _error_ g.minimizedAtUs
minimizedAtUs
> MINIMIZED_HOLD_US)
{ g.
g.minimized
minimized
= false;
g.
g.occlusionDone
occlusionDone
= true;
logEvent("vis_change state=restored t=%lld frame=%u", t, g.
g.frame
frame
);
undefined identifier `logEvent`
ShowWindow(g_hwnd, SW_RESTORE);
undefined identifier `ShowWindow`
} } } // --------------------------------------------------------------------------- // Stats: min/p50/p99/max inter-frame delta + coarse jitter histogram, printed // to stdout at exit (F04 requirement 2). extern (C) int
int app.cmpLong(const(void)* a, const(void)* b) nothrow @nogc
cmpLong
(const(void)*
(parameter) const(void)* a
a
, const(void)*
(parameter) const(void)* b
b
) nothrow @nogc
{ const
(local variable) const(long) x
x
= *cast(const(long)*)
(parameter) const(void)* a
a
,
(local variable) const(long) y
y
= *cast(const(long)*)
(parameter) const(void)* b
b
;
return (
(local variable) const(long) x
x
>
(local variable) const(long) y
y
) - (
(local variable) const(long) x
x
<
(local variable) const(long) y
y
);
} void
void app.printStats() nothrow
printStats
() nothrow
{ if (g.
(field) _error_ g.statsDone
statsDone
)
return; g.
g.statsDone
statsDone
= true;
const
(local variable) const(_error_) n
n
= (g.
(field) _error_ g.frame
frame
< FRAMES_TOTAL ? g.
(field) _error_ g.frame
frame
: FRAMES_TOTAL);
if (n < 2) {
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("stats path=%s frames=%u deltas=0\n", g.
(field) _error_ g.path
path
, g.
(field) _error_ g.frame
frame
);
int core.stdc.stdio.fflush(shared(core.stdc.stdio._IO_FILE)* stream) nothrow @nogc @trusted
fflush
(
(shared global) shared(core.stdc.stdio._IO_FILE*) core.stdc.stdio.stdout
stdout
);
return; } static long[
(constant) int app.FRAMES_TOTAL = 600
FRAMES_TOTAL
- 1]
(thread local global) long[599] app.printStats.deltas
deltas
;
const
(local variable) const(_error_) nd
nd
= n - 1;
foreach (
(parameter) i
i
; 0 .. nd)
deltas[i] = g.
g.frameTimes
frameTimes
[i + 1] - g.
g.frameTimes
frameTimes
[i];
// Histogram over the raw (unsorted) deltas. static immutable long[7]
(immutable global) immutable(long[7]) app.printStats.edges
edges
= [2_000, 8_000, 12_000, 17_000, 20_000,
34_000, 100_000]; static immutable
(alias) object.string = string
string
[8]
(immutable global) immutable(string[8]) app.printStats.labels
labels
= [
"<2ms", "2-8ms", "8-12ms", "12-17ms", "17-20ms", "20-34ms", "34-100ms", ">=100ms", ]; uint[8]
(local variable) uint[8] buckets
buckets
;
foreach (
(parameter) i
i
; 0 .. nd)
{
(unresolved type) size_t
size_t
_error_ b
b
= edges.
edges.length
length
; // last bucket unless an edge catches it
foreach (
(parameter) j
j
,
(parameter) e
e
; edges)
if (deltas[i] < e) { b = j; break; } ++buckets[b]; }
void core.stdc.stdlib.qsort(void* base, ulong nmemb, ulong size, extern (C) int function(const(void*), const(void*)) compar) nothrow @nogc
qsort
(
(thread local global) long[599] app.printStats.deltas
deltas
.
(constant) long* long[599].ptr = &deltas
ptr
, nd, long.
(constant) ulong long.sizeof = 8LU
sizeof
, &
int app.cmpLong(const(void)* a, const(void)* b) nothrow @nogc
cmpLong
);
const long
(local variable) const(long) mn
mn
=
(thread local global) long[599] app.printStats.deltas
deltas
[0];
const long
(local variable) const(long) p50
p50
=
(thread local global) long[599] app.printStats.deltas
deltas
[nd / 2];
const long
(local variable) const(long) p99
p99
=
(thread local global) long[599] app.printStats.deltas
deltas
[(nd * 99) / 100];
const long
(local variable) const(long) mx
mx
=
(thread local global) long[599] app.printStats.deltas
deltas
[nd - 1];
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("stats path=%s frames=%u deltas=%u min_us=%lld p50_us=%lld "
~ "p99_us=%lld max_us=%lld\n", g.
(field) _error_ g.path
path
, g.
(field) _error_ g.frame
frame
, cast(uint) nd,
(local variable) const(long) mn
mn
,
(local variable) const(long) p50
p50
,
(local variable) const(long) p99
p99
,
(local variable) const(long) mx
mx
);
foreach (
(parameter) ulong j
j
,
(parameter) immutable(string) label
label
;
(immutable global) immutable(string[8]) app.printStats.labels
labels
)
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("histogram bucket=%.*s count=%u\n",
cast(int)
(local variable) immutable(string) label
label
.
(field) ulong immutable(string).length
length
,
(local variable) immutable(string) label
label
.
(field) immutable(char)* immutable(string).ptr
ptr
,
(local variable) uint[8] buckets
buckets
[
(local variable) ulong j
j
]);
int core.stdc.stdio.fflush(shared(core.stdc.stdio._IO_FILE)* stream) nothrow @nogc @trusted
fflush
(
(shared global) shared(core.stdc.stdio._IO_FILE*) core.stdc.stdio.stdout
stdout
);
} // --------------------------------------------------------------------------- // Stall watchdog: the bounded mode must never hang CI. If no frame lands for // 10 s (a pacing source that blocks forever, e.g. a DwmFlush that never // returns), report and abort with exit code 2. extern (Windows) DWORD
app.stallWatchdog
stallWatchdog
(LPVOID) nothrow
undefined identifier `DWORD`
undefined identifier `LPVOID`
{ while (!atomicLoad(s_done)) { Sleep(500); const
_error_ last
last
= atomicLoad(s_lastFrameUs);
if (!atomicLoad(s_done) && nowUs() - last > 10_000_000) { logEvent("watchdog event=stall last_frame_us=%lld path=%s", last, g.
g.path
path
);
printStats(); ExitProcess(2); } } return 0; } // --------------------------------------------------------------------------- // The window procedure. extern (Windows) LRESULT
app.wndProc
wndProc
(HWND hwnd, UINT
(parameter) UINT msg
msg
, WPARAM wParam, LPARAM lParam) nothrow
undefined identifier `LRESULT`
undefined identifier `HWND`
undefined identifier `UINT`
undefined identifier `WPARAM`
undefined identifier `LPARAM`
{ switch (msg) { case WM_CREATE: g.
g.memDc
memDc
= CreateCompatibleDC(null);
return 0; case WM_SIZE: const
_error_ w
w
= cast(int)(lParam & 0xffff);
const
_error_ h
h
= cast(int)((lParam >> 16) & 0xffff);
logEvent("resize size=%dx%d wparam=%d", w, h, cast(int) wParam); if (wParam == SIZE_MINIMIZED) { logEvent("vis_change state=size_minimized"); return 0; // keep the backbuffer; pacing continues (or not — log!) } if (w != g.
g.width
width
|| h != g.
g.height
height
)
createBackbuffer(w, h); return 0; case WM_ERASEBKGND: return 1; case WM_PAINT: PAINTSTRUCT
_error_ ps
ps
;
HDC
_error_ hdc
hdc
= BeginPaint(hwnd, &ps);
if (g.
g.pixels
pixels
!is null)
BitBlt(hdc, 0, 0, g.
g.width
width
, g.
g.height
height
, g.
g.memDc
memDc
, 0, 0, SRCCOPY);
EndPaint(hwnd, &ps); return 0; case WM_TIMER: if (wParam != FRAME_TIMER_ID) return 0; onFrame(); if (g.
g.autoExit
autoExit
&& g.
g.frame
frame
>= FRAMES_TOTAL)
{ KillTimer(hwnd, FRAME_TIMER_ID); printStats(); DestroyWindow(hwnd); } return 0; case WM_CLOSE: logEvent("close_requested"); goto default; case WM_DESTROY: logEvent("msg name=WM_DESTROY"); KillTimer(hwnd, FRAME_TIMER_ID); createBackbuffer(0, 0); if (g.
g.memDc
memDc
!is null)
{ DeleteDC(g.
g.memDc
memDc
);
g.
g.memDc
memDc
= null;
} PostQuitMessage(0); return 0; default: return DefWindowProcW(hwnd, msg, wParam, lParam); } } // --------------------------------------------------------------------------- // Pacing-path selection: report what DWM says, then measure what DwmFlush // actually does. A real composition clock blocks ~per-vblank (2–50 ms); an // immediate return (Wine stubs, composition off) or an error HRESULT means // the documented fallback (SetTimer) must take over. const(char)*
const(char)* app.probeDwm() nothrow
probeDwm
() nothrow
{ BOOL
(local variable) _error_ enabled
enabled
= FALSE;
undefined identifier `BOOL`
undefined identifier `FALSE`, did you mean `false`?
const
(local variable) const(_error_) hrEnabled
hrEnabled
= DwmIsCompositionEnabled(&enabled);
logEvent("step name=DwmIsCompositionEnabled hr=0x%08x enabled=%d",
undefined identifier `logEvent`
cast(uint) hrEnabled, enabled ? 1 : 0); long
(local variable) long minDt
minDt
= long.
(constant) long long.max = 9223372036854775807L
max
,
(local variable) long maxDt
maxDt
= 0;
HRESULT
(local variable) _error_ lastHr
lastHr
= 0;
undefined identifier `HRESULT`
uint
(local variable) uint failures
failures
= 0;
foreach (
(local variable) int i
i
; 0 .. 10)
{ const
(local variable) const(_error_) t0
t0
= nowUs();
undefined identifier `nowUs`
const
(local variable) const(_error_) hr
hr
= DwmFlush();
const
(local variable) const(_error_) dt
dt
= nowUs() - t0;
undefined identifier `nowUs`
if (hr != 0) { ++
(local variable) uint failures
failures
;
lastHr = hr; } if (dt <
(local variable) long minDt
minDt
)
(local variable) long minDt
minDt
= dt;
if (dt >
(local variable) long maxDt
maxDt
)
(local variable) long maxDt
maxDt
= dt;
logEvent("pacing_probe call=%d hr=0x%08x dt_us=%lld", i,
undefined identifier `logEvent`
cast(uint) hr, dt); } if (g.
(field) _error_ g.forceTimer
forceTimer
)
return "forced_timer"; if (
(local variable) uint failures
failures
== 10 && !g.
(field) _error_ g.forceDwm
forceDwm
)
return "dwmflush_failed"; if (
(local variable) uint failures
failures
> 0 && !g.
(field) _error_ g.forceDwm
forceDwm
)
return "dwmflush_unreliable"; // "Blocks at least once for >= 2 ms" is the cheapest honest signature of // a real composition clock; immediate returns would busy-spin the loop. if (
(local variable) long maxDt
maxDt
< 2_000 && !g.
(field) _error_ g.forceDwm
forceDwm
)
return "dwmflush_returns_immediately"; if (!enabled && !g.
(field) _error_ g.forceDwm
forceDwm
)
return "composition_disabled"; return null; // use the DWM path } // The DwmFlush-paced loop. Returns true when the run is complete (or the // window died); false means "fall back to the timer path mid-run". bool
bool app.runDwmLoop() nothrow
runDwmLoop
() nothrow
{ uint
(local variable) uint consecutiveFailures
consecutiveFailures
= 0;
while (true) { const
(local variable) const(_error_) hr
hr
= DwmFlush();
if (hr != 0) { logEvent("pacing_error hr=0x%08x frame=%u", cast(uint) hr, g.
g.frame
frame
);
undefined identifier `logEvent`
if (++
(local variable) uint consecutiveFailures
consecutiveFailures
>= 5)
{ logEvent("pacing_path path=timer reason=dwmflush_failed_midrun");
undefined identifier `logEvent`
return false; } } else
(local variable) uint consecutiveFailures
consecutiveFailures
= 0;
void app.onFrame() nothrow
onFrame
();
// Drain whatever the frame produced; the loop owns the cadence. MSG
(local variable) _error_ msg
msg
;
undefined identifier `MSG`
while (PeekMessageW(&msg, null, 0, 0, PM_REMOVE))
undefined identifier `PeekMessageW`
{ if (msg.message == WM_QUIT)
undefined identifier `WM_QUIT`
return true; TranslateMessage(&msg);
undefined identifier `TranslateMessage`
DispatchMessageW(&msg);
undefined identifier `DispatchMessageW`
} if (g.
(field) _error_ g.autoExit
autoExit
&& g.
(field) _error_ g.frame
frame
>= FRAMES_TOTAL)
{
void app.printStats() nothrow
printStats
();
DestroyWindow(g_hwnd);
undefined identifier `DestroyWindow`
while (GetMessageW(&msg, null, 0, 0) > 0)
undefined identifier `GetMessageW`
{ TranslateMessage(&msg);
undefined identifier `TranslateMessage`
DispatchMessageW(&msg);
undefined identifier `DispatchMessageW`
} return true; } } } bool
bool app.envFlag(const(wchar)* name) nothrow
envFlag
(const(wchar)*
(parameter) const(wchar)* name
name
) nothrow
{ WCHAR[8]
(local variable) _error_ buf
buf
;
undefined identifier `WCHAR`
const
(local variable) const(_error_) n
n
= GetEnvironmentVariableW(name, buf.
buf.ptr
ptr
, buf.
buf.length
length
);
undefined identifier `GetEnvironmentVariableW`
return n >= 1 && n < buf.
(field) _error_ buf.length
length
&& buf[0] == '1';
} int
int D main()
main
()
{ instrumentInit("f04_frame_pacing_win32");
undefined identifier `instrumentInit`
logEvent("init_start");
undefined identifier `logEvent`
g.
g.autoExit
autoExit
= envFlag("WSI_AUTO_EXIT"w.
"WSI_AUTO_EXIT"w.ptr
ptr
);
g.
g.forceTimer
forceTimer
= envFlag("WSI_FORCE_TIMER"w.
"WSI_FORCE_TIMER"w.ptr
ptr
);
g.
g.forceDwm
forceDwm
= envFlag("WSI_FORCE_DWM"w.
"WSI_FORCE_DWM"w.ptr
ptr
);
logEvent("mode auto_exit=%d force_timer=%d force_dwm=%d",
undefined identifier `logEvent`
g.
g.autoExit
autoExit
? 1 : 0, g.
g.forceTimer
forceTimer
? 1 : 0, g.
g.forceDwm
forceDwm
? 1 : 0);
HINSTANCE
(local variable) _error_ hInst
hInst
= GetModuleHandleW(null);
undefined identifier `HINSTANCE`
undefined identifier `GetModuleHandleW`
HCURSOR
(local variable) _error_ arrow
arrow
= LoadCursorW(null, IDC_ARROW);
undefined identifier `HCURSOR`
undefined identifier `LoadCursorW`
auto
(local variable) wstring clsName
clsName
= "wsi-f04-class"w;
WNDCLASSEXW
(local variable) _error_ wc
wc
;
undefined identifier `WNDCLASSEXW`
wc.cbSize = WNDCLASSEXW.
WNDCLASSEXW.sizeof
sizeof
;
wc.lpfnWndProc = &wndProc; wc.hInstance = hInst; wc.lpszClassName = clsName.
clsName.ptr
ptr
;
wc.hCursor = arrow; logEvent("step name=RegisterClassExW");
undefined identifier `logEvent`
if (!RegisterClassExW(&wc))
undefined identifier `RegisterClassExW`
{ logEvent("error what=RegisterClassExW code=%lu", GetLastError());
undefined identifier `logEvent`
return 1; } logEvent("step name=CreateWindowExW");
undefined identifier `logEvent`
g_hwnd = CreateWindowExW(0, clsName.
clsName.ptr
ptr
, "wsi-f04-frame-pacing"w.
"wsi-f04-frame-pacing"w.ptr
ptr
,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 480, 320, null, null, hInst, null); if (g_hwnd is null) { logEvent("error what=CreateWindowExW code=%lu", GetLastError());
undefined identifier `logEvent`
return 1; } logEvent("window_created");
undefined identifier `logEvent`
ShowWindow(g_hwnd, SW_SHOW);
undefined identifier `ShowWindow`
UpdateWindow(g_hwnd);
undefined identifier `UpdateWindow`
(template function) core.atomic.atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval) if (!is(T == shared) && !is(V == shared))
atomicStore
(
(shared global) shared(long) app.s_lastFrameUs
s_lastFrameUs
, nowUs());
undefined identifier `nowUs`
HANDLE
(local variable) _error_ wd
wd
= null;
undefined identifier `HANDLE`
if (g.
(field) _error_ g.autoExit
autoExit
)
wd = CreateThread(null, 0, &stallWatchdog, null, 0, null); const
(local variable) const(char*) reason
reason
=
const(char)* app.probeDwm() nothrow
probeDwm
();
bool
(local variable) bool completed
completed
= false;
if (
(local variable) const(char*) reason
reason
is null)
{ g.
g.path
path
= "dwm";
logEvent("pacing_path path=dwm reason=%s",
undefined identifier `logEvent`
g.
g.forceDwm
forceDwm
? "forced_dwm".
"forced_dwm".ptr
ptr
: "probe_blocked".
"probe_blocked".ptr
ptr
);
(local variable) bool completed
completed
=
bool app.runDwmLoop() nothrow
runDwmLoop
();
} else logEvent("pacing_path path=timer reason=%s", reason);
undefined identifier `logEvent`
int
(local variable) int code
code
= 0;
if (!
(local variable) bool completed
completed
)
{ g.
g.path
path
= "timer";
logEvent("step name=SetTimer interval_ms=%d", TIMER_MS);
undefined identifier `logEvent`
SetTimer(g_hwnd, FRAME_TIMER_ID, TIMER_MS, null);
undefined identifier `SetTimer`
MSG
(local variable) _error_ msg
msg
;
undefined identifier `MSG`
while (GetMessageW(&msg, null, 0, 0) > 0)
undefined identifier `GetMessageW`
{ TranslateMessage(&msg);
undefined identifier `TranslateMessage`
DispatchMessageW(&msg);
undefined identifier `DispatchMessageW`
}
(local variable) int code
code
= cast(int) msg.wParam;
}
void core.atomic.atomicStore!(MemoryOrder.seq, bool, bool)(ref shared(bool) val, bool newval) pure nothrow @nogc @trusted

Writes 'newval' into 'val'. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.rel, and MemoryOrder.seq.

@paramval The target variable.@paramnewval The value to store.
atomicStore
(
(shared global) shared(bool) app.s_done
s_done
, true);
if (wd !is null) { WaitForSingleObject(wd, 1500);
undefined identifier `WaitForSingleObject`
CloseHandle(wd);
undefined identifier `CloseHandle`
}
void app.printStats() nothrow
printStats
(); // no-op if already printed
logEvent("exit code=%d", code);
undefined identifier `logEvent`
return
(local variable) int code
code
;
}