Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions .github/workflows/ci-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,6 @@ jobs:
--skip 'UntoldEngineRenderTests.RemoteStreamFlyThroughTests' \
--skip 'UntoldEngineRenderTests.PerformanceTests'

# ✅ Run remote streaming PSNR in isolation.
# The flythrough test mutates streaming budgets and waits on remote tile
# residency; running it inside the broad parallel sweep can capture an
# unsettled waypoint frame even when the same test is deterministic alone.
- name: Run remote stream flythrough PSNR
timeout-minutes: 20
env:
CI: true
UNTOLD_PSNR_THRESHOLD: "33.5"
UNTOLD_PYTHON: "python3"
run: |
command -v "${UNTOLD_PYTHON}" >/dev/null 2>&1 || { echo "python not found"; exit 1; }
swift test -v --disable-swift-testing --filter 'UntoldEngineRenderTests.RemoteStreamFlyThroughTests/testRemoteStreamFlythrough_psnr'

# ✅ Run performance benchmarks as CI gates, isolated from the parallel renderer suite.
# These numbers are intentionally configurable because GitHub-hosted macOS runners
# are shared machines. They still fail the build on meaningful regressions, while
Expand Down
8 changes: 2 additions & 6 deletions Sources/Demos/LargeSceneStreamingDemo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
@MainActor
@Observable
final class LargeSceneStreamingState {
var status = "Loading default remote scene..."
var status = "Loading offline reference field..."
var customManifestURL = ""
var isLoading = false
var tileBoundsEnabled = true
Expand All @@ -47,7 +47,7 @@
setupWindow()
setupRendererAndScene()
presentSceneView()
gameScene.loadPreset(.dungeon)
gameScene.loadFallbackField()
}

func applicationShouldTerminateAfterLastWindowClosed(_: NSApplication) -> Bool {
Expand Down Expand Up @@ -99,7 +99,6 @@
renderer: renderer,
state: state,
actions: .init(
loadPreset: { [weak self] preset in self?.gameScene.loadPreset(preset) },
loadCustomURL: { [weak self] url in self?.gameScene.loadManifest(url: url, label: "Custom Manifest") },
loadFallbackField: { [weak self] in self?.gameScene.loadFallbackField() },
setTileBounds: { [weak self] enabled in self?.gameScene.setTileBoundsDebug(enabled) },
Expand All @@ -116,7 +115,6 @@
}

private struct LargeSceneStreamingActions {
let loadPreset: (GameScene.RemoteScenePreset) -> Void
let loadCustomURL: (URL) -> Void
let loadFallbackField: () -> Void
let setTileBounds: (Bool) -> Void
Expand Down Expand Up @@ -155,8 +153,6 @@
}

HStack {
Button("Dungeon") { actions.loadPreset(.dungeon) }
Button("City") { actions.loadPreset(.city) }
Button("Field") { actions.loadFallbackField() }
}

Expand Down
29 changes: 2 additions & 27 deletions Sources/Demos/LargeSceneStreamingDemo/GameScene.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,8 @@
import UntoldEngine

final class GameScene: @unchecked Sendable {
enum RemoteScenePreset: String, CaseIterable {
case dungeon = "Dungeon"
case city = "City"

var manifestURL: URL {
switch self {
case .dungeon:
URL(string: "https://d8pyi1c08k1w.cloudfront.net/dungeon3/dungeon3.json")!
case .city:
URL(string: "https://d8pyi1c08k1w.cloudfront.net/city/city.json")!
}
}

var cameraEye: simd_float3 {
switch self {
case .dungeon: simd_float3(0.0, 4.0, 18.0)
case .city: simd_float3(0.0, 18.35, 73.56)
}
}
}

private enum Constants {
static let defaultCameraEye = simd_float3(0.0, 4.0, 18.0)
static let cameraMoveSpeed: Float = 9.0
static let cameraInputDeltaTime: Float = 1.0 / 60.0
static let orbitTargetOffset: Float = 25.0
Expand All @@ -64,11 +44,6 @@
setSceneReady(false)
}

func loadPreset(_ preset: RemoteScenePreset) {
placeCamera(eye: preset.cameraEye)
loadManifest(url: preset.manifestURL, label: preset.rawValue)
}

func loadManifest(url: URL, label: String) {
clearLoadedContent()
setSceneReady(false)
Expand Down Expand Up @@ -206,7 +181,7 @@
}

private func createCamera() {
makeDemoCamera(name: "Streaming Camera", eye: RemoteScenePreset.dungeon.cameraEye, orbitOffset: Constants.orbitTargetOffset)
makeDemoCamera(name: "Streaming Camera", eye: Constants.defaultCameraEye, orbitOffset: Constants.orbitTargetOffset)
}

private func createLight() {
Expand Down
3 changes: 1 addition & 2 deletions Sources/Demos/LargeSceneStreamingDemo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ What it demonstrates:
- tile bounds, LOD debug, and texture tier debug overlays
- live engine stats for streaming, batching, draw calls, and memory

The default remote scenes reuse the same public manifests as `ShowcaseDemo`. The
`Field` button loads a procedural offline reference field so the executable still
The `Field` button loads a procedural offline reference field so the executable
runs without network access, but that mode is not tile streaming.

To test your own exported world, paste a full `https://.../scene.json` or
Expand Down
51 changes: 0 additions & 51 deletions Sources/Demos/ShowcaseDemo/DemoHUD.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,26 +186,6 @@
resolutionMenu
}

HStack(alignment: .center, spacing: 8) {
Picker("Remote Scene", selection: $state.selectedRemoteSceneID) {
ForEach(state.remoteScenes) { scene in
Text(scene.title).tag(scene.id)
}
}
.pickerStyle(.menu)
.frame(maxWidth: .infinity, alignment: .leading)
.disabled(state.isLoading || state.remoteScenes.isEmpty)
Button("Load", action: loadSelectedRemoteScene)
.buttonStyle(.borderedProminent)
.tint(.blue)
.disabled(state.isLoading || state.selectedRemoteScene?.manifestURL == nil)
if state.isLoading {
ProgressView()
.scaleEffect(0.6)
.frame(width: 16, height: 16)
}
}

HStack(alignment: .center, spacing: 8) {
Text("Local Scene")
.foregroundStyle(.secondary)
Expand Down Expand Up @@ -495,30 +475,6 @@
.disabled(!enabled)
}

private func loadSelectedRemoteScene() {
guard let scene = state.selectedRemoteScene,
let manifestURL = scene.manifestURL,
let onLoadTiledScene = state.onLoadTiledScene
else { return }

state.batchingEnabled = false
state.streamingEnabled = false
state.isLoading = true

let sceneID = scene.id
onLoadTiledScene(sceneID, manifestURL) { success in
Task { @MainActor in
state.isLoading = false
state.hasLoadedEntity = success
state.streamingEnabled = success
if success {
state.selectedPostFXPreset = Self.postFXPreset(for: sceneID)
state.applySelectedPostFXPreset()
}
}
}
}

private func openLocalAssetPicker() {
localImportMode = .asset
showFilePicker = true
Expand Down Expand Up @@ -590,13 +546,6 @@
}
}

private static func postFXPreset(for sceneID: String) -> DemoState.PostFXPreset {
switch sceneID {
case "f1car", "airplane", "porsche964": .cinematic
default: .neutral
}
}

private func finishLocalImport(url: URL, accessing: Bool, success: Bool, streamingEnabled: Bool) {
state.isLoading = false
state.hasLoadedEntity = success
Expand Down
39 changes: 0 additions & 39 deletions Sources/Demos/ShowcaseDemo/DemoState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
private enum Defaults {
static let streamingRadius: Double = 200.0
static let unloadRadius: Double = 350.0
static let selectedRemoteSceneID = "dungeon"
}

enum PostFXPreset: String, CaseIterable, Identifiable {
Expand Down Expand Up @@ -70,48 +69,10 @@

@ObservationIgnored private var isApplyingPostFXPreset = false

struct RemoteSceneOption: Identifiable, Hashable {
let id: String
let title: String
let manifestURL: URL?
}

// MARK: - File Loading

var hasLoadedEntity: Bool = false
var isLoading: Bool = false
let remoteScenes: [RemoteSceneOption] = [
.init(
id: "dungeon",
title: "Game Dungeon",
manifestURL: URL(string: "https://d8pyi1c08k1w.cloudfront.net/dungeon3/dungeon3.json")!
),
.init(
id: "city",
title: "Cartoon City",
manifestURL: URL(string: "https://d8pyi1c08k1w.cloudfront.net/city/city.json")!
),
.init(
id: "f1car",
title: "Formula 1",
manifestURL: URL(string: "https://d8pyi1c08k1w.cloudfront.net/F1Car/F1Car.json")!
),
.init(
id: "airplane",
title: "Skyhawk",
manifestURL: URL(string: "https://d8pyi1c08k1w.cloudfront.net/Shyhawk_stream/Skyhawks.json")!
),
.init(
id: "porsche964",
title: "Porsche 964",
manifestURL: URL(string: "https://d8pyi1c08k1w.cloudfront.net/Porsche964-stream/Porsche964-stream.json")!
),
]
var selectedRemoteSceneID: String = Defaults.selectedRemoteSceneID

var selectedRemoteScene: RemoteSceneOption? {
remoteScenes.first { $0.id == selectedRemoteSceneID }
}

var localSceneAuthoredEnabled: Bool = false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ final class RemoteStreamFlyThroughTests: BaseRenderSetup {

/// Remote (or local file://) URL of your tile manifest.
/// Override at runtime with the UNTOLD_STREAM_MANIFEST_URL env var.
private let manifestURLString = "https://d8pyi1c08k1w.cloudfront.net/city/city.json"
private let manifestURLString = "https://cdn.example.com/dungeon/dungeon.json"

/// Waypoints the camera visits. At each stop a screenshot is taken.
/// Adjust positions and look-at targets to match your dungeon layout.
Expand Down Expand Up @@ -147,7 +147,10 @@ final class RemoteStreamFlyThroughTests: BaseRenderSetup {

// -------------------------------------------------------------------------

func testGenerateFlythroughReferenceImages() async throws {
// Disabled: no remote manifest URL is configured (the AWS/CloudFront URL
// used previously was removed). Re-enable by restoring `test` as the
// method-name prefix once a replacement manifest host is available.
func disabled_testGenerateFlythroughReferenceImages() async throws {
guard ProcessInfo.processInfo.environment["UNTOLD_REGENERATE_REFERENCES"] == "1" else {
throw XCTSkip("Reference generation is opt-in. Set UNTOLD_REGENERATE_REFERENCES=1 to run.")
}
Expand Down Expand Up @@ -178,7 +181,10 @@ final class RemoteStreamFlyThroughTests: BaseRenderSetup {

// -------------------------------------------------------------------------

func testRemoteStreamFlythrough_psnr() async throws {
// Disabled: no remote manifest URL is configured (the AWS/CloudFront URL
// used previously was removed). Re-enable by restoring `test` as the
// method-name prefix once a replacement manifest host is available.
func disabled_testRemoteStreamFlythrough_psnr() async throws {
let sceneRoot = try await loadRemoteScene()
await hydrateFlythroughRoute(sceneRoot: sceneRoot)

Expand Down
Loading