Skip to content

Commit 54b9e35

Browse files
committed
Testing hooks
1 parent 892594c commit 54b9e35

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

Sources/SwiftTerm/Apple/Metal/MetalTerminalRenderer.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,19 @@ final class MetalTerminalRenderer: NSObject, MTKViewDelegate {
223223
private var preparedSnapshot: (snapshot: TerminalSnapshot,
224224
context: SnapshotRenderContext)?
225225

226+
/// Testing hook: block until the GPU finishes, so the drawable texture can
227+
/// be read back. Never set in production; a synchronous wait on the render
228+
/// path is exactly what this work is trying to remove.
229+
var waitForCompletionAfterCommit = false
230+
231+
/// Testing hook: retains the texture this renderer actually drew into.
232+
///
233+
/// Necessary because asking the surface for a drawable a second time
234+
/// returns a *different* one from the pool, not the frame just rendered —
235+
/// comparing that instead silently compares uninitialised memory.
236+
var capturesRenderedTexture = false
237+
private(set) var lastRenderedTexture: MTLTexture?
238+
226239
/// Asks the host to schedule a frame. A callback rather than a reference to
227240
/// the view's frame driver, so the renderer needs no view access
228241
/// (io-gaps.md G1, WO-F1c).
@@ -603,9 +616,18 @@ final class MetalTerminalRenderer: NSObject, MTKViewDelegate {
603616
os_signpost(.begin, log: MetalTerminalRenderer.profileLog, name: "Metal.Commit", signpostID: commitID)
604617
}
605618
#endif
619+
if capturesRenderedTexture {
620+
lastRenderedTexture = drawable.texture
621+
}
606622
commandBuffer.present(drawable)
607623
bufferPool.commit(commandBuffer: commandBuffer)
608624
commandBuffer.commit()
625+
if waitForCompletionAfterCommit {
626+
// Testing only: makes the drawable texture readable right after
627+
// render() returns, so a test can compare what two surfaces
628+
// actually produced.
629+
commandBuffer.waitUntilCompleted()
630+
}
609631
#if canImport(os)
610632
if MetalTerminalRenderer.profileEnabled {
611633
os_signpost(.end, log: MetalTerminalRenderer.profileLog, name: "Metal.Commit", signpostID: commitID)

TerminalApp/MacTerminal/ViewController.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,33 @@ class ViewController: NSViewController, LocalProcessTerminalViewDelegate, NSUser
678678
guard let name = environment ?? argument, !name.isEmpty else {
679679
return
680680
}
681+
if name == "surfaceparity" {
682+
// Not a load case: renders the same content through both Metal
683+
// surfaces and reports the pixel difference. This is the WO-F3
684+
// regression net, and it can only run where the shader bundle
685+
// exists — that is, inside the app.
686+
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [weak self] in
687+
guard let self else { exit(2) }
688+
_ = self
689+
let result = TerminalView.compareMetalSurfaces()
690+
print("===BASELINE-BEGIN===")
691+
print("## Metal surface parity\n")
692+
if let reason = result.unavailableReason {
693+
print("UNAVAILABLE: \(reason)")
694+
} else {
695+
print("| Measurement | Value |\n| --- | --- |")
696+
print("| Pixels compared | \(result.totalPixels) |")
697+
print("| Differing pixels | \(result.differingPixels) |")
698+
print("| Non-uniform pixels (proof it drew) | \(result.nonUniformPixels) |")
699+
print("| Match | \(result.matches ? "yes" : "NO") |")
700+
}
701+
print("===BASELINE-END===")
702+
fflush(stdout)
703+
exit(result.matches ? 0 : 4)
704+
}
705+
return
706+
}
707+
681708
let loadCase: IOBaselineHarness.Case
682709
switch name {
683710
case "flood": loadCase = .flood

0 commit comments

Comments
 (0)