Summary
On Android the inline-3D rig zone and the woven canvas rect disagree by a constant 168 device px vertically. The runtime therefore solves each eye's view for a zone ~1/2 inch higher on the panel than the pixels actually being woven, and the result on a 3D display is a double image — a disparity error, not a phase error.
168 px on the test device (480 dpi, density 3.0) is exactly 56 dp, the toolbar height. The zone appears to be reported in content-viewport coordinates while the weave rect is in window/surface coordinates that include the browser chrome.
Windows is unaffected and weaves correctly on the same pages.
Evidence
Two pages with different layouts and different scroll positions, same delta:
| page |
zone(device px) |
woven rect |
Δy |
samples/windows (multi-canvas) |
60,1558 960x960 |
60,1726 960x467 |
168 |
samples/hello-cube (single canvas) |
60,1590 960x480 |
60,1758 960x435 |
168 |
Log lines:
[DisplayXR] android rig locate live: 2 views | zone(device px)=60,1590 960x480
| bound window(device px)=0,0 1080x2193 display=0 | virtualDisplayHeight=0.12m
| fov L/R/U/D=-0.00599997/0.135171/0.155729/-0.155729
[DisplayXR] weave zero-copy failed: BeginScopedReadAccess(canvas) (rect=60,1758 960x435)
[DisplayXR] weave window bound: origin 0,0 client 1080x2193 display 0
Note the height also differs (480 vs 435), but that part is explained: 1758 + 435 = 2193 is exactly the bound window height, i.e. the rect is clipped at the viewport bottom while the zone is not. The origin delta is the defect.
The window is bound at origin 0,0 client 1080x2193 on a 1080x2400 panel. 2400 - 2193 = 207, which is not the 168 offset — so this is not simply the bound window being wrong; the two coordinate spaces are separately derived and one of them omits the toolbar.
Why this reads as "texture size wrong" rather than "phase"
Phase errors shift the interlace comb and show as a stripe/ghost that moves with head position. This instead shows a stable doubled image at every head position, because the per-eye frusta are computed for a zone whose screen rect doesn't match the pixels being woven.
Where to look
xrWeaveBindWindow2DXR — window geometry comes from the browser's Java UI per docs/android-port.md; likely the content view rect rather than the surface rect (or vice-versa for the zone).
- The rig zone path that emits
android rig locate live: — whichever of the two is not toolbar-adjusted.
- Whatever the mac backend does here is the reference: the mac arm has no in-window chrome offset problem, and Windows passes an HWND whose client rect is consistently the origin for both.
Repro
- Runtime + vendor plug-in installed; a 3D panel at density 3.0.
- Launch with
--enable-inline-3d --enable-blink-features=DisplayXRInline3D (via /data/local/tmp/chrome-command-line + am set-debug-app --persistent).
- Load
displayxr-web/samples/hello-cube.
adb logcat | grep -oE "zone\(device px\)=[^|]*|rect=[0-9]+,[0-9]+ [0-9]+x[0-9]+" and compare the two origins.
Eyeball: content weaves (all rects, both pages) but shows a persistent double image.
Notes
Summary
On Android the inline-3D rig zone and the woven canvas rect disagree by a constant 168 device px vertically. The runtime therefore solves each eye's view for a zone ~1/2 inch higher on the panel than the pixels actually being woven, and the result on a 3D display is a double image — a disparity error, not a phase error.
168 px on the test device (480 dpi, density 3.0) is exactly 56 dp, the toolbar height. The zone appears to be reported in content-viewport coordinates while the weave rect is in window/surface coordinates that include the browser chrome.
Windows is unaffected and weaves correctly on the same pages.
Evidence
Two pages with different layouts and different scroll positions, same delta:
zone(device px)rectsamples/windows(multi-canvas)60,1558 960x96060,1726 960x467samples/hello-cube(single canvas)60,1590 960x48060,1758 960x435Log lines:
Note the height also differs (480 vs 435), but that part is explained:
1758 + 435 = 2193is exactly the bound window height, i.e. the rect is clipped at the viewport bottom while the zone is not. The origin delta is the defect.The window is bound at
origin 0,0 client 1080x2193on a1080x2400panel.2400 - 2193 = 207, which is not the 168 offset — so this is not simply the bound window being wrong; the two coordinate spaces are separately derived and one of them omits the toolbar.Why this reads as "texture size wrong" rather than "phase"
Phase errors shift the interlace comb and show as a stripe/ghost that moves with head position. This instead shows a stable doubled image at every head position, because the per-eye frusta are computed for a zone whose screen rect doesn't match the pixels being woven.
Where to look
xrWeaveBindWindow2DXR— window geometry comes from the browser's Java UI perdocs/android-port.md; likely the content view rect rather than the surface rect (or vice-versa for the zone).android rig locate live:— whichever of the two is not toolbar-adjusted.Repro
--enable-inline-3d --enable-blink-features=DisplayXRInline3D(via/data/local/tmp/chrome-command-line+am set-debug-app --persistent).displayxr-web/samples/hello-cube.adb logcat | grep -oE "zone\(device px\)=[^|]*|rect=[0-9]+,[0-9]+ [0-9]+x[0-9]+"and compare the two origins.Eyeball: content weaves (all rects, both pages) but shows a persistent double image.
Notes
patches/(lives on the EC2 builder, blocked on patches 0072-0074 (web#12 canvas-readback) need a recapture refresh post-#109 #122 / epic Android port: inline-3D weave on the DisplayXR Android runtime #100), so this is filed against that work rather than a patch number.weave zero-copy failed: BeginScopedReadAccess(canvas)/ProduceSkia(canvas)firing every frame, andinline-3D withheld N of M weave rects: no canvas resource resolvedon multi-canvas pages. Those did not prevent weaving here but are worth their own look.