From a3efb03dd9c8bd1a34761c108714ddd160a48741 Mon Sep 17 00:00:00 2001 From: wheaney <42350981+wheaney@users.noreply.github.com> Date: Sun, 21 Apr 2024 22:21:44 -0700 Subject: [PATCH] Move to IPC data version 2, includes the IMU data time in milliseconds, removes fields that the extension settings may own --- .../IMUAdjust.frag | 49 +++++++++--------- .../breezydesktop@org.xronlinux/extension.js | 20 +++++--- gnome/breezydesktop@org.xronlinux/ipc.js | 4 ++ .../monitormanager.js | 11 ++-- gnome/breezydesktop@org.xronlinux/time.js | 6 ++- gnome/breezydesktop@org.xronlinux/xrEffect.js | 51 +++++++++++-------- 6 files changed, 83 insertions(+), 58 deletions(-) diff --git a/gnome/breezydesktop@org.xronlinux/IMUAdjust.frag b/gnome/breezydesktop@org.xronlinux/IMUAdjust.frag index 658f422..0f9925e 100644 --- a/gnome/breezydesktop@org.xronlinux/IMUAdjust.frag +++ b/gnome/breezydesktop@org.xronlinux/IMUAdjust.frag @@ -5,12 +5,12 @@ uniform bool show_banner; uniform sampler2D uDesktopTexture; uniform mat4 imu_quat_data; uniform vec4 look_ahead_cfg; +uniform float look_ahead_ms; uniform float display_zoom; uniform float display_north_offset; uniform float lens_distance_ratio; uniform bool sbs_enabled; uniform bool sbs_content; -uniform bool sbs_mode_stretched; uniform bool custom_banner_enabled; uniform float stage_aspect_ratio; uniform float display_aspect_ratio; @@ -19,7 +19,6 @@ uniform float trim_height_percent; uniform float half_fov_z_rads; uniform float half_fov_y_rads; uniform float screen_distance; -uniform float frametime; float look_ahead_ms_cap = 45.0; @@ -67,29 +66,29 @@ void PS_IMU_Transform(vec4 pos, vec2 texcoord, out vec4 color) { float lens_z_offset = 0.0; float aspect_ratio = stage_aspect_ratio; - if(enabled && sbs_enabled) { - bool right_display = texcoord.x > 0.5; - aspect_ratio /= 2; + // if(enabled && sbs_enabled) { + // bool right_display = texcoord.x > 0.5; + // aspect_ratio /= 2; - lens_y_offset = lens_distance_ratio / 3; - if(right_display) - lens_y_offset = -lens_y_offset; - if(sbs_content) { - // source video is SBS, left-half of the screen goes to the left lens, right-half to the right lens - if(right_display) - texcoord_x_min = 0.5; - else - texcoord_x_max = 0.5; - } - if(!sbs_mode_stretched) { - // if the content isn't stretched, assume it's centered in the middle 50% of the screen - texcoord_x_min = max(0.25, texcoord_x_min); - texcoord_x_max = min(0.75, texcoord_x_max); - } + // lens_y_offset = lens_distance_ratio / 3; + // if(right_display) + // lens_y_offset = -lens_y_offset; + // if(sbs_content) { + // // source video is SBS, left-half of the screen goes to the left lens, right-half to the right lens + // if(right_display) + // texcoord_x_min = 0.5; + // else + // texcoord_x_max = 0.5; + // } + // if(!sbs_mode_stretched) { + // // if the content isn't stretched, assume it's centered in the middle 50% of the screen + // texcoord_x_min = max(0.25, texcoord_x_min); + // texcoord_x_max = min(0.75, texcoord_x_max); + // } - // translate the texcoord respresenting the current lens's half of the screen to a full-screen texcoord - texcoord.x = (texcoord.x - (right_display ? 0.5 : 0.0)) * 2; - } + // // translate the texcoord respresenting the current lens's half of the screen to a full-screen texcoord + // texcoord.x = (texcoord.x - (right_display ? 0.5 : 0.0)) * 2; + // } if(!enabled || show_banner) { // vec2 banner_size = vec2(800.0 / ReShade::ScreenSize.x, 200.0 / ReShade::ScreenSize.y); // Assuming ScreenWidth and ScreenHeight are defined @@ -142,8 +141,8 @@ void PS_IMU_Transform(vec4 pos, vec2 texcoord, out vec4 color) { float look_ahead_scanline_adjust = texcoord.y * look_ahead_cfg.z; // use the 4th value of the look-ahead config to cap the look-ahead value - float look_ahead_ms = min(min(look_ahead_cfg.x + frametime * look_ahead_cfg.y, look_ahead_cfg.w), look_ahead_ms_cap) + look_ahead_scanline_adjust; - float look_ahead_ms_squared = pow(look_ahead_ms, 2); + float look_ahead_ms_capped = min(min(look_ahead_ms, look_ahead_cfg.w), look_ahead_ms_cap) + look_ahead_scanline_adjust; + float look_ahead_ms_squared = pow(look_ahead_ms_capped, 2); // apply most recent velocity and acceleration to most recent position to get a predicted position vec3 res = applyLookAhead(rotated_vector_t0, velocity_t0, accel_t0, look_ahead_ms, look_ahead_ms_squared) - diff --git a/gnome/breezydesktop@org.xronlinux/extension.js b/gnome/breezydesktop@org.xronlinux/extension.js index 9c2f762..e333faa 100644 --- a/gnome/breezydesktop@org.xronlinux/extension.js +++ b/gnome/breezydesktop@org.xronlinux/extension.js @@ -60,10 +60,13 @@ export default class BreezyDesktopExtension extends Extension { } _find_supported_monitor() { - const target_monitor_id = this._monitor_manager.getMonitorPropertiesList()?.find( - monitor => SUPPORTED_MONITOR_PRODUCTS.includes(monitor.product))?.index; - if (target_monitor_id !== undefined) { - return this._monitor_manager.getMonitors()[target_monitor_id]; + const target_monitor = this._monitor_manager.getMonitorPropertiesList()?.find( + monitor => SUPPORTED_MONITOR_PRODUCTS.includes(monitor.product)); + if (target_monitor !== undefined) { + return { + monitor: this._monitor_manager.getMonitors()[target_monitor.index], + refreshRate: target_monitor.refreshRate, + }; } return null; @@ -74,10 +77,13 @@ export default class BreezyDesktopExtension extends Extension { console.log('Monitors changed, disabling XR effect'); this._effect_disable(); } - this._target_monitor = this._find_supported_monitor(); + const target_monitor = this._find_supported_monitor(); // if target_monitor isn't set, do nothing and wait for MonitorManager to call this again - if (this._target_monitor && this._running_poller_id === undefined) { + if (target_monitor && this._running_poller_id === undefined) { + this._target_monitor = target_monitor.monitor; + this._refresh_rate = target_monitor.refreshRate; + if (this._check_driver_running()) { this._effect_enable(); } else { @@ -118,7 +124,7 @@ export default class BreezyDesktopExtension extends Extension { this._xr_effect = new XREffect({ target_monitor: this._target_monitor, - target_framerate: 60 + target_framerate: this._refresh_rate ?? 60 }); this._overlay.add_effect_with_name('xr-desktop', this._xr_effect); diff --git a/gnome/breezydesktop@org.xronlinux/ipc.js b/gnome/breezydesktop@org.xronlinux/ipc.js index f1fe3c0..77d8fa1 100644 --- a/gnome/breezydesktop@org.xronlinux/ipc.js +++ b/gnome/breezydesktop@org.xronlinux/ipc.js @@ -20,6 +20,10 @@ export function dataViewUint(dataView, dataViewInfo) { return dataView.getUint32(dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX], true); } +export function dataViewBigUint(dataView, dataViewInfo) { + return Number(dataView.getBigUint64(dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX], true)); +} + export function dataViewUintArray(dataView, dataViewInfo) { const uintArray = [] let offset = dataViewInfo[DATA_VIEW_INFO_OFFSET_INDEX]; diff --git a/gnome/breezydesktop@org.xronlinux/monitormanager.js b/gnome/breezydesktop@org.xronlinux/monitormanager.js index 2e979e4..09e4e2b 100644 --- a/gnome/breezydesktop@org.xronlinux/monitormanager.js +++ b/gnome/breezydesktop@org.xronlinux/monitormanager.js @@ -71,7 +71,11 @@ export function getMonitorConfig(displayConfigProxy, callback) { const vendor = props['vendor'].get_string()[0]; const product = props['product'].get_string()[0]; const serial = props['serial'].get_string()[0]; - monitors.push([displayName, connectorName, vendor, product, serial]); + + // grab refresh rate from the modes array + const refreshRate = result[3][i][4]; + + monitors.push([displayName, connectorName, vendor, product, serial, refreshRate]); } callback(monitors, null); } @@ -139,7 +143,7 @@ export default class MonitorManager { } const monitorProperties = []; for (let i = 0; i < result.length; i++) { - const [monitorName, connectorName, vendor, product, serial] = result[i]; + const [monitorName, connectorName, vendor, product, serial, refreshRate] = result[i]; const monitorIndex = this._backendManager.get_monitor_for_connector(connectorName); console.log(`\n\nFound monitor ${monitorName}, vendor ${vendor}, product ${product}, serial ${serial}, connector ${connectorName}, index ${monitorIndex}\n\n`); if (monitorIndex >= 0) { @@ -149,7 +153,8 @@ export default class MonitorManager { vendor: vendor, product: product, serial: serial, - connector: connectorName + connector: connectorName, + refreshRate: refreshRate }; } } diff --git a/gnome/breezydesktop@org.xronlinux/time.js b/gnome/breezydesktop@org.xronlinux/time.js index b4cd219..6c3259c 100644 --- a/gnome/breezydesktop@org.xronlinux/time.js +++ b/gnome/breezydesktop@org.xronlinux/time.js @@ -1,3 +1,7 @@ export function getEpochSec() { - return Math.floor(Date.now() / 1000); + return toSec(Date.now()); +} + +export function toSec(milliseconds) { + return Math.floor(milliseconds / 1000); } \ No newline at end of file diff --git a/gnome/breezydesktop@org.xronlinux/xrEffect.js b/gnome/breezydesktop@org.xronlinux/xrEffect.js index 325e579..b23ae5f 100644 --- a/gnome/breezydesktop@org.xronlinux/xrEffect.js +++ b/gnome/breezydesktop@org.xronlinux/xrEffect.js @@ -7,7 +7,7 @@ import Globals from './globals.js'; import { dataViewEnd, dataViewUint8, - dataViewUint, + dataViewBigUint, dataViewUintArray, dataViewFloat, dataViewFloatArray, @@ -20,28 +20,24 @@ import { } from "./ipc.js"; import { degreeToRadian } from "./math.js"; import { getShaderSource } from "./shader.js"; -import { getEpochSec } from "./time.js"; +import { toSec } from "./time.js"; export const IPC_FILE_PATH = "/dev/shm/breezy_desktop_imu"; // the driver should be using the same data layout version -const DATA_LAYOUT_VERSION = 1; +const DATA_LAYOUT_VERSION = 2; // DataView info: [offset, size, count] const VERSION = [0, UINT8_SIZE, 1]; const ENABLED = [dataViewEnd(VERSION), BOOL_SIZE, 1]; -const EPOCH_SEC = [dataViewEnd(ENABLED), UINT_SIZE, 1]; -const LOOK_AHEAD_CFG = [dataViewEnd(EPOCH_SEC), FLOAT_SIZE, 4]; +const LOOK_AHEAD_CFG = [dataViewEnd(ENABLED), FLOAT_SIZE, 4]; const DISPLAY_RES = [dataViewEnd(LOOK_AHEAD_CFG), UINT_SIZE, 2]; const DISPLAY_FOV = [dataViewEnd(DISPLAY_RES), FLOAT_SIZE, 1]; -const DISPLAY_ZOOM = [dataViewEnd(DISPLAY_FOV), FLOAT_SIZE, 1]; -const DISPLAY_NORTH_OFFSET = [dataViewEnd(DISPLAY_ZOOM), FLOAT_SIZE, 1]; -const LENS_DISTANCE_RATIO = [dataViewEnd(DISPLAY_NORTH_OFFSET), FLOAT_SIZE, 1]; +const LENS_DISTANCE_RATIO = [dataViewEnd(DISPLAY_FOV), FLOAT_SIZE, 1]; const SBS_ENABLED = [dataViewEnd(LENS_DISTANCE_RATIO), BOOL_SIZE, 1]; -const SBS_CONTENT = [dataViewEnd(SBS_ENABLED), BOOL_SIZE, 1]; -const SBS_MODE_STRETCHED = [dataViewEnd(SBS_CONTENT), BOOL_SIZE, 1]; -const CUSTOM_BANNER_ENABLED = [dataViewEnd(SBS_MODE_STRETCHED), BOOL_SIZE, 1]; -const IMU_QUAT_DATA = [dataViewEnd(CUSTOM_BANNER_ENABLED), FLOAT_SIZE, 16]; +const CUSTOM_BANNER_ENABLED = [dataViewEnd(SBS_ENABLED), BOOL_SIZE, 1]; +const EPOCH_MS = [dataViewEnd(CUSTOM_BANNER_ENABLED), UINT_SIZE, 2]; +const IMU_QUAT_DATA = [dataViewEnd(EPOCH_MS), FLOAT_SIZE, 16]; const DATA_VIEW_LENGTH = dataViewEnd(IMU_QUAT_DATA); // cached after first retrieval @@ -50,6 +46,7 @@ const shaderUniformLocations = { 'show_banner': null, 'imu_quat_data': null, 'look_ahead_cfg': null, + 'look_ahead_ms': null, 'stage_aspect_ratio': null, 'display_aspect_ratio': null, 'trim_width_percent': null, @@ -59,12 +56,10 @@ const shaderUniformLocations = { 'lens_distance_ratio': null, 'sbs_enabled': null, 'sbs_content': null, - 'sbs_mode_stretched': null, 'custom_banner_enabled': null, 'half_fov_z_rads': null, 'half_fov_y_rads': null, - 'screen_distance': null, - 'frametime': null + 'screen_distance': null }; function transferUniformBoolean(effect, location, dataView, dataViewInfo) { @@ -103,14 +98,25 @@ function setUniformMatrix(effect, locationName, components, dataView, dataViewIn effect.set_uniform_matrix(shaderUniformLocations[locationName], true, components, floatArray); } +function lookAheadMS(dataView) { + const lookAheadCfg = dataViewFloatArray(dataView, LOOK_AHEAD_CFG); + const imuDateMS = dataViewBigUint(dataView, EPOCH_MS); + + // how stale the imu data is + const dataAge = Date.now() - imuDateMS; + + return lookAheadCfg[0] + dataAge; +} + // most uniforms don't change frequently, this function should be called periodically function setIntermittentUniformVariables() { const dataView = this._dataView; if (dataView.byteLength === DATA_VIEW_LENGTH) { const version = dataViewUint8(dataView, VERSION); - const date = dataViewUint(dataView, EPOCH_SEC); - const validKeepalive = Math.abs(getEpochSec() - date) < 5; + const imuDateMS = dataViewBigUint(dataView, EPOCH_MS); + const currentDateMS = Date.now(); + const validKeepalive = Math.abs(toSec(currentDateMS) - toSec(imuDateMS)) < 5; const imuData = dataViewFloatArray(dataView, IMU_QUAT_DATA); const imuResetState = imuData[0] === 0.0 && imuData[1] === 0.0 && imuData[2] === 0.0 && imuData[3] === 1.0; const enabled = dataViewUint8(dataView, ENABLED) !== 0 && version === DATA_LAYOUT_VERSION && validKeepalive && !imuResetState; @@ -135,12 +141,8 @@ function setIntermittentUniformVariables() { // all these values are transferred directly, unmodified from the driver transferUniformFloat(this, 'look_ahead_cfg', dataView, LOOK_AHEAD_CFG); - transferUniformFloat(this, 'display_zoom', dataView, DISPLAY_ZOOM); - transferUniformFloat(this, 'display_north_offset', dataView, DISPLAY_NORTH_OFFSET); transferUniformFloat(this, 'lens_distance_ratio', dataView, LENS_DISTANCE_RATIO); transferUniformBoolean(this, 'sbs_enabled', dataView, SBS_ENABLED); - transferUniformBoolean(this, 'sbs_content', dataView, SBS_CONTENT); - transferUniformBoolean(this, 'sbs_mode_stretched', dataView, SBS_MODE_STRETCHED); transferUniformBoolean(this, 'custom_banner_enabled', dataView, CUSTOM_BANNER_ENABLED); // computed values with no dataViewInfo, so we set these manually @@ -152,7 +154,11 @@ function setIntermittentUniformVariables() { setSingleFloat(this, 'half_fov_z_rads', halfFovZRads); setSingleFloat(this, 'half_fov_y_rads', halfFovYRads); setSingleFloat(this, 'screen_distance', screenDistance); - setSingleFloat(this, 'frametime', this._frametime); + + // TOOD - drive from settings + setSingleFloat(this, 'display_zoom', 1.0); + setSingleFloat(this, 'display_north_offset', 1.0); + setSingleFloat(this, 'sbs_content', 0.0); } setSingleFloat(this, 'enabled', enabled ? 1.0 : 0.0); } else if (dataView.byteLength !== 0) { @@ -217,6 +223,7 @@ export const XREffect = GObject.registerClass({ } if (this._dataView.byteLength === DATA_VIEW_LENGTH) { + setSingleFloat(this, 'look_ahead_ms', lookAheadMS(this._dataView)); setUniformMatrix(this, 'imu_quat_data', 4, this._dataView, IMU_QUAT_DATA); } else if (this._dataView.byteLength !== 0) { console.error(`Invalid dataView.byteLength: ${this._dataView.byteLength} !== ${DATA_VIEW_LENGTH}`)