From 0c6869fa029ed8013f9ddbdb5e9313dce4109792 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 5 Oct 2026 19:13:30 -0700 Subject: [PATCH] feat(weave/android): hand the v4 2D overlay to the DP (2D under the lens) This is the Android twin of the Linux caller in 94fc02248. Before the self-submit split, the weave now offers the browser's window-sized 2D overlay to the DP's Vulkan set_overlay_2d slot, together with the v15 filter strength. It moves the overlay barrier ahead of the split, so a self-submitting DP (Leia CNSDK) can sample the layer during process_atlas. When the DP accepts, the post-weave premultiplied-over blend is skipped. When it declines, or the slot is absent, behaviour is unchanged. The layer is offered only when it is exactly the process_atlas target size. The satellite physical-rect and v6 N-view targets are not. The XR_DXR_weave v14/v15 hints (layer unchanged, filter strength) were already on the wire. Until now they were dropped on Android; they are now forwarded through the new comp_multi_weave_android_set_overlay_hints. Co-Authored-By: Claude Opus 5.5 --- src/xrt/compositor/multi/comp_multi_private.h | 22 +++++++ .../multi/comp_multi_weave_android.c | 64 ++++++++++++++++++- src/xrt/ipc/server/ipc_server_handler.c | 4 ++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/xrt/compositor/multi/comp_multi_private.h b/src/xrt/compositor/multi/comp_multi_private.h index 87f8827531..f51122cdda 100644 --- a/src/xrt/compositor/multi/comp_multi_private.h +++ b/src/xrt/compositor/multi/comp_multi_private.h @@ -804,6 +804,20 @@ struct multi_compositor uint32_t overlay_refusals; //! @} + /*! + * @name 2D under the lens (ADR-027 Amendment, XR_DXR_weave v14/v15) + * Android twin of the desktop-Linux fields: per-submit overlay hints set by + * comp_multi_weave_android_set_overlay_hints right before each submit + * (never sticky), forwarded to the DP with the overlay when its + * set_overlay_2d slot takes it. @c overlay_in_dp is the last verdict so the + * WARN fires on a change only. + * @{ + */ + bool overlay_unchanged; + float overlay_filter_strength; + uint8_t overlay_in_dp; //!< 0 = no overlay seen yet, 1 = runtime blend, 2 = DP composites + //! @} + //! @name Arch-C weave satellite (#1277 P0) — service-presented weave //! `debug.dxr.weave_satellite=1`: the woven output is blitted onto a //! SERVICE-owned full-panel overlay surface (the #558 machinery) and @@ -1500,6 +1514,14 @@ comp_multi_weave_android_satellite_clear(struct multi_compositor *mc); */ bool comp_multi_weave_android_satellite_presented(struct multi_compositor *mc); + +/*! + * XR_DXR_weave v14/v15 overlay hints for the NEXT comp_multi_weave_submit only + * (Android twin of comp_multi_weave_linux_set_overlay_hints). @p filter_strength + * outside [0, 1] (incl. NaN) means "not set by the app": the DP's own default. + */ +void +comp_multi_weave_android_set_overlay_hints(struct xrt_compositor *xc, bool overlay_unchanged, float filter_strength); #endif bool diff --git a/src/xrt/compositor/multi/comp_multi_weave_android.c b/src/xrt/compositor/multi/comp_multi_weave_android.c index c06e20abd2..6836bc1eb8 100644 --- a/src/xrt/compositor/multi/comp_multi_weave_android.c +++ b/src/xrt/compositor/multi/comp_multi_weave_android.c @@ -1439,6 +1439,22 @@ comp_multi_weave_android_satellite_clear(struct multi_compositor *mc) U_LOG_W("weave satellite(#1277): overlay CLEARED on weave-idle (stale-frame guard)"); } +void +comp_multi_weave_android_set_overlay_hints(struct xrt_compositor *xc, bool overlay_unchanged, float filter_strength) +{ + struct multi_compositor *mc = multi_compositor(xc); + if (mc == NULL || mc->msc == NULL) { + return; + } + weave_ensure_mutex(mc); + os_mutex_lock(&mc->weave.mutex); + mc->weave.overlay_unchanged = overlay_unchanged; + // Out of range (incl. NaN) = not set by the app: the DP's own default. + mc->weave.overlay_filter_strength = + (filter_strength >= 0.0f && filter_strength <= 1.0f) ? filter_strength : -1.0f; + os_mutex_unlock(&mc->weave.mutex); +} + bool comp_multi_weave_android_satellite_presented(struct multi_compositor *mc) { @@ -2329,6 +2345,52 @@ comp_multi_weave_submit(struct xrt_compositor *xc, // completion contract for the whole frame. // Kill-switch: debug.xrt.DXR_ANDROID_WEAVE_SPLIT=0 restores the old // single-submission behaviour. + // 2D under the lens (ADR-027 Amendment): offer the v4 overlay to the DP so + // it composites the layer INSIDE the weave and band-limits it for the lens, + // instead of the post-weave blend below (which aliases per eye wherever the + // lens is on). Only when the layer is exactly the process_atlas target size + // (the slot's contract; the satellite physical-rect and v6 N-view targets + // are not window-sized). The layer is put in SHADER_READ_ONLY here, BEFORE + // the self-submit split, so it is ready when a self-submitting DP (CNSDK) + // samples it during process_atlas. A DP that declines leaves the post-weave + // blend to do exactly what it did before. Per submit (#1835): the import + // is cached by AHB pointer, so a submit that chains no overlay must not + // hand the DP the last one. + struct xrt_display_processor_vk *dp_vk = (struct xrt_display_processor_vk *)mc->weave.dp; + bool ov_in_dp = false; + if (mc->weave.overlay_image != VK_NULL_HANDLE && mc->weave.overlay_this_submit && + mc->weave.overlay_w == mc->weave.out_w && + mc->weave.overlay_h == mc->weave.out_h && xrt_display_processor_vk_supports_overlay_2d(dp_vk)) { + VkImageMemoryBarrier ov_to_read = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + .oldLayout = mc->weave.overlay_first_use ? VK_IMAGE_LAYOUT_UNDEFINED + : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .image = mc->weave.overlay_image, + .subresourceRange = range, + }; + mc->weave.overlay_first_use = false; + vk->vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, 0, NULL, 0, NULL, 1, &ov_to_read); + // v15 strength first: the D3D11 / Linux order. + xrt_display_processor_vk_set_overlay_2d_filter_strength(dp_vk, mc->weave.overlay_filter_strength); + ov_in_dp = xrt_display_processor_vk_set_overlay_2d( + dp_vk, mc->weave.overlay_view, (VkFormat_XDP)WEAVE_VK_FORMAT, mc->weave.overlay_w, + mc->weave.overlay_h, XRT_ATLAS_ENCODING_ENCODED, mc->weave.overlay_unchanged); + } + if (mc->weave.overlay_image != VK_NULL_HANDLE && mc->weave.overlay_this_submit) { + const uint8_t verdict = ov_in_dp ? 2u : 1u; + if (verdict != mc->weave.overlay_in_dp) { + mc->weave.overlay_in_dp = verdict; + U_LOG_W("weave(#1036) v4: 2D overlay %ux%u (target %ux%u) -> %s", mc->weave.overlay_w, + mc->weave.overlay_h, mc->weave.out_w, mc->weave.out_h, + ov_in_dp ? "composited by the DP inside the weave (2D under the lens)" + : "runtime post-weave premul-over blend"); + } + } + bool weave_split = weave_split_enabled() && xrt_display_processor_is_self_submitting(mc->weave.dp); if (weave_split) { if (vk->vkEndCommandBuffer(cmd) != VK_SUCCESS) { @@ -2406,7 +2468,7 @@ comp_multi_weave_submit(struct xrt_compositor *xc, // blend, so crisp 2D lands on top of the interlaced 3D at screen depth. // The overlay is NOT woven — it is drawn after process_atlas onto the same // output attachment. - if (mc->weave.overlay_image != VK_NULL_HANDLE && mc->weave.overlay_this_submit) { + if (mc->weave.overlay_image != VK_NULL_HANDLE && mc->weave.overlay_this_submit && !ov_in_dp) { bool blend_ready = mc->weave.overlay_blend_initialized; if (!blend_ready) { blend_ready = vk_local2d_composite_init(&mc->weave.overlay_blend, vk, WEAVE_VK_FORMAT, diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index 3abe61d8f7..bb1d8ab29e 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -6727,6 +6727,10 @@ ipc_handle_weave_submit(volatile struct ipc_client_state *ics, comp_multi_weave_linux_set_mono_in_2d(ics->xc, args->mono_in_2d != 0); // v14/v15: per submit, read only when the DP composites the overlay. comp_multi_weave_linux_set_overlay_hints(ics->xc, args->overlay_unchanged != 0, args->overlay_filter_strength); +#elif defined(XRT_OS_ANDROID) + // v14/v15: same per-submit hints for the Android weave (2D under the lens). + comp_multi_weave_android_set_overlay_hints(ics->xc, args->overlay_unchanged != 0, + args->overlay_filter_strength); #endif bool ok = comp_multi_weave_submit( // ics->xc, handles[0], //