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
10 changes: 10 additions & 0 deletions src/xrt/compositor/multi/comp_multi_compositor.c
Original file line number Diff line number Diff line change
Expand Up @@ -2458,6 +2458,16 @@ multi_compositor_get_window_screen_rect(struct multi_compositor *mc,
bool
multi_compositor_request_display_mode(struct multi_compositor *mc, bool enable_3d)
{
#if defined(COMP_MULTI_HAVE_WEAVE) && defined(XRT_OS_LINUX_DESKTOP)
// Desktop-Linux XR_DXR_weave present-owner (browser#55 on Linux): it has no
// window, so session_render is never initialised and the gate below dropped
// every hardware request on the floor — the panel's lens stayed on over a
// 2D tab while the browser believed the request had landed. Its DP is the
// weave engine's own instance (mc->weave.dp), so the request goes there.
if (mc != NULL && !mc->session_render.initialized) {
return comp_multi_weave_linux_request_display_mode(mc, enable_3d);
}
#endif
if (mc == NULL || !mc->session_render.initialized) {
return false;
}
Expand Down
33 changes: 33 additions & 0 deletions src/xrt/compositor/multi/comp_multi_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,14 @@ struct multi_compositor
uint32_t last_offpanel_band_count;
//! @}

/*!
* Hardware 2D/3D as last CONFIRMED by mc->weave.dp and reported to
* this client's session (comp_multi_weave_linux_request_display_mode).
* Stored inverted so the zero-initialised struct means 3D, the state
* every session starts in. The standing WISH is mc->hardware_display_3d.
*/
bool hw_2d_confirmed;

//! @name Flat regions (spec v8, browser#88, on desktop Linux)
//! The sticky screen-space latch (xrWeaveSetScreenFlatRegionsDXR),
//! absolute screen device px; a SET, count 0 clears. Unioned with
Expand Down Expand Up @@ -1493,6 +1501,31 @@ bool
comp_multi_weave_set_screen_flat_regions(struct xrt_compositor *xc,
uint32_t rect_count,
const struct xrt_rect *screen_rects);

/*!
* HARDWARE 2D/3D request (xrRequestDisplayModeDXR, #533) for a present-owner
* on desktop Linux — routed here by multi_compositor_request_display_mode,
* whose per-session-render branch a present-owner never reaches (it has no
* window, so session_render is never initialised). Applies the request to the
* weave engine's OWN display processor (mc->weave.dp — the only DP in the
* service process, the one holding the vendor's lens), inline on the calling
* (IPC) thread under mc->weave.mutex: a present-owner that asks for 2D has, by
* definition, stopped submitting, so a frame-gated apply would never run (the
* D3D11 service's #815 for the same browser#55 flow). Before the engine exists
* the wish is recorded and applied at engine bring-up.
*
* Emits XRT_SESSION_EVENT_HARDWARE_DISPLAY_STATE_CHANGE (carrying the
* REQUESTED state) to this client's session only once the DP ACCEPTED a change
* (#961 semantics; a DP with no request_display_mode slot is mode-neutral and
* counts as accepted); a request for the state already confirmed sends none.
* Logs one WARN per transition with the DP call's duration and, as information
* only, the DP's read-back (a vendor lens may switch asynchronously, so it can
* lag the request).
*
* @return true if the request was applied (or recorded for bring-up).
*/
bool
comp_multi_weave_linux_request_display_mode(struct multi_compositor *mc, bool enable_3d);
/*! @} */
#endif // XRT_OS_LINUX_DESKTOP

Expand Down
107 changes: 107 additions & 0 deletions src/xrt/compositor/multi/comp_multi_weave_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,11 @@
#include "xrt/xrt_display_processor_vk.h"
#include "xrt/xrt_display_metrics.h"
#include "xrt/xrt_handles.h"
#include "xrt/xrt_session.h"
#include "xrt/xrt_weave_dmabuf.h"

#include "os/os_time.h"

#include "util/u_misc.h"
#include "util/u_logging.h"
#include "util/u_handles.h"
Expand Down Expand Up @@ -981,6 +984,75 @@ weave_reset_acquire_sem(struct vk_bundle *vk, struct multi_compositor *mc)
* in the Linux DP contract ties its creation to a thread, so the factory runs on
* the IPC handler thread.
*/
/*!
* Apply a HARDWARE 2D/3D request to the engine's own DP and, once the DP
* confirmed a CHANGE, tell this client's session (#961: the event follows the
* DP, never the bookkeeping). Call with mc->weave.mutex held and mc->weave.dp
* non-NULL. The vendor call is one lens-hint call (Leia: srLensDisable /
* srLensEnable under the plug-in's own context lock), so it is cheap enough
* for the IPC thread; the lock order weave.mutex -> vendor lock is the same one
* every submit already takes (process_atlas runs under weave.mutex).
*
* A DP without a request_display_mode slot is mode-neutral (sim_display by
* default): the request counts as accepted, as in the D3D11 service's
* dp_request_display_mode_confirmed. A DP that HAS the slot and returns false
* rejected it — nothing is recorded or reported, so the session never believes
* in a panel state the hardware did not reach.
*
* The event carries the REQUESTED state once the DP accepted it (#961), never
* a read-back: a vendor lens may switch asynchronously (Leia SR flips it via
* its own LENS_ON/OFF events), so get_hardware_3d_state right after the
* request can still report the old state. The read-back is logged as
* information only. The DP call is timed, because it runs on the IPC thread
* under weave.mutex (a slow vendor service stalls this client's submits).
*/
static bool
weave_apply_display_mode_locked(struct multi_compositor *mc, bool want_3d, const char *why)
{
struct xrt_display_processor *dp = mc->weave.dp;
const bool has_slot = XRT_DP_HAS_SLOT(dp, request_display_mode) && dp->request_display_mode != NULL;
const int64_t t0_ns = os_monotonic_get_ns();
const bool accepted = has_slot ? xrt_display_processor_request_display_mode(dp, want_3d) : true;
const double dp_ms = (double)(os_monotonic_get_ns() - t0_ns) / 1e6;
const char *slow = dp_ms > 50.0 ? " (slow)" : "";
if (!accepted) {
U_LOG_W(
"weave(#1699): the display processor REJECTED hardware %s (%s) in %.1f ms%s — panel state "
"unchanged, no event sent",
want_3d ? "3D" : "2D", why, dp_ms, slow);
return false;
}

const bool prev_3d = !mc->weave.hw_2d_confirmed;
mc->weave.hw_2d_confirmed = !want_3d;
if (prev_3d == want_3d) {
return true; // already there (a re-assert keeps a drifted vendor honest; nothing to report)
}

// One WARN per transition (a human-rate event: a tab switch, a page's mode
// choice), so a hardware run can be read from the journal alone. The
// read-back is informational only (see above): it may lag the request.
bool panel_3d = false;
const bool have_readback = xrt_display_processor_get_hardware_3d_state(dp, &panel_3d);
U_LOG_W(
"weave(#1699): hardware %s -> %s (%s) on the weave engine's display processor (%s) in %.1f ms%s; "
"DP readback: %s",
prev_3d ? "3D" : "2D", want_3d ? "3D" : "2D", why,
has_slot ? "request_display_mode accepted" : "mode-neutral DP, nothing to switch", dp_ms, slow,
have_readback ? (panel_3d ? "3D (may lag — the lens switches asynchronously)"
: "2D (may lag — the lens switches asynchronously)")
: "none (the DP has no get_hardware_3d_state)");

union xrt_session_event xse = {0};
xse.hardware_display_state_change.type = XRT_SESSION_EVENT_HARDWARE_DISPLAY_STATE_CHANGE;
xse.hardware_display_state_change.hardware_display_3d = want_3d;
const xrt_result_t xret = multi_compositor_push_event(mc, &xse);
if (xret != XRT_SUCCESS) {
U_LOG_W("weave(#1699): could not push the hardware-state event to the session: %d", xret);
}
return true;
}

static bool
weave_ensure_engine(struct vk_bundle *vk, struct multi_compositor *mc)
{
Expand Down Expand Up @@ -1085,6 +1157,14 @@ weave_ensure_engine(struct vk_bundle *vk, struct multi_compositor *mc)
vk_dmabuf_supported(vk) ? "yes" : "NO (device lacks dma-buf / DRM modifier / foreign queue)",
mc->weave.release_sem != VK_NULL_HANDLE ? "GPU (SYNC_FD semaphores)" : "none (CPU poll + synchronous)",
(int)xrt_display_processor_is_self_submitting(mc->weave.dp));

// A hardware 2D request that arrived before this DP existed (the page asked
// for a flat panel before the first submit). 3D is the default, so only a
// 2D wish needs acting on — same shape as the Android session_render
// deferral in multi_compositor_init_session_render.
if (!mc->hardware_display_3d) {
(void)weave_apply_display_mode_locked(mc, false, "deferred request, applied at engine bring-up");
}
return true;
}

Expand Down Expand Up @@ -2723,6 +2803,33 @@ comp_multi_weave_snap_window_rect(struct xrt_compositor *xc,
return snapped;
}

bool
comp_multi_weave_linux_request_display_mode(struct multi_compositor *mc, bool enable_3d)
{
if (mc == NULL || mc->msc == NULL) {
return false;
}
weave_ensure_mutex(mc);
os_mutex_lock(&mc->weave.mutex);
// The standing wish: read again at engine bring-up if the DP is not there yet.
const bool had_pending_2d = mc->weave.dp == NULL && !mc->hardware_display_3d;
mc->hardware_display_3d = enable_3d;
bool ok = true;
if (mc->weave.dp != NULL) {
ok = weave_apply_display_mode_locked(mc, enable_3d, "xrRequestDisplayModeDXR");
} else if (enable_3d && had_pending_2d) {
U_LOG_W(
"weave(#1699): hardware 3D requested before the weave engine exists — the recorded 2D request is "
"withdrawn, nothing to apply at bring-up");
} else if (!enable_3d) {
U_LOG_W(
"weave(#1699): hardware 2D requested before the weave engine exists — recorded, applied when "
"the engine comes up");
}
os_mutex_unlock(&mc->weave.mutex);
return ok;
}

void
comp_multi_weave_fini(struct multi_compositor *mc)
{
Expand Down
51 changes: 51 additions & 0 deletions src/xrt/drivers/sim_display/sim_display_processor.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,21 @@ DEBUG_GET_ONCE_BOOL_OPTION(sim_display_strict_panel, "SIM_DISPLAY_STRICT_PANEL",
*/
DEBUG_GET_ONCE_NUM_OPTION(sim_display_interlace_period, "SIM_DISPLAY_INTERLACE_PERIOD", 1)

/*!
* Fake switchable lens (test double for the hardware 2D/3D channel).
*
* sim_display is mode-neutral by default: it has no lens, so its DP leaves the
* request_display_mode / get_hardware_3d_state slots NULL and the runtime
* treats a hardware request as "nothing to switch" (in-process compositors then
* fall back to the device's OUTPUT_MODE property). That keeps it honest, but it
* also makes a headless run blind to WHERE a hardware request lands — e.g.
* whether the desktop-Linux weave engine's own DP receives a present-owner's
* xrRequestDisplayModeDXR at all. With this option the DP fills both slots: it
* records the requested state, logs one WARN per transition and reports it back,
* like a vendor lens would. Off by default, so default behaviour is unchanged.
*/
DEBUG_GET_ONCE_BOOL_OPTION(sim_display_fake_lens, "SIM_DISPLAY_FAKE_LENS", false)

// SPIR-V shader headers (generated at build time by spirv_shaders())
#include "sim_display/shaders/fullscreen.vert.h"
#include "sim_display/shaders/anaglyph.frag.h"
Expand Down Expand Up @@ -145,6 +160,9 @@ struct sim_display_processor
uint32_t geom_last_target_w, geom_last_target_h;
int32_t geom_last_canvas_x, geom_last_canvas_y;
uint32_t geom_last_canvas_w, geom_last_canvas_h;

//! SIM_DISPLAY_FAKE_LENS — the fake lens state (true = 3D, the default).
bool fake_lens_3d;
};

static inline struct sim_display_processor *
Expand Down Expand Up @@ -686,6 +704,31 @@ sim_dp_get_predicted_eye_positions(struct xrt_display_processor *xdp, struct xrt
return true;
}

//! SIM_DISPLAY_FAKE_LENS: record the request (one WARN per transition).
static bool
sim_dp_request_display_mode(struct xrt_display_processor *xdp, bool enable_3d)
{
struct sim_display_processor *sdp = sim_display_processor(xdp);
if (sdp->fake_lens_3d != enable_3d) {
U_LOG_W("sim_display: fake lens %s -> %s (request_display_mode on DP %p)",
sdp->fake_lens_3d ? "3D" : "2D", enable_3d ? "3D" : "2D", (void *)xdp);
}
sdp->fake_lens_3d = enable_3d;
return true;
}

//! SIM_DISPLAY_FAKE_LENS: report the recorded state.
static bool
sim_dp_get_hardware_3d_state(struct xrt_display_processor *xdp, bool *out_is_3d)
{
struct sim_display_processor *sdp = sim_display_processor(xdp);
if (out_is_3d == NULL) {
return false;
}
*out_is_3d = sdp->fake_lens_3d;
return true;
}

static VkRenderPass
sim_dp_get_render_pass(struct xrt_display_processor *xdp)
{
Expand Down Expand Up @@ -995,6 +1038,14 @@ sim_display_processor_create(enum sim_display_output_mode mode,
sdp->base_vk.base.publish_local_zone_mask = sim_dp_publish_local_zone_mask; // #224 / ADR-027
sdp->base_vk.base.clear_local_zone_mask = sim_dp_clear_local_zone_mask; // #224 / ADR-027

// Fake switchable lens: off by default (the slots stay NULL = mode-neutral).
sdp->fake_lens_3d = true;
if (debug_get_bool_option_sim_display_fake_lens()) {
sdp->base_vk.base.request_display_mode = sim_dp_request_display_mode;
sdp->base_vk.base.get_hardware_3d_state = sim_dp_get_hardware_3d_state;
U_LOG_W("sim_display: SIM_DISPLAY_FAKE_LENS — this DP (%p) reports a switchable lens", (void *)sdp);
}

// #224 / ADR-027 zone test double config (shared parser).
sim_zone_config_from_env(&sdp->zone_cfg, "VK");

Expand Down
Loading
Loading