Skip to content

rendererBrowsing.kt

src/jvmMain/kotlin/afield/app/server/rendererBrowsing.kt · 865 lines · cited by Profiling

package afield.app.server

import afield.graphics.vulkan.CPUSpan
import afield.graphics.vulkan.Renderer
import afield.graphics.vulkan.device.*
import afield.document.context.*
import afield.graphics.render.*
import afield.graphics.scene.*
import afield.graphics.shader.*
import afield.graphics.vulkan.targets.ComputeTarget
import afield.graphics.vulkan.targets.RenderTarget
import afield.graphics.texture.*
import afield.graphics.texture.video.VideoTexture
import afield.graphics.vulkan.util.Window
import java.lang.reflect.Field
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong

private val rendererAdaptersRegistered = AtomicBoolean(false)
private val cpuLastPushMs = AtomicLong(0)

internal const val LIVE_FRAMES = 60L

Frames per live-update step for adapters whose version follows the frame counter.

fun registerRendererBrowsingAdapters()

One-time registration of the Renderer/graphics Browsable adapters, so column("r", renderer) and tree("r", renderer) open the renderer as targets (in draw order), modules with their shaders and bindings, textures, CPU span timings and profiler state. Called from installInspectorHandler at server start; idempotent.

Thread ownership: dir()/html() run inside Inspector.handle, which the __browsing__ handler runs inMain, the same Runloop thread that records and submits frames, so they never read a target mid-record. version() runs on the inspector's poll timer and reads only scalars (frame counter, map sizes), quantised so a live renderer refreshes the browser about once a second rather than on every frame.

body — 697 lines, from line 37
fun registerRendererBrowsingAdapters() {
    if (!rendererAdaptersRegistered.compareAndSet(false, true)) return
    CPUSpan.addListener { maybePushCpuChanged() }

    // Renderer + windowing ------------------------------------------------------------------------------------------

    reg<Renderer> { r, _, _ ->
        object : Browsable {
            override fun heading(): String = "Renderer"
            override fun dir(): Map<String, Any?> {
                val contexts = r.windows.indices.associate { i -> "context[$i]" to r.windowContext(i) }
                val windows = r.windows.withIndex().associate { (i, w) -> "window[$i]" to w }
                val queues = mapOf("graphics" to r.graphQueue, "present" to r.presentQueue)
                val profiling = runCatching { r.windowContext(0).profilerState }.getOrNull()
                return linkedMapOf<String, Any?>(
                    "render" to r.renderList,
                    "compute" to r.computeList,
                    "contexts" to contexts,
                    "windows" to windows,
                    "queues" to queues,
                    "cpu" to CpuNode,
                    "device" to r.device,
                    "pipelineCache" to r.pipelineCache,
                ).also { if (profiling != null) it["profiling"] = profiling }
            }

            override fun html(): String {
                val cpu = CPUSpan.snapshot()
                val cpuLine = cpu.joinToString(" · ") {
                    "${it.label}:${"%.2f".format(it.p50Ms)}ms p50/${"%.2f".format(it.p90Ms)} p90"
                }.ifBlank { "n/a" }
                val rows = listOf(
                    "frame" to "#${r.frameCounter}",
                    "images" to "${r.currentImage}/${r.numImages}",
                    "gfx modules" to "${r.renderList.modules.size} + mesh ${r.renderList.meshModules.size}",
                    "compute modules" to "${r.computeList.modules.size}",
                    "windows" to r.windows.joinToString { it.title },
                    "cpu" to cpuLine
                )
                return card("Renderer", rows, accent = "#7dd3fc")
            }

            override fun version(): Long = r.frameCounter / LIVE_FRAMES
        }
    }

    reg<Renderer.WindowContext> { ctx, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "WindowContext"
            override fun dir(): Map<String, Any?> {
                return linkedMapOf(
                    "window" to ctx.window,
                    "swapchain" to ctx.swapChain,
                    "renderTarget" to ctx.renderTarget,
                    "depthAttachments" to ctx.depthAttachments,
                    "commandBuffers" to ctx.commandBuffers.toList(),
                    "computeCommandBuffers" to ctx.computeCommandBuffers.toList(),
                    "fences" to ctx.fences.toList(),
                    "computeFences" to ctx.computeFences.toList(),
                    "computeSemaphores" to ctx.computeFinishedSemaphores.toList(),
                    "secondary" to mapOf(
                        "graphics" to ctx.graphicsSecondary,
                        "compute" to ctx.computeSecondary
                    ),
                    "commandPools" to mapOf(
                        "graphics" to ctx.graphicsPoolsPerThread,
                        "compute" to ctx.computePoolsPerThread
                    ),
                    "profiling" to ctx.profilerState
                )
            }

            override fun html(): String {
                val extent = ctx.swapChain.swapChainExtent
                val rows = listOf(
                    "image" to "${ctx.currentImage}/${ctx.numImages}",
                    "swapchain" to "${extent.width()}x${extent.height()} ${ctx.swapChain.surfaceFormat.imageFormat}",
                    "modules" to "${ctx.renderTarget.modules.size} gfx / ${ctx.renderTarget.meshModules.size} mesh",
                    "secondary" to "${ctx.graphicsSecondary.size} gfx / ${ctx.computeSecondary.size} cs"
                )
                return card(heading(), rows, accent = "#a3e635")
            }

            override fun version(): Long = (ctx.currentImage.toLong() shl 32) or ctx.numImages.toLong()
        }
    }

    reg<Window> { w, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "Window"
            override fun dir(): Map<String, Any?>? = null
            override fun html(): String = card(
                heading(),
                listOf(
                    "title" to w.title,
                    "size" to "${w.width}x${w.height}",
                    "fullscreen" to w.fullscreen.toString(),
                    "resized" to w.isResized.toString()
                ),
                accent = "#38bdf8"
            )

            override fun version(): Long = (w.width.toLong() shl 32) or w.height.toLong()
        }
    }

    // Targets --------------------------------------------------------------------------------------------------------

    reg<RenderTarget> { rt, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "RenderTarget"
            // Keys in the order RenderTarget.render records them: pre-targets, then graphics modules,
            // then mesh-shader modules (each map in insertion order), then the "others" targets.
            override fun dir(): Map<String, Any?> = linkedMapOf(
                "preTargets" to rt.preTargets,
                "modules" to rt.modules,
                "meshModules" to rt.meshModules,
                "others" to rt.others,
                "preRecorded" to (rt.preRecordedInsideRendering ?: emptyList<CommandBuffer>())
            )

            override fun html(): String {
                val rows = listOf(
                    "1. preTargets" to names(rt.preTargets.keys),
                    "2. modules" to names(rt.modules.keys),
                    "3. mesh" to names(rt.meshModules.keys),
                    "4. others" to names(rt.others.keys)
                )
                return card(heading(), rows, accent = "#c084fc")
            }

            override fun version(): Long =
                rt.modules.size + rt.meshModules.size + rt.others.size + rt.preTargets.size.toLong()
        }
    }

    reg<ComputeTarget> { ct, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "ComputeTarget"
            override fun dir(): Map<String, Any?> = linkedMapOf(
                "modules" to ct.modules,
                "others" to ct.others
            )

            override fun html(): String = card(
                heading(),
                listOf(
                    "modules" to names(ct.modules.keys),
                    "others" to names(ct.others.keys)
                ),
                accent = "#22d3ee"
            )

            override fun version(): Long = ct.modules.size.toLong()
        }
    }

    // Modules --------------------------------------------------------------------------------------------------------

    reg<ModulePointer> { mp, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: mp.current.parameters.name
            override fun dir(): Map<String, Any?> = mapOf("module" to mp.current)
            override fun html(): String = card(
                heading(),
                listOf(
                    "valid" to mp.current.valid.toString(),
                    "enabled" to mp.current.enabled.toString(),
                    "meshes" to mp.current.meshes.size.toString()
                ),
                accent = "#f97316"
            )

            override fun version(): Long = mp.current.parameters.hashCode().toLong()
        }
    }

    reg<MeshModulePointer> { mp, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: mp.current.parameters.name
            override fun dir(): Map<String, Any?> = mapOf("module" to mp.current)
            override fun html(): String = card(
                heading(),
                listOf(
                    "valid" to mp.current.valid.toString(),
                    "enabled" to mp.current.enabled.toString(),
                    "meshes" to mp.current.meshes.size.toString()
                ),
                accent = "#fb7185"
            )

            override fun version(): Long = mp.current.parameters.hashCode().toLong()
        }
    }

    reg<ComputeModulePointer> { mp, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: mp.current.parameters.name
            override fun dir(): Map<String, Any?> = mapOf("module" to mp.current)
            override fun html(): String = card(
                heading(),
                listOf(
                    "valid" to mp.current.valid.toString(),
                    "enabled" to mp.current.enabled.toString(),
                    "tasks" to mp.current.meshes.size.toString()
                ),
                accent = "#0ea5e9"
            )

            override fun version(): Long = mp.current.parameters.hashCode().toLong()
        }
    }

    reg<Module> { m, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: m.parameters.name
            override fun dir(): Map<String, Any?> = linkedMapOf(
                "parameters" to m.parameters,
                "shaders" to shaderStages(m.parameters),
                "uniforms" to m.uniforms,
                "liveUniforms" to m.liveUniformStructures,
                "meshes" to m.meshes
            )

            override fun html(): String {
                val rows = listOf(
                    "valid" to m.valid.toString(),
                    "enabled" to m.enabled.toString(),
                    "pipelines" to if (m.pipeline != 0L) "built" else "missing",
                    "uniforms" to m.uniforms.size.toString(),
                    "meshes" to m.meshes.size.toString(),
                    "shaders" to stagesSummary(m.parameters)
                )
                return card(heading(), rows, accent = "#22c55e")
            }

            override fun version(): Long = m.parameters.renderer.frameCounter / LIVE_FRAMES
        }
    }

    reg<MeshModule> { m, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: m.parameters.name
            override fun dir(): Map<String, Any?> = linkedMapOf(
                "parameters" to m.parameters,
                "shaders" to shaderStages(m.parameters),
                "uniforms" to m.uniforms,
                "liveUniforms" to m.liveUniformStructures,
                "meshes" to m.meshes
            )

            override fun html(): String {
                val rows = listOf(
                    "valid" to m.valid.toString(),
                    "enabled" to m.enabled.toString(),
                    "meshes" to m.meshes.size.toString(),
                    "shaders" to stagesSummary(m.parameters)
                )
                return card(heading(), rows, accent = "#d946ef")
            }

            override fun version(): Long = m.parameters.renderer.frameCounter / LIVE_FRAMES
        }
    }

    reg<ComputeModule> { m, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: m.parameters.name
            override fun dir(): Map<String, Any?> = linkedMapOf(
                "parameters" to m.parameters,
                "shaders" to shaderStages(m.parameters),
                "uniforms" to m.uniforms,
                "liveUniforms" to m.liveUniformStructures,
                "tasks" to m.meshes
            )

            override fun html(): String {
                val rows = listOf(
                    "valid" to m.valid.toString(),
                    "enabled" to m.enabled.toString(),
                    "tasks" to m.meshes.size.toString(),
                    "shaders" to stagesSummary(m.parameters)
                )
                return card(heading(), rows, accent = "#38bdf8")
            }

            override fun version(): Long = m.parameters.renderer.frameCounter / LIVE_FRAMES
        }
    }

    reg<Parameters> { p, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: p.name
            override fun dir(): Map<String, Any?>? = null
            override fun html(): String {
                val rows = listOf(
                    "name" to p.name,
                    "color" to "${p.color} attachments @ ${p.imageFormat}",
                    "depth" to if (p.depth > 0) "enabled (${p.depthFormat})" else "disabled",
                    "primitive" to p.primitiveType.toString(),
                    "viewport" to (p.viewport?.let { "${it.w.toInt()}x${it.h.toInt()}" } ?: "full"),
                    "blend" to p.blend.toString()
                )
                return card(heading(), rows, accent = "#f59e0b")
            }

            override fun version(): Long = (p.name.hashCode().toLong() shl 32) or p.imageFormat.toLong()
        }
    }

    reg<Module.Uniform> { u, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: u.name
            override fun dir(): Map<String, Any?> = mapOf("buffer" to u.buffer, "source" to u.source)
            override fun html(): String = card(
                heading(),
                listOf(
                    "set/binding" to "${u.binding.set}/${u.binding.binding}",
                    "kind" to "UBO/SSBO",
                    "size" to u.buffer.get().requestedSize.toString()
                ),
                accent = "#67e8f9"
            )
        }
    }

    reg<Module.TexturePointer> { t, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: t.name
            override fun dir(): Map<String, Any?> = mapOf(
                "texture" to t.texture,
                "sampler" to t.sampler
            )

            override fun html(): String = card(
                heading(),
                listOf(
                    "set/binding" to "${t.binding.set}/${t.binding.binding}",
                    "views" to t.texture.imageViewArray.size.toString()
                ),
                accent = "#f472b6"
            )
        }
    }

    reg<Module.TextureArrayPointer> { t, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: t.name
            override fun dir(): Map<String, Any?> = mapOf(
                "texture" to t.texture,
                "sampler" to t.sampler
            )

            override fun html(): String = card(
                heading(),
                listOf(
                    "set/binding" to "${t.binding.set}/${t.binding.binding}",
                    "views" to t.texture.imageViewArray.size.toString()
                ),
                accent = "#c4b5fd"
            )
        }
    }

    reg<Module.ImagePointer> { t, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: t.name
            override fun dir(): Map<String, Any?> = mapOf("image" to t.texture)
            override fun html(): String = card(
                heading(),
                listOf("set/binding" to "${t.binding.set}/${t.binding.binding}"),
                accent = "#fb7185"
            )
        }
    }

    // Meshes --------------------------------------------------------------------------------------------------------

    reg<Mesh> { m, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "Mesh"
            override fun dir(): Map<String, Any?> = linkedMapOf(
                "vertices" to m.v,
                "namedVertices" to m.vn,
                "triangleCount" to m.numTriangle,
                "vertexCount" to m.numVert,
                "pushConstants" to m.push
            )

            override fun html(): String = card(
                heading(),
                listOf(
                    "verts" to m.numVert.toString(),
                    "triangles" to m.numTriangle.toString(),
                    "instances" to m.instanceCount.toString()
                ),
                accent = "#10b981"
            )
        }
    }

    reg<MeshMesh> { m, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "Mesh task"
            override fun dir(): Map<String, Any?> = mapOf("pushConstants" to m.push)
            override fun html(): String = card(
                heading(),
                listOf("x/y/z" to "${m.x} / ${m.y} / ${m.z}"),
                accent = "#f97316"
            )
        }
    }

    reg<ComputeMesh> { m, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "Compute task"
            override fun dir(): Map<String, Any?> = mapOf("pushConstants" to m.push)
            override fun html(): String = card(
                heading(),
                listOf("x/y/z" to "${m.x} / ${m.y} / ${m.z}"),
                accent = "#22d3ee"
            )
        }
    }

    // Textures ------------------------------------------------------------------------------------------------------

    reg<Attachment> { a, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: if (a.isDepthAttachment) "Depth Attachment" else "Attachment"
            override fun dir(): Map<String, Any?> = mapOf("image" to a.image, "view" to a.imageView)
            override fun html(): String = card(
                heading(),
                listOf(
                    "depth" to a.isDepthAttachment.toString(),
                    "format" to a.image.format.toString()
                ),
                accent = "#60a5fa"
            )
        }
    }

    reg<Image> { img, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "Image"
            override fun dir(): Map<String, Any?>? = null
            override fun html(): String = card(
                heading(),
                listOf(
                    "format" to img.format.toString(),
                    "mips" to img.mipLevels.toString(),
                    "handle" to hex(img.vkImage)
                ),
                accent = "#0ea5e9"
            )
        }
    }

    reg<ImageView> { view, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "ImageView"
            override fun dir(): Map<String, Any?> = view.underlyingImage?.let { mapOf("image" to it) } ?: emptyMap()
            override fun html(): String = card(
                heading(),
                listOf(
                    "format" to view.imageViewData.format.toString(),
                    "mips" to view.imageViewData.mipLevels.toString(),
                    "view" to hex(view.vkImageView)
                ),
                accent = "#a78bfa"
            )
        }
    }

    reg<LoadedTexture> { tex, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: tex.fileName
            override fun dir(): Map<String, Any?> = mapOf("image" to tex.image, "view" to tex.imageView)
            override fun html(): String = card(
                heading(),
                listOf(
                    "size" to "${tex.width}x${tex.height}",
                    "format" to tex.image.format.toString(),
                    "staging" to (tex.stgBuffer != null).toString()
                ),
                accent = "#f472b6"
            )
        }
    }

    reg<HasImageView> { hv, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: hv.imageView.toString()
            override fun dir(): Map<String, Any?> = mapOf("view" to hv.imageView)
            override fun html(): String = card(
                heading(),
                listOf("view" to hex(hv.imageView.vkImageView)),
                accent = "#22c55e"
            )
        }
    }

    reg<TextureSampler> { s, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "Sampler"
            override fun dir(): Map<String, Any?>? = null
            override fun html(): String = card(heading(), listOf("handle" to hex(s.vkSampler)), accent = "#fcd34d")
        }
    }

    reg<VideoTexture> { v, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "VideoTexture"
            override fun dir(): Map<String, Any?>? = null
            override fun html(): String {
                val width = readField<Int>(v, "videoWidth") ?: 0
                val height = readField<Int>(v, "videoHeight") ?: 0
                val playing = readField<Boolean>(v, "isPlaying") ?: false
                val ts = readField<Double>(v, "currentTimestamp") ?: 0.0
                val path = readField<String>(v, "currentVideoPath") ?: "(none)"
                val slot = readField<Any>(v, "currentSlot")?.let { (it as? java.util.concurrent.atomic.AtomicInteger)?.get() } ?: 0
                return card(
                    heading(),
                    listOf(
                        "video" to path,
                        "size" to if (width > 0) "${width}x${height}" else "unloaded",
                        "timestamp" to "%.2fs".format(ts),
                        "playing" to playing.toString(),
                        "slot" to slot.toString()
                    ),
                    accent = "#fb7185"
                )
            }

            override fun version(): Long =
                (readField<java.util.concurrent.atomic.AtomicInteger>(v, "currentSlot")?.get()?.toLong() ?: 0L) + v.timestamp.hashCode()
        }
    }

    // Device/runtime -------------------------------------------------------------------------------------------------

    reg<SwapChain> { sc, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "SwapChain"
            override fun dir(): Map<String, Any?> = linkedMapOf(
                "images" to sc.imageViews.toList(),
                "syncSemaphores" to sc.syncSemaphoresList.toList()
            )

            override fun html(): String {
                val rows = listOf(
                    "extent" to "${sc.swapChainExtent.width()}x${sc.swapChainExtent.height()}",
                    "format" to sc.surfaceFormat.imageFormat.toString(),
                    "images" to sc.imageViews.size.toString(),
                    "currentFrame" to sc.currentFrame.toString()
                )
                return card(heading(), rows, accent = "#60a5fa")
            }

            override fun version(): Long = sc.currentFrame.toLong()
        }
    }

    reg<Queue> { q, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "Queue"
            override fun dir(): Map<String, Any?>? = null
            override fun html(): String = card(
                heading(),
                listOf(
                    "family" to q.queueFamilyIndex.toString(),
                    "handle" to hex(q.vkQueue.address())
                ),
                accent = "#facc15"
            )
        }
    }

    reg<CommandBuffer> { cb, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "CommandBuffer"
            override fun dir(): Map<String, Any?>? = null
            override fun html(): String = card(
                heading(),
                listOf("handle" to hex(cb.vkCommandBuffer.address())),
                accent = "#a3e635"
            )
        }
    }

    reg<CommandPool> { cp, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "CommandPool"
            override fun dir(): Map<String, Any?>? = null
            override fun html(): String = card(
                heading(),
                listOf(
                    "family" to cp.queueFamilyIndex.toString(),
                    "handle" to hex(cp.vkCommandPool)
                ),
                accent = "#f97316"
            )
        }
    }

    // Profiling ------------------------------------------------------------------------------------------------------

    reg<Renderer.ProfilerState> { ps, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "ProfilerState"
            override fun dir(): Map<String, Any?> = linkedMapOf(
                "profiler" to ps.profiler,
                "markers" to ps.markers.toList(),
                "perImageModuleMarks" to ps.perImageModuleMarks.withIndex().associate { (i, v) -> "image[$i]" to v },
                "pending" to ps.pending
            )

            override fun html(): String = card(
                heading(),
                listOf(
                    "markers" to ps.markers.size.toString(),
                    "pending" to ps.pending.size.toString()
                ),
                accent = "#22c55e"
            )

            override fun version(): Long = ps.pending.size.toLong()
        }
    }

    reg<Renderer.FrameMarkers> { m, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "Frame markers"
            override fun dir(): Map<String, Any?> = emptyMap()
            override fun html(): String = card(
                heading(),
                listOf(
                    "frame" to m.perfFrameIndex.toString(),
                    "ts" to "${m.tsFrameBegin}/${m.tsAfterCompute}/${m.tsAfterGraphics}/${m.tsFrameEnd}",
                    "pipeStats" to "${m.pipeStatsCompute}/${m.pipeStatsGraphics}"
                ),
                accent = "#c084fc"
            )
        }
    }

    reg<Renderer.ModuleMarks> { m, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: m.name
            override fun dir(): Map<String, Any?> = emptyMap()
            override fun html(): String = card(
                heading(),
                listOf(
                    "timestamps" to "${m.tsBegin}/${m.tsEnd}",
                    "pipeStats" to m.pipeStatsIndex.toString(),
                    "perf" to m.perfIndex.toString()
                ),
                accent = "#fb7185"
            )
        }
    }

    reg<GpuProfiler> { p, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "GpuProfiler"
            override fun dir(): Map<String, Any?> = mapOf("perfMeta" to p.perfMeta)
            override fun html(): String = card(
                heading(),
                listOf(
                    "enabled" to p.enabled.toString(),
                    "timestamps" to p.timestampsEnabled.toString(),
                    "pipeStats" to p.pipeStatsEnabled.toString(),
                    "perfCounters" to p.perfQueryEnabled.toString(),
                    "period(ns)" to "%.2f".format(p.timestampPeriodNs)
                ),
                accent = "#4ade80"
            )
        }
    }

    reg<ProfilingOptions> { o, _, title ->
        object : Browsable {
            override fun heading(): String = title ?: "ProfilingOptions"
            override fun dir(): Map<String, Any?> = emptyMap()
            override fun html(): String = card(
                heading(),
                listOf(
                    "enabled" to o.enabled.toString(),
                    "timestamps" to o.timestamps.toString(),
                    "pipelineStats" to o.pipelineStats.toString(),
                    "perfCounters" to o.perfCounters.toString()
                ),
                accent = "#93c5fd"
            )
        }
    }
}

Registers adapter with BrowsableAdapters, shaped so its card is seen: the inspector shows html() only for leaves, so a node with children gets its card as a first summary row, and a node whose dir() is empty becomes a leaf.

private inline fun <reified T : Any> reg(noinline adapter: (T, Browsable?, String?) -> Browsable?) {
    BrowsableAdapters.register(T::class) { v: T, parent, title -> adapter(v, parent, title)?.let(::withSummaryRow) }
}

internal fun withSummaryRow(b: Browsable): Browsable

internal fun withSummaryRow(b: Browsable): Browsable {
    val d = b.dir()
    if (d.isNullOrEmpty()) return object : Browsable {
        override fun heading(): String = b.heading()
        override fun html(): String? = b.html()
        override fun version(): Long = b.version()
    }
    if (b.html() == null) return b
    return object : Browsable {
        override fun heading(): String = b.heading()
        override fun dir(): Map<String, Any?> = linkedMapOf<String, Any?>("summary" to SummaryCard(b)) + (b.dir() ?: emptyMap())
        override fun version(): Long = b.version()
    }
}

The card of a directory node, as a leaf row.

private class SummaryCard(val of: Browsable) : Browsable {
    override fun heading(): String = of.heading()
    override fun html(): String? = of.html()
    override fun version(): Long = of.version()
    override fun toString(): String = "card"
    override fun equals(other: Any?) = other is SummaryCard && other.of.heading() == of.heading()
    override fun hashCode(): Int = of.heading().hashCode()
}

helpers

private fun card(title: String, rows: List<Pair<String, String>>, accent: String = "#9ca3af"): String {
    val body = rows.joinToString("") { (k, v) ->
        """
        <div style="display:flex;gap:6px;align-items:flex-start;padding:1px 0;">
          <div style="flex:0 0 80px;text-align:right;color:#6b7280;font-size:11px;letter-spacing:.05em;text-transform:uppercase;">${escapeHtml(k)}</div>
          <div style="flex:0 0 6px;text-align:center;color:#4b5563;">|</div>
          <div style="flex:1;">${ToStringHighlighter.render(v)}</div>
        </div>
        """.trimIndent()
    }
    return """
      <div style="padding:4px 0;font-family:inherit;">
        $body
      </div>
    """.trimIndent()
}

private fun names(keys: Collection<String>): String = if (keys.isEmpty()) "-" else keys.joinToString(", ")

internal fun shaderStages(p: Parameters): Map<String, String>

The shader stages p has source for, stage name to GLSL source, in pipeline order.

internal fun shaderStages(p: Parameters): Map<String, String> = linkedMapOf(
    "task" to p.task, "mesh" to p.mesh, "vertex" to p.vertex, "fragment" to p.fragment, "compute" to p.compute,
    "raygen" to p.raygen, "miss" to p.miss, "closesthit" to p.closesthit, "anyhit" to p.anyhit,
    "intersection" to p.intersection, "callable" to p.callable,
).filterValues { it.isNotBlank() }

internal fun stagesSummary(p: Parameters): String

vertex 11 lines · fragment 8 lines: which stages a module has, and how big each is.

internal fun stagesSummary(p: Parameters): String =
    shaderStages(p).entries.joinToString(" · ") { (k, v) -> "$k ${v.lines().size} lines" }.ifBlank { "-" }

private fun hex(v: Long): String = "0x" + v.toString(16)

private fun fmt(v: Double): String = String.format("%.2f", v)

private fun escapeHtml(s: String): String =
    s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")

private fun <T> readField(target: Any, name: String): T? {
    return runCatching {
        val f: Field = target.javaClass.getDeclaredField(name)
        f.isAccessible = true
        @Suppress("UNCHECKED_CAST")
        f.get(target) as T?
    }.getOrNull()
}

Browsable CPU node (stable identity for change pushes)

source — 47 lines, from line 818
private object CpuNode : Browsable {
    override fun heading(): String = "CPU"
    override fun toString(): String = CPUSpan.snapshot().let { if (it.isEmpty()) "no samples" else "${it.size} spans" }
    override fun dir(): Map<String, Any?>? = null
    override fun html(): String {
        val snaps = CPUSpan.snapshot()
        if (snaps.isEmpty()) return "<div style='color:#6b7280;'>no samples</div>"

        val header = listOf("span", "p1", "p10", "p50", "p90", "p99")
        val rows = snaps.joinToString("") { s ->
            """
            <div style="display:grid;grid-template-columns:120px repeat(5,70px);gap:8px;align-items:center;padding:2px 0;">
              <div style="color:#e5e7eb;font-family:'JetBrains Mono','SFMono-Regular',monospace;">${escapeHtml(s.label)}</div>
              <div style="color:#cbd5e1;text-align:right;font-family:'JetBrains Mono','SFMono-Regular',monospace;">${fmt(s.p1Ms)}</div>
              <div style="color:#cbd5e1;text-align:right;font-family:'JetBrains Mono','SFMono-Regular',monospace;">${fmt(s.p10Ms)}</div>
              <div style="color:#e5e7eb;text-align:right;font-family:'JetBrains Mono','SFMono-Regular',monospace;">${fmt(s.p50Ms)}</div>
              <div style="color:#fbbf24;text-align:right;font-family:'JetBrains Mono','SFMono-Regular',monospace;">${fmt(s.p90Ms)}</div>
              <div style="color:#f97316;text-align:right;font-family:'JetBrains Mono','SFMono-Regular',monospace;">${fmt(s.p99Ms)}</div>
            </div>
            """.trimIndent()
        }
        val headRow = header.joinToString("") {
            """
            <div style="text-transform:uppercase;font-size:11px;letter-spacing:.08em;color:#9ca3af;text-align:${if (it == "span") "left" else "right"};font-family:'JetBrains Mono','SFMono-Regular',monospace;">${escapeHtml(it)}</div>
            """.trimIndent()
        }
        val n = snaps.firstOrNull()?.n ?: 0
        return """
        <div style="padding:4px 0;font-family:inherit;">
          <div style="color:#6b7280;font-size:11px;letter-spacing:.05em;text-transform:uppercase;margin-bottom:4px;">window · $n samples</div>
          <div style="display:grid;grid-template-columns:120px repeat(5,70px);gap:8px;padding:2px 0;border-bottom:1px solid #1f2937;">$headRow</div>
          $rows
        </div>
        """.trimIndent()
    }

    override fun version(): Long = CPUSpan.version()
}

private fun maybePushCpuChanged(intervalMs: Long = 1000) {
    val now = System.currentTimeMillis()
    val last = cpuLastPushMs.get()
    if (now - last < intervalMs) return
    if (cpuLastPushMs.compareAndSet(last, now)) {
        Inspector.changed(CpuNode)
    }
}