OpenDlssNrLiveEditSmoke.kt
src/jvmMain/kotlin/afield/examples/four/OpenDlssNrLiveEditSmoke.kt · 129 lines
package afield.examples.four
import afield.graphics.render.neural.OpenDlssNrColorEncoding
import afield.graphics.render.neural.OpenDlssNrFrame
import afield.graphics.render.neural.OpenDlssNrInputs
import afield.graphics.render.neural.OpenDlssNrPass
import afield.graphics.render.neural.OpenDlssNrNative
import afield.graphics.render.neural.OpenDlssNrSupport
import afield.graphics.render.neural.OpenDlssNrStudy
import afield.graphics.scene.fabricated.FabricatePostStack
import afield.graphics.vulkan.Renderer
import afield.graphics.vulkan.util.Window
import java.nio.ByteBuffer
import java.nio.ByteOrder
import kotlin.system.exitProcess
FIELD_TEST id: four.open-dlss-nr.live-edit requiresDisplay: true runner: jvm-main entrypoint: afield.examples.four.OpenDlssNrLiveEditSmoke tags: [smoke, four, gpu, neural] timeoutSec: 180 expect: exitCode: 0 stdoutContains: - "OpenDlssNr live edit PASSED" stdoutNotContains: - "VUID-" - "Validation Error" stderrNotContains: - "VUID-" - "Validation Error"
object OpenDlssNrLiveEditSmoke
Live edits that used to need a box rerun. OpenDlssNrStudy.reload with a new varying between the
stages rebuilds the source and the next frames draw with it; with the native library present, a
pass added to a Fabricate post stack leaves that stack when it closes. Without the library the
reload half still runs, in source mode.
object OpenDlssNrLiveEditSmoke {
private val vertex = """
#version 460
layout(location=0) out vec2 uv;
layout(location=1) out float tint;
void main() {
vec2 corner=vec2((gl_VertexIndex<<1)&2,gl_VertexIndex&2);
uv=vec2(corner.x,1-corner.y);
tint=0.5;
gl_Position=vec4(corner*2-1,0,1);
}
""".trimIndent()
private val fragment = """
#version 460
layout(location=0) in vec2 uv;
layout(location=1) in float tint;
layout(location=0) out vec4 color;
layout(push_constant) uniform Study { vec4 frame; } pc;
void main() { color=vec4(tint,0.25,0,1); }
""".trimIndent()
fun main(args: Array<String>)
body — 65 lines, from line 64
@JvmStatic
fun main(args: Array<String>) {
val window = Window("OpenDlssNr live edit")
val renderer = Renderer(window)
// With FIELD_OPEN_DLSS_NR_LIBRARY naming an absent file: build (copy) it after the device exists.
args.indexOf("--built-after-device").takeIf { it >= 0 }?.let { at ->
val built = java.nio.file.Path.of(args[at + 1])
val library = java.nio.file.Path.of(System.getenv("FIELD_OPEN_DLSS_NR_LIBRARY"))
check(OpenDlssNrSupport.availability(renderer).reason == OpenDlssNrNative.ABSENT)
java.nio.file.Files.copy(built, library, java.nio.file.StandardCopyOption.REPLACE_EXISTING)
val reason = OpenDlssNrSupport.availability(renderer).reason
check(reason == OpenDlssNrSupport.BUILT_AFTER_DEVICE) { "unexpected reason: $reason" }
check(OpenDlssNrNative.loaded.isSuccess) { "the newly built adapter did not load" }
renderer.cleanup(); window.cleanup()
// The advice holds: a renderer created now, in the same JVM, gets the NR features.
val restartedWindow = Window("OpenDlssNr restarted")
val restarted = Renderer(restartedWindow)
val after = OpenDlssNrSupport.availability(restarted)
check(after.ready) { "restarted renderer still lacks NR: ${after.reason}" }
restarted.cleanup(); restartedWindow.cleanup()
println("OpenDlssNr built-after-device PASSED: $reason; restarted renderer: ${after.reason}")
exitProcess(0)
}
val study = OpenDlssNrStudy(renderer, size = 128)
if ("--require-native" in args) check(study.pass != null) { study.availability.reason }
println("NR availability: ${study.availability.reason}")
fun frames(n: Int) = repeat(n) { window.pollEvents(); renderer.render() }
frames(4)
val reloaded = study.reload(vertex, fragment)
check(reloaded.isSuccess) { "interface-changing reload failed: ${reloaded.exceptionOrNull()?.message}" }
check(study.reloadPending) { "an interface change should queue a rebuilt source" }
frames(4)
check(!study.reloadPending) { "the rebuilt source never reached a frame" }
val pixels = study.source.readPixelsAsync()
var guard = 0
while (!pixels.isDone && guard++ < 200) frames(1)
val buffer = ByteBuffer.wrap(pixels.get()).order(ByteOrder.nativeOrder())
val red = java.lang.Float.float16ToFloat(buffer.getShort(0))
val green = java.lang.Float.float16ToFloat(buffer.getShort(2))
check(kotlin.math.abs(red - 0.5f) < 0.01f && kotlin.math.abs(green - 0.25f) < 0.01f) {
"rebuilt source did not draw the new varying: rgb=($red, $green)"
}
check(study.reload().isSuccess) { "reloading the original interface failed" }
frames(4)
var detached = "skipped (native NR absent)"
if (study.pass != null) {
val pass = OpenDlssNrPass(renderer, 128, 128)
val stack = FabricatePostStack(study.source)
stack.append(pass.postEffect("nr", { OpenDlssNrInputs(study.source, OpenDlssNrColorEncoding.LINEAR_LDR) },
{ OpenDlssNrFrame(0) }))
check(stack.names() == listOf("nr"))
pass.close()
check(stack.names().isEmpty()) { "closing the pass left it in the post stack: ${stack.names()}" }
check(stack.output() === study.source)
detached = "closed pass left its post stack"
}
frames(2)
study.close()
renderer.cleanup()
window.cleanup()
println("OpenDlssNr live edit PASSED: interface reload rebuilt the source; $detached")
exitProcess(0)
}
}