128 lines
5.6 KiB
Python
128 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Monkey-patch updateRenderIndexes to log every call, then force a sort and
|
|
see what the renderer sees. Also try directly setting drawRange ourselves."""
|
|
import json, sys, time, pathlib, socketserver, threading
|
|
from http.server import SimpleHTTPRequestHandler
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
HERE = pathlib.Path(__file__).resolve().parent
|
|
VIEWER_DIR = (HERE.parent / "web").resolve()
|
|
PLY_PATH = pathlib.Path(sys.argv[1]) if len(sys.argv) > 1 else pathlib.Path(
|
|
"/home/work/lito/ComfyUI/output/lito_output.ply"
|
|
)
|
|
PORT = 18436
|
|
|
|
class _H(SimpleHTTPRequestHandler):
|
|
def translate_path(self, p):
|
|
if p.split("?",1)[0] == "/test.ply": return str(PLY_PATH)
|
|
return super().translate_path(p)
|
|
def log_message(self, *a): pass
|
|
def __init__(self, *a, **kw): super().__init__(*a, directory=str(VIEWER_DIR), **kw)
|
|
|
|
PATCH_JS = r"""
|
|
window.__patchLog = [];
|
|
const origURI = splatMesh.updateRenderIndexes.bind(splatMesh);
|
|
splatMesh.updateRenderIndexes = function (globalIndexes, renderSplatCount) {
|
|
const before = { start: splatMesh.geometry.drawRange.start, count: splatMesh.geometry.drawRange.count };
|
|
let err = null;
|
|
try {
|
|
origURI(globalIndexes, renderSplatCount);
|
|
} catch (e) {
|
|
err = e.message;
|
|
}
|
|
const after = { start: splatMesh.geometry.drawRange.start, count: splatMesh.geometry.drawRange.count };
|
|
window.__patchLog.push({
|
|
renderSplatCount,
|
|
globalIndexesLen: globalIndexes && globalIndexes.length,
|
|
before, after,
|
|
instanceCount: splatMesh.geometry.instanceCount,
|
|
err,
|
|
at: performance.now().toFixed(1),
|
|
});
|
|
};
|
|
return "patched";
|
|
"""
|
|
|
|
PROBE2_JS = r"""
|
|
return new Promise(function (resolve) {
|
|
const out = {};
|
|
out.patchLogPre = window.__patchLog.slice();
|
|
out.gatesPre = { sortRunning: viewer.sortRunning, splatRenderReady: viewer.splatRenderReady };
|
|
out.drawRangePre = Object.assign({}, splatMesh.geometry.drawRange);
|
|
|
|
viewer.runSplatSort(true, true).then(async function (sortRunning) {
|
|
const t0 = performance.now();
|
|
while (performance.now() - t0 < 3000) {
|
|
if (!viewer.sortRunning) break;
|
|
await new Promise(function (rr) { setTimeout(rr, 30); });
|
|
}
|
|
out.patchLogPost = window.__patchLog.slice();
|
|
out.drawRangePost = Object.assign({}, splatMesh.geometry.drawRange);
|
|
out.instanceCountPost = splatMesh.geometry.instanceCount;
|
|
out.splatIndexAttrCount = splatMesh.geometry.attributes.splatIndex.count;
|
|
|
|
// Try directly setting drawRange ourselves and rendering.
|
|
splatMesh.geometry.setDrawRange(0, splatMesh.geometry.attributes.splatIndex.count);
|
|
splatMesh.geometry.instanceCount = splatMesh.geometry.attributes.splatIndex.count;
|
|
splatMesh.geometry.attributes.splatIndex.needsUpdate = true;
|
|
viewer.renderer.info.reset();
|
|
try { viewer.renderer.render(splatMesh, viewer.camera); } catch (e) { out.manualErr = e.message; }
|
|
out.afterManualOverride = {
|
|
renderInfo: JSON.parse(JSON.stringify(viewer.renderer.info.render)),
|
|
drawRange: Object.assign({}, splatMesh.geometry.drawRange),
|
|
instanceCount: splatMesh.geometry.instanceCount,
|
|
matProgram: !!(splatMesh.material && splatMesh.material.program),
|
|
};
|
|
// Pixel check
|
|
const c = document.getElementById('canvas');
|
|
const gl = c.getContext('webgl2') || c.getContext('webgl');
|
|
const px = new Uint8Array(c.width * c.height * 4);
|
|
gl.readPixels(0, 0, c.width, c.height, gl.RGBA, gl.UNSIGNED_BYTE, px);
|
|
let nb = 0, max = 0;
|
|
for (let i = 0; i < px.length; i += 4) {
|
|
const m = Math.max(px[i], px[i+1], px[i+2]);
|
|
if (m > 30) nb++; if (m > max) max = m;
|
|
}
|
|
out.pixels = { nonBlack: nb, max };
|
|
resolve(out);
|
|
});
|
|
});
|
|
"""
|
|
|
|
def main():
|
|
socketserver.TCPServer.allow_reuse_address = True
|
|
httpd = socketserver.TCPServer(("127.0.0.1", PORT), _H)
|
|
threading.Thread(target=httpd.serve_forever, daemon=True).start()
|
|
with sync_playwright() as p:
|
|
browser = p.chromium.launch(headless=True,
|
|
args=["--use-gl=swiftshader", "--ignore-gpu-blocklist"])
|
|
ctx = browser.new_context(viewport={"width": 1024, "height": 768})
|
|
page = ctx.new_page()
|
|
page.on("console", lambda m: print(f" {m.text}") if "frames" not in m.text else None)
|
|
page.goto(f"http://127.0.0.1:{PORT}/viewer_gaussian.html", wait_until="load")
|
|
page.wait_for_function("typeof window.__gs === 'object'")
|
|
|
|
page.evaluate("""async () => {
|
|
window._loaded = false; window._error = null;
|
|
addEventListener('message', e => {
|
|
if (e.data?.type === 'MESH_LOADED') window._loaded = true;
|
|
if (e.data?.type === 'MESH_ERROR') window._error = e.data.error;
|
|
});
|
|
const r = await fetch('/test.ply'); const buf = await r.arrayBuffer();
|
|
postMessage({ type:'LOAD_MESH_DATA', data: buf, filename:'t.ply', renderer:'webgl2' }, '*');
|
|
}""")
|
|
page.wait_for_function("window._loaded || window._error", timeout=180000)
|
|
page.wait_for_timeout(1000)
|
|
print("[harness] applying monkey-patch...")
|
|
page.evaluate("(src) => window.__gs.run(src)", PATCH_JS)
|
|
page.wait_for_timeout(500)
|
|
print("[harness] running probe2...")
|
|
result = page.evaluate("(src) => window.__gs.run(src)", PROBE2_JS)
|
|
print(json.dumps(result, indent=2))
|
|
page.screenshot(path="/tmp/viewer_probe2.png")
|
|
browser.close()
|
|
httpd.shutdown()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|