Compare commits
4
Commits
9e921a5b3b
...
93946c1d24
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93946c1d24 | ||
|
|
7c777eba7c | ||
|
|
af836785d3 | ||
|
|
ba8bf45dbc |
@@ -47,5 +47,8 @@ if(TARGET faset_ui AND TARGET faset_editor_session AND TARGET faset_scene_view)
|
||||
set_tests_properties(editor_ui_gizmos PROPERTIES LABELS "gpu")
|
||||
add_test(NAME editor_ui_authoring COMMAND faset_editor_ui_tests)
|
||||
set_tests_properties(editor_ui_authoring PROPERTIES LABELS "gpu")
|
||||
add_executable(faset_editor_ui_latency ${PROJECT_SOURCE_DIR}/tests/editor_ui_latency.cpp)
|
||||
target_link_libraries(faset_editor_ui_latency PRIVATE faset_editor_ui)
|
||||
target_compile_definitions(faset_editor_ui_latency PRIVATE FASET_TEST_ENGINE="${PROJECT_SOURCE_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -57,7 +57,7 @@ were installed. This proves linkage and CPU validation, not graphics compatibili
|
||||
## September 24 Release follow-up
|
||||
|
||||
The [Release execution record](lua-release-2026-09-24/README.md) closes the
|
||||
Linux offscreen export gap above. At source commit `846f1f4`, a Release Editor
|
||||
Linux offscreen export gap above. At source commit `4331857`, a Release Editor
|
||||
exported the checked-in Lua-only sample into a disposable Unicode-path project.
|
||||
The package was relocated, the source project path was hidden, and its Player
|
||||
validated and rendered 120 frames on an NVIDIA GeForce RTX 2080 Ti with driver
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Lua-only Release game: relocated execution
|
||||
|
||||
This is a local Linux result for source revision
|
||||
`846f1f459d61ee0f878ab9ad116ac0e75d74d588` on 2026-09-24. The
|
||||
`433185717e1f324acb6eaf186818589d11697453` on 2026-09-24. The
|
||||
[machine-readable report](report.json) records the exact source input hashes,
|
||||
Release package, Editor binary hash, command arguments and elapsed times. The
|
||||
Editor itself was built with the `linux-release` preset. The exported Player
|
||||
@@ -25,6 +25,10 @@ resource/timing definitions; the [validate](lua-validate.json),
|
||||
results. The [PNG preview](lua.png) is a lossless conversion of the checked
|
||||
PPM.
|
||||
|
||||
The verifier also confirmed a clean Git source tree, rejected undeclared
|
||||
package files and unexpected C++ script files, classified the selected device
|
||||
as physical, and found the sample Lua `on_start` log in the relocated run.
|
||||
|
||||
To repeat this check from a built checkout, choose a **new, empty** output
|
||||
directory:
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"asset_generations": {},
|
||||
"build_fingerprint": "55f8ff15cb5e4f241fcf7ee436a52a5a1eed36f2031f12bf44070276d796927e",
|
||||
"build_fingerprint": "b745490f85f05987d849f6bb6f4d06953883f4b8e10c5551fadf164c7eec5857",
|
||||
"configuration": "Release",
|
||||
"executable": "faset_player",
|
||||
"files": [
|
||||
@@ -136,7 +136,7 @@
|
||||
},
|
||||
{
|
||||
"path": "faset_player",
|
||||
"sha256": "c9f626134e0742eb015da1c02ca2587471f30261042830631f55307b1ec4ac71",
|
||||
"sha256": "99d7b8286a9151ec4eff9a9899e862d987048b031e1e40ca1938646afbde37bd",
|
||||
"size": 6329192
|
||||
},
|
||||
{
|
||||
@@ -166,7 +166,7 @@
|
||||
}
|
||||
],
|
||||
"format": "faset.export",
|
||||
"generation": "38d65abf-1c6d-4e6e-850a-5a4916e36b16",
|
||||
"generation": "aa31bf16-984e-4854-b46f-15655bd6cc67",
|
||||
"lua_enabled": true,
|
||||
"lua_fingerprint": "a9261789bb1e0ca38bd40b08b0454165cd51454cba3ad4725dd357812ced6e35",
|
||||
"platform": "linux",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"arguments": [
|
||||
"/tmp/faset-playable-exports-yz70irb6/Faset Café 世界/lua/faset_player",
|
||||
"/tmp/faset-playable-exports-8wzkrc_u/Faset Café 世界/lua/faset_player",
|
||||
"--headless",
|
||||
"--frames",
|
||||
"120",
|
||||
"--capture",
|
||||
"/tmp/faset-playable-exports-yz70irb6/Faset Café 世界/lua/verification.ppm",
|
||||
"/tmp/faset-playable-exports-8wzkrc_u/Faset Café 世界/lua/verification.ppm",
|
||||
"--profile",
|
||||
"/tmp/faset-playable-exports-yz70irb6/Faset Café 世界/lua/profile.json"
|
||||
"/tmp/faset-playable-exports-8wzkrc_u/Faset Café 世界/lua/profile.json"
|
||||
],
|
||||
"cwd": "/tmp/faset-playable-exports-yz70irb6/empty-working-directory",
|
||||
"seconds": 0.6078518449794501,
|
||||
"cwd": "/tmp/faset-playable-exports-8wzkrc_u/empty-working-directory",
|
||||
"seconds": 0.6288121230027173,
|
||||
"exit_code": 0,
|
||||
"timed_out": false,
|
||||
"stdout": "{\"device\":\"NVIDIA GeForce RTX 2080 Ti\",\"dimension\":2,\"effective_visibility_mode\":\"direct\",\"frames\":120,\"gpu_visibility_active\":false,\"ticks\":120,\"validation_errors\":0,\"visibility_mode\":\"direct\"}\n",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"arguments": [
|
||||
"/tmp/faset-playable-exports-yz70irb6/Faset Café 世界/lua/faset_player",
|
||||
"/tmp/faset-playable-exports-8wzkrc_u/Faset Café 世界/lua/faset_player",
|
||||
"--validate"
|
||||
],
|
||||
"cwd": "/tmp/faset-playable-exports-yz70irb6/empty-working-directory",
|
||||
"seconds": 0.0062960259965620935,
|
||||
"cwd": "/tmp/faset-playable-exports-8wzkrc_u/empty-working-directory",
|
||||
"seconds": 0.007359832990914583,
|
||||
"exit_code": 0,
|
||||
"timed_out": false,
|
||||
"stdout": "{\"dimension\":2,\"validated\":true}\n",
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
{
|
||||
"format": "faset.playable-export-verification",
|
||||
"version": 1,
|
||||
"started_utc": "2026-09-23T23:20:41.969369+00:00",
|
||||
"started_utc": "2026-09-23T23:30:12.719805+00:00",
|
||||
"platform": "linux",
|
||||
"engine": "/home/emil/Desktop/.worktrees/Faset_Engine-p1-lua-export",
|
||||
"editor": "/home/emil/Desktop/.worktrees/Faset_Engine-p1-lua-export/build/linux-release/faset_editor",
|
||||
"standalone_root": "/tmp/faset-playable-exports-yz70irb6",
|
||||
"engine_revision": "846f1f459d61ee0f878ab9ad116ac0e75d74d588",
|
||||
"standalone_root": "/tmp/faset-playable-exports-8wzkrc_u",
|
||||
"engine_revision": "433185717e1f324acb6eaf186818589d11697453",
|
||||
"engine_dirty": false,
|
||||
"engine_git_status": [],
|
||||
"engine_diff_sha256": null,
|
||||
"editor_sha256": "03ac75942f5f1d29e9d6fedb21ecffc6c74f4299401dbe84f01ab1b4e9c176a0",
|
||||
"project_workspace": "/tmp/faset-playable-projects-6xvbjr4b",
|
||||
"project_workspace": "/tmp/faset-playable-projects-cuhq4iwr",
|
||||
"vulkaninfo_available": true,
|
||||
"driver_override": null,
|
||||
"frames_per_game": 120,
|
||||
@@ -44,14 +47,14 @@
|
||||
"sha256": "7e4c0781c1837208b4499a9991ffb702143edf1f933ae9c7e3d2543fd2577747"
|
||||
}
|
||||
],
|
||||
"generation": "38d65abf-1c6d-4e6e-850a-5a4916e36b16",
|
||||
"generation": "aa31bf16-984e-4854-b46f-15655bd6cc67",
|
||||
"configuration": "Release",
|
||||
"standalone_directory": "/tmp/faset-playable-exports-yz70irb6/Faset Café 世界/lua",
|
||||
"standalone_directory": "/tmp/faset-playable-exports-8wzkrc_u/Faset Café 世界/lua",
|
||||
"executable": "faset_player",
|
||||
"package_file_count": 32,
|
||||
"asset_generations": {},
|
||||
"device": "NVIDIA GeForce RTX 2080 Ti",
|
||||
"validation_enabled": true,
|
||||
"device_class": "physical",
|
||||
"driver": {
|
||||
"apiVersion": "1.4.329",
|
||||
"driverVersion": "595.84.0.0",
|
||||
@@ -60,56 +63,57 @@
|
||||
"driverName": "NVIDIA",
|
||||
"driverInfo": "595.84"
|
||||
},
|
||||
"validation_enabled": true,
|
||||
"validation_errors": 0,
|
||||
"completed_frames": 120,
|
||||
"summary_ms": {
|
||||
"gpu": {
|
||||
"max": 0.585024,
|
||||
"min": 0.558816,
|
||||
"p50": 0.560416,
|
||||
"p95": 0.577312,
|
||||
"max": 0.584992,
|
||||
"min": 0.551712,
|
||||
"p50": 0.5608,
|
||||
"p95": 0.574592,
|
||||
"samples": 120
|
||||
},
|
||||
"render_call": {
|
||||
"max": 4.487375,
|
||||
"min": 1.483498,
|
||||
"p50": 1.856402,
|
||||
"p95": 2.145527,
|
||||
"max": 4.928888,
|
||||
"min": 1.544123,
|
||||
"p50": 1.919881,
|
||||
"p95": 2.423702,
|
||||
"samples": 120
|
||||
},
|
||||
"renderer_cpu": {
|
||||
"max": 4.483287,
|
||||
"min": 1.480312,
|
||||
"p50": 1.851913,
|
||||
"p95": 2.141489,
|
||||
"max": 4.923196,
|
||||
"min": 1.540666,
|
||||
"p50": 1.915753,
|
||||
"p95": 2.420426,
|
||||
"samples": 120
|
||||
},
|
||||
"renderer_readback_cpu": {
|
||||
"max": 2.631884,
|
||||
"min": 0.383573,
|
||||
"p50": 0.508409,
|
||||
"p95": 0.57264,
|
||||
"max": 2.837363,
|
||||
"min": 0.395756,
|
||||
"p50": 0.504853,
|
||||
"p95": 0.641169,
|
||||
"samples": 120
|
||||
},
|
||||
"simulation": {
|
||||
"max": 0.21704,
|
||||
"max": 0.210056,
|
||||
"min": 0.084289,
|
||||
"p50": 0.122371,
|
||||
"p95": 0.17531,
|
||||
"p50": 0.122261,
|
||||
"p95": 0.171062,
|
||||
"samples": 120
|
||||
},
|
||||
"snapshot": {
|
||||
"max": 0.113824,
|
||||
"min": 0.046728,
|
||||
"p50": 0.067627,
|
||||
"p95": 0.102965,
|
||||
"max": 0.254931,
|
||||
"min": 0.046518,
|
||||
"p50": 0.065754,
|
||||
"p95": 0.087906,
|
||||
"samples": 120
|
||||
},
|
||||
"wall": {
|
||||
"max": 4.747145,
|
||||
"min": 1.658538,
|
||||
"p50": 2.05683,
|
||||
"p95": 2.394717,
|
||||
"max": 5.322149,
|
||||
"min": 1.702973,
|
||||
"p50": 2.142903,
|
||||
"p95": 2.634219,
|
||||
"samples": 120
|
||||
}
|
||||
},
|
||||
@@ -126,5 +130,5 @@
|
||||
"requested_projects": [
|
||||
"lua"
|
||||
],
|
||||
"finished_utc": "2026-09-23T23:22:48.305164+00:00"
|
||||
"finished_utc": "2026-09-23T23:32:18.151669+00:00"
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ int test_main(int argc, char** argv) {
|
||||
}
|
||||
#ifdef _WIN32
|
||||
int wmain(int argc, wchar_t** argv) {
|
||||
return run_utf8_main(argc, argv, test_main);
|
||||
return faset::run_utf8_main(argc, argv, test_main);
|
||||
}
|
||||
#else
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <faset/core/io.hpp>
|
||||
#include <faset/editor/editor_ui.hpp>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
using namespace faset;
|
||||
using Clock = std::chrono::steady_clock;
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: faset_editor_ui_latency OUTPUT.json\n";
|
||||
return 2;
|
||||
}
|
||||
const auto root = std::filesystem::temp_directory_path() /
|
||||
path_from_utf8("faset-ui-latency-" + new_id());
|
||||
try {
|
||||
std::filesystem::create_directories(root);
|
||||
atomic_write_json(root / "project.faset.json",
|
||||
{{"format", "faset.project"},
|
||||
{"version", 1},
|
||||
{"name", "UI latency fixture"},
|
||||
{"dimension", 3}});
|
||||
editor::Session session({root, path_from_utf8(FASET_TEST_ENGINE), root});
|
||||
render::Renderer renderer({1280, 800, "Editor input latency", true, true});
|
||||
editor::EditorUI ui(session, renderer,
|
||||
path_from_utf8(FASET_TEST_ENGINE) / "assets/fonts/NotoSans.ttf",
|
||||
path_from_utf8(FASET_TEST_ENGINE) / "assets/ui/dark.json");
|
||||
ui.frame({});
|
||||
Json samples = Json::array();
|
||||
constexpr int warmup = 10, measured = 100;
|
||||
for (int index = 0; index < warmup + measured; ++index) {
|
||||
render::Event event;
|
||||
event.type = render::Event::Type::KeyDown;
|
||||
event.key = index % 2 == 0 ? "E" : "W";
|
||||
const auto started = Clock::now();
|
||||
ui.frame({event});
|
||||
renderer.render(ui.snapshot());
|
||||
const auto elapsed = std::chrono::duration<double, std::milli>(Clock::now() - started)
|
||||
.count();
|
||||
const auto target = index % 2 == 0 ? "gizmo-Rotate" : "gizmo-Move";
|
||||
if (!ui.widgets().find(target)->selected ||
|
||||
renderer.stats().validation_errors != 0 || !std::isfinite(elapsed) ||
|
||||
elapsed <= 0)
|
||||
throw std::runtime_error("Synthetic input was not visible in a valid frame");
|
||||
if (index >= warmup)
|
||||
samples.push_back({{"iteration", index - warmup + 1},
|
||||
{"milliseconds", elapsed},
|
||||
{"gizmo", event.key == "E" ? "Rotate" : "Move"}});
|
||||
}
|
||||
atomic_write_json(path_from_utf8(argv[1]),
|
||||
{{"format", "faset.editor-ui-latency"},
|
||||
{"version", 1},
|
||||
{"warmup_frames", warmup},
|
||||
{"measured_frames", measured},
|
||||
{"presentation_mode", "offscreen"},
|
||||
{"method", "KeyDown gizmo toggle through EditorUI::frame and "
|
||||
"offscreen Vulkan render completion; no window present"},
|
||||
{"device", renderer.stats().device},
|
||||
{"validation_enabled", renderer.stats().validation_enabled},
|
||||
{"validation_errors", renderer.stats().validation_errors},
|
||||
{"samples", samples}});
|
||||
std::filesystem::remove_all(root);
|
||||
std::cout << "Measured " << measured << " synthetic Editor input frames\n";
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << "\nFixture: " << path_to_utf8(root) << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,10 @@ import unittest
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "tools"))
|
||||
from verify_playable_exports import (project_matrix, project_workspace, verify_capture,
|
||||
verify_lua_export, vulkan_device_details)
|
||||
from verify_playable_exports import (device_class, project_matrix, project_workspace,
|
||||
sha256, verify_capture, verify_lua_export,
|
||||
verify_lua_execution, verify_package,
|
||||
vulkan_device_details)
|
||||
|
||||
|
||||
class ExportProjectMatrixTests(unittest.TestCase):
|
||||
@@ -42,10 +44,12 @@ class ExportProjectMatrixTests(unittest.TestCase):
|
||||
verify_lua_export(root, manifest)
|
||||
with self.assertRaisesRegex(RuntimeError, "license"):
|
||||
verify_lua_export(root, {**manifest, "files": manifest["files"][:1]})
|
||||
(root / "Scripts/Gameplay.cpp").write_text("// stray\n", encoding="utf-8")
|
||||
(root / "Scripts/GameplayExtra.cpp").write_text("// stray\n", encoding="utf-8")
|
||||
manifest["files"].append({"path": "Scripts/GameplayExtra.cpp"})
|
||||
with self.assertRaisesRegex(RuntimeError, "C\\+\\+"):
|
||||
verify_lua_export(root, manifest)
|
||||
(root / "Scripts/Gameplay.cpp").unlink()
|
||||
(root / "Scripts/GameplayExtra.cpp").unlink()
|
||||
manifest["files"].pop()
|
||||
(root / "Notices/lua/LICENSE.txt").unlink()
|
||||
with self.assertRaisesRegex(RuntimeError, "license"):
|
||||
verify_lua_export(root, manifest)
|
||||
@@ -70,6 +74,31 @@ class ExportProjectMatrixTests(unittest.TestCase):
|
||||
{"deviceName": "Discrete GPU", "driverVersion": "123",
|
||||
"driverName": "Vendor", "driverInfo": "1.2.3"})
|
||||
self.assertEqual(vulkan_device_details(summary, "Unknown"), {})
|
||||
self.assertEqual(device_class("SwiftShader Device", {}), "software")
|
||||
self.assertEqual(device_class("NVIDIA GeForce RTX 2080 Ti", {}), "physical")
|
||||
self.assertEqual(device_class("Mystery Device", {}), "unknown")
|
||||
|
||||
def test_package_rejects_undeclared_file(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
(root / "Scripts").mkdir()
|
||||
(root / "Scripts/player.lua").write_text("return {}\n", encoding="utf-8")
|
||||
file = root / "Scripts/player.lua"
|
||||
manifest = {"format": "faset.export", "version": 1,
|
||||
"configuration": "Release", "files": [
|
||||
{"path": "Scripts/player.lua", "size": file.stat().st_size,
|
||||
"sha256": sha256(file)}]}
|
||||
import json
|
||||
(root / "manifest.json").write_text(json.dumps(manifest), encoding="utf-8")
|
||||
verify_package(root)
|
||||
(root / "Scripts/GameplayExtra.cpp").write_text("// stray\n", encoding="utf-8")
|
||||
with self.assertRaisesRegex(RuntimeError, "undeclared"):
|
||||
verify_package(root)
|
||||
|
||||
def test_lua_execution_requires_on_start_marker(self):
|
||||
verify_lua_execution("Lua player ready: A/D move, Space jump, E reset\n")
|
||||
with self.assertRaisesRegex(RuntimeError, "on_start"):
|
||||
verify_lua_execution("")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -53,6 +53,27 @@ def vulkan_device_details(summary: str, device: str) -> dict:
|
||||
return {}
|
||||
|
||||
|
||||
def device_class(device: str, driver: dict) -> str:
|
||||
identity = " ".join((device, driver.get("driverName", ""), driver.get("driverInfo", ""))).lower()
|
||||
if any(name in identity for name in ("swiftshader", "llvmpipe", "lavapipe", "softpipe")):
|
||||
return "software"
|
||||
if any(name in identity for name in ("nvidia", "geforce", "radeon", "amd", "intel", "arc")):
|
||||
return "physical"
|
||||
return "unknown"
|
||||
|
||||
|
||||
def git_identity(engine: Path) -> dict:
|
||||
def git(*arguments: str) -> str:
|
||||
return subprocess.run(["git", "-C", str(engine), *arguments], check=True,
|
||||
capture_output=True, text=True).stdout
|
||||
revision = git("rev-parse", "HEAD").strip()
|
||||
status = git("status", "--porcelain", "--untracked-files=normal")
|
||||
diff = git("diff", "--binary", "HEAD")
|
||||
return {"revision": revision, "dirty": bool(status),
|
||||
"status_lines": status.splitlines(),
|
||||
"diff_sha256": hashlib.sha256(diff.encode("utf-8")).hexdigest() if diff else None}
|
||||
|
||||
|
||||
def run(arguments: list[str | Path], cwd: Path, log: Path, timeout: int = 1800) -> dict:
|
||||
command = [str(argument) for argument in arguments]
|
||||
print(f"{log.stem}: {subprocess.list2cmdline(command)}", flush=True)
|
||||
@@ -105,6 +126,11 @@ def verify_package(directory: Path) -> dict:
|
||||
require(path.is_file() and not path.is_symlink(), f"Missing packaged file: {path}")
|
||||
require(path.stat().st_size == entry["size"] and sha256(path) == entry["sha256"],
|
||||
f"Packaged file checksum mismatch: {path}")
|
||||
declared = [entry["path"] for entry in manifest["files"]]
|
||||
actual = {path.relative_to(directory).as_posix() for path in directory.rglob("*")
|
||||
if path.is_file() or path.is_symlink()}
|
||||
require(len(declared) == len(set(declared)) and actual == set(declared) | {"manifest.json"},
|
||||
"Package has undeclared, duplicate or missing files")
|
||||
return manifest
|
||||
|
||||
|
||||
@@ -153,13 +179,20 @@ def verify_lua_export(directory: Path, manifest: dict) -> None:
|
||||
require("Notices/lua/LICENSE.txt" in {entry["path"] for entry in manifest["files"]} and
|
||||
(directory / "Notices/lua/LICENSE.txt").is_file(),
|
||||
"Lua export is missing its license notice")
|
||||
require(not (directory / "Scripts/Gameplay.cpp").exists() and
|
||||
not (directory / "Scripts/Gameplay.hpp").exists(),
|
||||
require(not any(path.startswith("Scripts/") and
|
||||
path.lower().endswith((".cpp", ".cc", ".cxx", ".hpp", ".hh", ".h"))
|
||||
for path in (entry["path"] for entry in manifest["files"])),
|
||||
"Lua-only export unexpectedly contains C++ gameplay source")
|
||||
require(not (directory / ".luarc.json").exists(),
|
||||
require(not any(path.endswith(".luarc.json") for path in
|
||||
(entry["path"] for entry in manifest["files"])),
|
||||
"Lua-only export includes Editor language-server configuration")
|
||||
|
||||
|
||||
def verify_lua_execution(stderr: str) -> None:
|
||||
require("Lua player ready: A/D move, Space jump, E reset" in stderr,
|
||||
"Lua gameplay on_start did not execute in the relocated Player")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
# Keep captured CI logs portable even when the Windows console uses a legacy code page.
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
@@ -189,8 +222,7 @@ def main() -> int:
|
||||
evidence, projects = output / "evidence", workspace / "Faset Café 世界"
|
||||
evidence.mkdir()
|
||||
projects.mkdir()
|
||||
revision = subprocess.run(["git", "-C", str(engine), "rev-parse", "HEAD"],
|
||||
capture_output=True, text=True, check=True).stdout.strip()
|
||||
source_identity = git_identity(engine)
|
||||
vulkan_summary = ""
|
||||
if shutil.which("vulkaninfo"):
|
||||
try:
|
||||
@@ -208,7 +240,11 @@ def main() -> int:
|
||||
report = {"format": "faset.playable-export-verification", "version": 1,
|
||||
"started_utc": datetime.now(timezone.utc).isoformat(), "platform": sys.platform,
|
||||
"engine": str(engine), "editor": str(editor), "standalone_root": str(standalone),
|
||||
"engine_revision": revision, "editor_sha256": sha256(editor),
|
||||
"engine_revision": source_identity["revision"],
|
||||
"engine_dirty": source_identity["dirty"],
|
||||
"engine_git_status": source_identity["status_lines"],
|
||||
"engine_diff_sha256": source_identity["diff_sha256"],
|
||||
"editor_sha256": sha256(editor),
|
||||
"project_workspace": str(workspace),
|
||||
"vulkaninfo_available": bool(vulkan_summary),
|
||||
"driver_override": os.environ.get("VK_DRIVER_FILES") or os.environ.get("VK_ICD_FILENAMES"),
|
||||
@@ -272,6 +308,8 @@ def main() -> int:
|
||||
capture, profile = relocated / "verification.ppm", relocated / "profile.json"
|
||||
rendered = run([player, "--headless", "--frames", "120", "--capture", capture,
|
||||
"--profile", profile], working, evidence / f"{name}-run.json", 300)
|
||||
if item["language"] == "lua":
|
||||
verify_lua_execution(rendered["stderr"])
|
||||
summary = json.loads(rendered["stdout"].strip().splitlines()[-1])
|
||||
require(summary["frames"] == 120 and summary["dimension"] == dimension and
|
||||
summary["validation_errors"] == 0, "Standalone GPU run reported an error")
|
||||
@@ -282,8 +320,9 @@ def main() -> int:
|
||||
len(measured["samples"]) == 120, "Invalid or incomplete frame profile")
|
||||
require(all(frame["gpu_allocated_bytes"] > 0 for frame in measured["samples"]),
|
||||
"Frame profile lacks Vulkan allocation measurements")
|
||||
item.update({"device": measured["device"], "validation_enabled": measured["validation_enabled"],
|
||||
"driver": vulkan_device_details(vulkan_summary, measured["device"]),
|
||||
driver = vulkan_device_details(vulkan_summary, measured["device"])
|
||||
item.update({"device": measured["device"], "device_class": device_class(measured["device"], driver),
|
||||
"driver": driver, "validation_enabled": measured["validation_enabled"],
|
||||
"validation_errors": 0, "completed_frames": 120,
|
||||
"summary_ms": measured["summary_ms"],
|
||||
"capture": verify_capture(capture, language=item["language"]),
|
||||
|
||||
Reference in New Issue
Block a user