Glasses: SteamVR starts and stops with them, closer view with a field of view setting, Recenter on the pad

This commit is contained in:
maxjivi05 committed 2026-10-13 14:11:41 -04:00
1 parent f0b329768e
commit 468262ab9d
17 files changed
+142 -16

No files matched your search

@@ -319,6 +319,9 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
private var glassesScreen: GlassesScreen? = null
private var glassesOutputActive by mutableStateOf(false)
private var glasses3dForVr = false
private var glassesPresent = false
private var steamVrAutoTried = false
private var headTracking by mutableStateOf(false)
private var glassesSlot by mutableStateOf(0)
private var glassesKey: List<Any?> = emptyList()
private val glassesScope = kotlinx.coroutines.MainScope()
@@ -582,6 +585,8 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
cursorImage, cursorHotX, cursorHotY, cursorImageScale)
if (hud.text.isNotEmpty()) HudText(hud.text)
if (glassesOutputActive && !loading.visible) com.droiddeck.launcher.ui.GlassesPlayingHint(glasses.model)
if (glassesOutputActive && headTracking && !drawerOpen && !pcKeyboardOpen && !loading.visible) com.droiddeck.launcher.ui.GlassesRecenterButton(
controllerSettings?.tint ?: android.graphics.Color.rgb(90, 160, 255), controllerSettings?.opacity ?: 100) { headTracker?.recenter() }
if (glasses.present && !drawerOpen && !pcKeyboardOpen && !loading.visible) com.droiddeck.launcher.ui.GlassesCornerButton(glassesSlot,
controllerSettings?.tint ?: android.graphics.Color.rgb(90, 160, 255), controllerSettings?.opacity ?: 100) {
drawerPage = com.droiddeck.launcher.ui.SessionDrawerPage.GLASSES
@@ -2643,14 +2648,14 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
Glasses.set3d(true)
}
if (action == "install") steamVrStatus = SteamVr.Status.INSTALLING
Thread({
steamVrWorker.execute {
val ok = SteamVr.run(this, action)
val now = SteamVr.status(this)
uiHandler.post {
onSteamVrStatus(now)
if (!ok) Toast.makeText(this, getString(R.string.cardboard_steamvr_failed), Toast.LENGTH_LONG).show()
}
}, "steamvr-$action").start()
}
return
}
if (action == "start") {
@@ -2659,7 +2664,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
}
if (action == "stop") restoreSteamVrPicture()
if (action == "install") steamVrStatus = SteamVr.Status.INSTALLING
Thread({
steamVrWorker.execute {
val ok = SteamVr.run(this, action)
val now = SteamVr.status(this)
uiHandler.post {
@@ -2668,7 +2673,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
onSteamVrStatus(now)
if (!ok) Toast.makeText(this, getString(R.string.cardboard_steamvr_failed), Toast.LENGTH_LONG).show()
}
}, "steamvr-$action").start()
}
}
/** SteamVR draws a side-by-side pair: the picture switches to that, remembering what it was. */
@@ -2688,6 +2693,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
if (glassesOutputActive) {
onGlassesSteamVr(now)
if ((was == SteamVr.Status.RUNNING) != (now == SteamVr.Status.RUNNING)) applyCardboard(cardboard)
autoStartSteamVr(now)
return
}
// Started some other way than the drawer (a script, a VR game): the picture follows it all the same.
@@ -2727,7 +2733,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
private fun pushCardboard(c: Cardboard) {
val fov = when {
c.viewer != Cardboard.Viewer.VITURE.id -> 0f
c.source == Cardboard.SOURCE_SBS -> GLASSES_VR_FOV_DEG
c.source == Cardboard.SOURCE_SBS -> glassesSettings.vrFovDeg.toFloat()
else -> glasses.verticalFovDeg
}
panelSizeMm().let { (w, h) -> c.push(w, h, fov, refreshHz()) }
@@ -2772,6 +2778,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
}.also { headTracker = it }
t.start()
}
headTracking = headTracker != null
}
private fun outputHolder(): SurfaceHolder = glassesScreen?.holder ?: surfaceView.holder
@@ -2790,11 +2797,29 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
private fun onGlassesChanged() {
val g = glasses
val s = glassesSettings
val key = listOf(g.usable, g.displayId, g.sbs, g.canControl, g.width, g.height, g.hz, s)
val key = listOf(g.present, g.usable, g.displayId, g.sbs, g.canControl, g.width, g.height, g.hz, s)
if (key == glassesKey) return
glassesKey = key
updateGlassesScreen()
applyCardboard(cardboard)
if (glassesPresent && !g.present) onGlassesUnplugged()
glassesPresent = g.present
}
private fun onGlassesUnplugged() {
val hadVr = steamVrAutoTried
steamVrAutoTried = false
glasses3dForVr = false
if (hadVr && !cardboard.enabled) steamVrAction("stop")
}
private fun autoStartSteamVr(now: SteamVr.Status) {
if (now == SteamVr.Status.RUNNING) steamVrAutoTried = true
if (now != SteamVr.Status.READY || steamVrAutoTried || !glassesSettings.autoSteamVr || !glasses.canControl ||
loading.visible || SessionState.mode != SessionService.MODE_STEAM) return
steamVrAutoTried = true
Log.i(TAG, "starting SteamVR for ${glasses.model}")
steamVrAction("start")
}
private fun updateGlassesScreen() {
@@ -3001,7 +3026,8 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
private const val DRAWER_SLOW_REPEAT_FLOOR_MS = 240L
private const val DRAWER_FAST_REPEAT_INTERVAL_MS = 90L
private const val DRAWER_REPEAT_ACCELERATION_MS = 1_400L
private const val GLASSES_VR_FOV_DEG = 70f
private val steamVrWorker = java.util.concurrent.ThreadPoolExecutor(0, 1, 30, java.util.concurrent.TimeUnit.SECONDS,
java.util.concurrent.LinkedBlockingQueue()) { Thread(it, "steamvr") }
/** Compositor scale modes (Container.FULLSCREEN_* values): 1 = fit with bars, centred. */
private const val SCALE_FIT = 1
private const val ALIGN_CENTER = 0
@@ -117,7 +117,7 @@ class AgentBridgeProvider : ContentProvider() {
val value = request.optString("value")
fun on() = value == "1" || value.equals("true", true) || value.equals("on", true)
val number = value.toIntOrNull()
val numeric = setOf("refreshHz", "sbsHz", "brightness", "volume", "picture3d", "screenWidthDm", "screenDistanceDm", "sbsSupport")
val numeric = setOf("refreshHz", "sbsHz", "brightness", "volume", "picture3d", "screenWidthDm", "screenDistanceDm", "vrFovDeg", "sbsSupport")
if (key in numeric && number == null) return error("INVALID_VALUE", "'$key' takes a number")
when (key) {
"refreshHz" -> g.setRefreshHz(number!!)
@@ -132,6 +132,8 @@ class AgentBridgeProvider : ContentProvider() {
"picture3d" -> g.setPicture3d(number!!)
"screenWidthDm" -> g.setScreenWidthDm(number!!)
"screenDistanceDm" -> g.setScreenDistanceDm(number!!)
"vrFovDeg" -> g.setVrFovDeg(number!!)
"autoSteamVr" -> g.setAutoSteamVr(on())
"sbsSupport" -> g.setSbsSupport(number!!)
else -> return error("INVALID_KEY", "Unknown glasses setting '$key'")
}
@@ -73,8 +73,13 @@ data class GlassesSettings(
val picture3d: Int = PICTURE_AUTO,
val screenWidthDm: Int = 20,
val screenDistanceDm: Int = 30,
val vrFovDeg: Int = VR_FOV_DEFAULT,
val autoSteamVr: Boolean = true,
) {
companion object {
const val VR_FOV_MIN = 24
const val VR_FOV_MAX = 90
const val VR_FOV_DEFAULT = 36
const val PICTURE_AUTO = 0
const val PICTURE_SCREEN = 1
const val PICTURE_SBS = 2
@@ -198,6 +203,8 @@ object Glasses {
fun setPicture3d(picture: Int) = post { update { it.copy(picture3d = picture.coerceIn(0, 2)) } }
fun setScreenWidthDm(dm: Int) = post { update { it.copy(screenWidthDm = dm.coerceIn(5, 200)) } }
fun setScreenDistanceDm(dm: Int) = post { update { it.copy(screenDistanceDm = dm.coerceIn(5, 200)) } }
fun setVrFovDeg(deg: Int) = post { update { it.copy(vrFovDeg = deg.coerceIn(GlassesSettings.VR_FOV_MIN, GlassesSettings.VR_FOV_MAX)) } }
fun setAutoSteamVr(on: Boolean) = post { update { it.copy(autoSteamVr = on) } }
fun glassesDisplay(): Display? = _state.value.displayId.takeIf { it != Display.INVALID_DISPLAY }?.let { displays.getDisplay(it) }
@@ -252,7 +259,8 @@ object Glasses {
.put("fovDeg", s.diagonalFovDeg.toDouble()).put("noSignal", s.noSignal).put("sbsSupport", s.sbsSupport)
.put("settings", JSONObject().put("refreshHz", g.refreshHz).put("sbsHz", g.sbsHz).put("sunblock", g.sunblock ?: JSONObject.NULL)
.put("gameOnGlasses", g.gameOnGlasses).put("headTracking", g.headTracking).put("auto3d", g.auto3d)
.put("picture3d", g.picture3d).put("screenWidthDm", g.screenWidthDm).put("screenDistanceDm", g.screenDistanceDm))
.put("picture3d", g.picture3d).put("screenWidthDm", g.screenWidthDm).put("screenDistanceDm", g.screenDistanceDm)
.put("vrFovDeg", g.vrFovDeg).put("autoSteamVr", g.autoSteamVr))
}
fun recentFrames(): JSONArray = synchronized(frames) { JSONArray(frames.toList()) }
@@ -544,6 +552,8 @@ object Glasses {
picture3d = p.getInt("picture3d", GlassesSettings.PICTURE_AUTO),
screenWidthDm = p.getInt("screenWidthDm", 20),
screenDistanceDm = p.getInt("screenDistanceDm", 30),
vrFovDeg = p.getInt("vrFovDeg", GlassesSettings.VR_FOV_DEFAULT).coerceIn(GlassesSettings.VR_FOV_MIN, GlassesSettings.VR_FOV_MAX),
autoSteamVr = p.getBoolean("autoSteamVr", true),
)
}
@@ -558,6 +568,8 @@ object Glasses {
putInt("picture3d", s.picture3d)
putInt("screenWidthDm", s.screenWidthDm)
putInt("screenDistanceDm", s.screenDistanceDm)
putInt("vrFovDeg", s.vrFovDeg)
putBoolean("autoSteamVr", s.autoSteamVr)
}.apply()
}
}
@@ -13,9 +13,11 @@ import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -128,6 +130,11 @@ internal fun GlassesGroups(
format = { String.format(Locale.US, "%.1f m", it / 10f) }, modifier = track("glasses-distance")) { Glasses.setScreenDistanceDm(it) }
}
steamVr()
ToggleRow(host, "glasses-auto-steamvr", stringResource(R.string.glasses_auto_steamvr), stringResource(R.string.glasses_auto_steamvr_hint),
s.autoSteamVr, chipModifier = track("glasses-auto-steamvr")) { Glasses.setAutoSteamVr(it) }
SliderRow(stringResource(R.string.glasses_vr_fov), stringResource(R.string.glasses_vr_fov_hint), s.vrFovDeg,
GlassesSettings.VR_FOV_MIN..GlassesSettings.VR_FOV_MAX, step = 1,
format = { "$it°" }, modifier = track("glasses-vr-fov")) { Glasses.setVrFovDeg(it) }
}
if ((tab == null || tab == GlassesTab.HARDWARE) && g.canControl) SettingsGroup(stringResource(R.string.glasses_hardware)) {
SliderRow(stringResource(R.string.glasses_brightness), null, g.brightness.coerceAtLeast(0), 0..g.brightnessMax, step = 1,
@@ -145,6 +152,13 @@ internal fun GlassesGroups(
}
}
private fun padButtonColors(tint: Int, opacity: Int, pressed: Boolean): Pair<Color, Color> {
val base = Color(tint)
val alpha = opacity.coerceIn(0, 100) / 100f
fun light(a: Int, f: Float) = Color(base.red + (1 - base.red) * f, base.green + (1 - base.green) * f, base.blue + (1 - base.blue) * f, a * alpha / 255f)
return Color(base.red * 0.12f, base.green * 0.12f, base.blue * 0.12f, 190 / 255f) to (if (pressed) light(230, 0.7f) else light(150, 0.25f))
}
@Composable
internal fun GlassesCornerButton(slot: Int, tint: Int, opacity: Int, onClick: () -> Unit) {
val density = androidx.compose.ui.platform.LocalDensity.current
@@ -155,11 +169,7 @@ internal fun GlassesCornerButton(slot: Int, tint: Int, opacity: Int, onClick: ()
val bottom = if (slot < 0) 44.dp else 34.dp
val source = remember { MutableInteractionSource() }
val pressed by source.collectIsPressedAsState()
val base = Color(tint)
val alpha = opacity.coerceIn(0, 100) / 100f
val fill = Color(base.red * 0.12f, base.green * 0.12f, base.blue * 0.12f, 190 / 255f)
fun light(a: Int, f: Float) = Color(base.red + (1 - base.red) * f, base.green + (1 - base.green) * f, base.blue + (1 - base.blue) * f, a * alpha / 255f)
val line = if (pressed) light(230, 0.7f) else light(150, 0.25f)
val (fill, line) = padButtonColors(tint, opacity, pressed)
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
@@ -176,6 +186,32 @@ internal fun GlassesCornerButton(slot: Int, tint: Int, opacity: Int, onClick: ()
}
}
@Composable
internal fun GlassesRecenterButton(tint: Int, opacity: Int, onClick: () -> Unit) {
val source = remember { MutableInteractionSource() }
val pressed by source.collectIsPressedAsState()
val (fill, line) = padButtonColors(tint, opacity, pressed)
val shape = RoundedCornerShape(50)
Box(
Modifier.fillMaxSize().windowInsetsPadding(WindowInsets.displayCutout).padding(top = 12.dp),
contentAlignment = Alignment.TopCenter,
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.height(36.dp)
.clip(shape)
.background(fill)
.border(1.5.dp, line, shape)
.clickable(interactionSource = source, indication = null, role = Role.Button, onClick = onClick)
.padding(horizontal = 18.dp)
.testTag("glasses-recenter"),
) {
Text(stringResource(R.string.glasses_recenter_button), color = line, fontSize = 14.sp)
}
}
}
@Composable
internal fun GlassesPlayingHint(model: String) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+5
View File
@@ -2183,6 +2183,11 @@
<string name="glasses_head_tracking">Seguimiento de cabeza</string>
<string name="glasses_head_tracking_hint">Los sensores de las gafas giran la pantalla virtual y SteamVR con tu cabeza.</string>
<string name="glasses_recenter">Recentrar la vista</string>
<string name="glasses_recenter_button">Recentrar</string>
<string name="glasses_auto_steamvr">Iniciar SteamVR con las gafas</string>
<string name="glasses_auto_steamvr_hint">En Steam, SteamVR se inicia al conectar las gafas y se detiene al desconectarlas.</string>
<string name="glasses_vr_fov">Campo de visión de SteamVR</string>
<string name="glasses_vr_fov_hint">Más bajo acerca SteamVR y llena las gafas; más alto muestra más a tu alrededor.</string>
<string name="glasses_playing">Jugando en %1$s</string>
<string name="stores_fact_developer">Desarrollador</string>
<string name="stores_fact_publisher">Distribuidor</string>
+5
View File
@@ -1013,6 +1013,11 @@
<string name="glasses_head_tracking">Suivi de la tête</string>
<string name="glasses_head_tracking_hint">Les capteurs des lunettes font tourner l\'écran virtuel et SteamVR avec votre tête.</string>
<string name="glasses_recenter">Recentrer la vue</string>
<string name="glasses_recenter_button">Recentrer</string>
<string name="glasses_auto_steamvr">Lancer SteamVR avec les lunettes</string>
<string name="glasses_auto_steamvr_hint">Dans Steam, SteamVR démarre quand les lunettes sont branchées et s\'arrête quand elles sont débranchées.</string>
<string name="glasses_vr_fov">Champ de vision SteamVR</string>
<string name="glasses_vr_fov_hint">Plus bas rapproche SteamVR et remplit les lunettes ; plus haut montre davantage autour de vous.</string>
<string name="glasses_playing">En jeu sur %1$s</string>
<string name="stores_fact_developer">Développeur</string>
<string name="stores_fact_publisher">Éditeur</string>
+5
View File
@@ -2139,6 +2139,11 @@
<string name="glasses_head_tracking">ヘッドトラッキング</string>
<string name="glasses_head_tracking_hint">グラスのセンサーで、頭の動きに合わせて仮想スクリーンと SteamVR を動かします。</string>
<string name="glasses_recenter">視点をリセット</string>
<string name="glasses_recenter_button">中央に戻す</string>
<string name="glasses_auto_steamvr">グラス接続時に SteamVR を起動</string>
<string name="glasses_auto_steamvr_hint">Steam では、グラスを接続すると SteamVR を起動し、外すと停止します。</string>
<string name="glasses_vr_fov">SteamVR の視野角</string>
<string name="glasses_vr_fov_hint">小さくすると SteamVR が近くなりグラスいっぱいに広がり、大きくすると周囲が広く見えます。</string>
<string name="glasses_playing">%1$s でプレイ中</string>
<string name="stores_fact_developer">開発元</string>
<string name="stores_fact_publisher">パブリッシャー</string>
+5
View File
@@ -2139,6 +2139,11 @@
<string name="glasses_head_tracking">헤드 트래킹</string>
<string name="glasses_head_tracking_hint">안경의 센서가 머리 움직임에 맞춰 가상 화면과 SteamVR을 돌립니다.</string>
<string name="glasses_recenter">시점 재설정</string>
<string name="glasses_recenter_button">중앙 맞추기</string>
<string name="glasses_auto_steamvr">안경 연결 시 SteamVR 시작</string>
<string name="glasses_auto_steamvr_hint">Steam에서 안경을 연결하면 SteamVR을 시작하고, 분리하면 중지합니다.</string>
<string name="glasses_vr_fov">SteamVR 시야각</string>
<string name="glasses_vr_fov_hint">낮추면 SteamVR이 가까워져 안경을 가득 채우고, 높이면 주변이 더 넓게 보입니다.</string>
<string name="glasses_playing">%1$s에서 플레이 중</string>
<string name="stores_fact_developer">개발사</string>
<string name="stores_fact_publisher">배급사</string>
+5
View File
@@ -1124,6 +1124,11 @@
<string name="glasses_head_tracking">Отслеживание головы</string>
<string name="glasses_head_tracking_hint">Датчики очков поворачивают виртуальный экран и SteamVR вслед за головой.</string>
<string name="glasses_recenter">Сбросить вид</string>
<string name="glasses_recenter_button">Центрировать</string>
<string name="glasses_auto_steamvr">Запускать SteamVR с очками</string>
<string name="glasses_auto_steamvr_hint">В Steam SteamVR запускается при подключении очков и останавливается при отключении.</string>
<string name="glasses_vr_fov">Поле зрения SteamVR</string>
<string name="glasses_vr_fov_hint">Меньше — SteamVR ближе и заполняет очки; больше — шире обзор вокруг.</string>
<string name="glasses_playing">Игра на %1$s</string>
<string name="stores_fact_developer">Разработчик</string>
<string name="stores_fact_publisher">Издатель</string>
@@ -2139,6 +2139,11 @@
<string name="glasses_head_tracking">头部追踪</string>
<string name="glasses_head_tracking_hint">眼镜自带的传感器会随头部转动虚拟屏幕和 SteamVR。</string>
<string name="glasses_recenter">重新居中视角</string>
<string name="glasses_recenter_button">重新居中</string>
<string name="glasses_auto_steamvr">连接眼镜时启动 SteamVR</string>
<string name="glasses_auto_steamvr_hint">在 Steam 中,插入眼镜时启动 SteamVR,拔出时停止。</string>
<string name="glasses_vr_fov">SteamVR 视场角</string>
<string name="glasses_vr_fov_hint">调低让 SteamVR 更近并填满眼镜;调高可看到更多周围内容。</string>
<string name="glasses_playing">正在 %1$s 上游玩</string>
<string name="stores_fact_developer">开发商</string>
<string name="stores_fact_publisher">发行商</string>
@@ -2139,6 +2139,11 @@
<string name="glasses_head_tracking">頭部追蹤</string>
<string name="glasses_head_tracking_hint">眼鏡自帶的感應器會隨頭部轉動虛擬螢幕和 SteamVR。</string>
<string name="glasses_recenter">重新置中視角</string>
<string name="glasses_recenter_button">重新置中</string>
<string name="glasses_auto_steamvr">連接眼鏡時啟動 SteamVR</string>
<string name="glasses_auto_steamvr_hint">在 Steam 中,插入眼鏡時啟動 SteamVR,拔出時停止。</string>
<string name="glasses_vr_fov">SteamVR 視場角</string>
<string name="glasses_vr_fov_hint">調低令 SteamVR 更近並填滿眼鏡;調高可看到更多周圍內容。</string>
<string name="glasses_playing">正在 %1$s 上遊玩</string>
<string name="stores_fact_developer">開發商</string>
<string name="stores_fact_publisher">發行商</string>
@@ -2139,6 +2139,11 @@
<string name="glasses_head_tracking">頭部追蹤</string>
<string name="glasses_head_tracking_hint">眼鏡內建的感測器會隨頭部轉動虛擬螢幕和 SteamVR。</string>
<string name="glasses_recenter">重新置中視角</string>
<string name="glasses_recenter_button">重新置中</string>
<string name="glasses_auto_steamvr">連接眼鏡時啟動 SteamVR</string>
<string name="glasses_auto_steamvr_hint">在 Steam 中,插上眼鏡時啟動 SteamVR,拔除時停止。</string>
<string name="glasses_vr_fov">SteamVR 視野角度</string>
<string name="glasses_vr_fov_hint">調低讓 SteamVR 更近並填滿眼鏡;調高可看到更多周圍內容。</string>
<string name="glasses_playing">正在 %1$s 上遊玩</string>
<string name="stores_fact_developer">開發商</string>
<string name="stores_fact_publisher">發行商</string>
+5
View File
@@ -2396,5 +2396,10 @@
<string name="glasses_head_tracking">Head tracking</string>
<string name="glasses_head_tracking_hint">The glasses\' own sensors turn the virtual screen and SteamVR with your head.</string>
<string name="glasses_recenter">Recenter view</string>
<string name="glasses_recenter_button">Recenter</string>
<string name="glasses_auto_steamvr">Start SteamVR with the glasses</string>
<string name="glasses_auto_steamvr_hint">In Steam, SteamVR starts when the glasses are plugged in and stops when they are unplugged.</string>
<string name="glasses_vr_fov">SteamVR field of view</string>
<string name="glasses_vr_fov_hint">Lower brings SteamVR closer and fills the glasses; higher shows more around you.</string>
<string name="glasses_playing">Playing on %1$s</string>
</resources>
+2 -1
View File
@@ -61,7 +61,8 @@ switches the picture to side-by-side and runs SteamVR with three DroidDeck piece
1. **`driver_droiddeck.so`**, an OpenVR driver with one HMD:
- pose: the shared head pose file (3DoF, standing height);
- projection: exactly the frustum the Cardboard pass samples, with identity distortion (the app does
the lens);
the lens). A new frustum mid-run (the glasses' SteamVR field of view) goes out with
`SetDisplayProjectionRaw` and `VREvent_LensDistortionChanged`;
- a proximity sensor that reads "worn" while Cardboard mode is on. Without it SteamVR takes a still
headset (a phone on a table) for an unused one, enters standby after a few seconds, and the
compositor stops submitting frames;
@@ -95,6 +95,9 @@ OpenVR to SteamVR's ARM64 `vrclient.so`, so no x86 SteamVR is involved.
and KGSL does not order the copy after the client's GPU work. The presenter's blit sat behind the
game's frame, so the compositor showed the swapchain image's older picture. The presenter now
waits for its blit before it presents.
- **A new projection needs an event.** `SetDisplayProjectionRaw` changed what `vrserver` reports, but
`vrcompositor` kept the frustum it started with, so the glasses' field of view did nothing until
SteamVR restarted. The driver now follows it with `VREvent_LensDistortionChanged`.
- **Head-tracking axes.** With the display at `ROTATION_90`, screen x is minus device y and screen y is
device x. Getting this wrong made a turn at the hips tilt the view. Recentring now keeps the world
vertical and resets the heading only.
+1 -1
View File
@@ -674,7 +674,7 @@ def build_parser() -> argparse.ArgumentParser:
glasses_ops = glasses.add_subparsers(dest="glasses_op")
glasses_ops.add_parser("status")
glasses_ops.add_parser("allow", help="ask for USB control of the glasses again")
glasses_set = glasses_ops.add_parser("set", help="refreshHz, sbsHz, brightness, volume, sunblock, 3d, gameOnGlasses, headTracking, auto3d")
glasses_set = glasses_ops.add_parser("set", help="refreshHz, sbsHz, brightness, volume, sunblock, 3d, gameOnGlasses, headTracking, auto3d, picture3d, screenWidthDm, screenDistanceDm, vrFovDeg, autoSteamVr")
glasses_set.add_argument("key")
glasses_set.add_argument("value")
glasses_sim = glasses_ops.add_parser("simulate", help="feed a moving head pose (yaw, pitch and roll sweeps), or hold one")
+1
View File
@@ -612,6 +612,7 @@ private:
uint32_t w = 0, h = 0;
GetRecommendedRenderTargetSize(&w, &h);
VRServerDriverHost()->SetRecommendedRenderTargetSize(id_, w, h);
VRServerDriverHost()->VendorSpecificEvent(id_, VREvent_LensDistortionChanged, VREvent_Data_t{}, 0.0);
Log("eye now tan(half fov) %.3f, aspect %.3f (%ux%u eye%s), render %ux%u", tanHalf_.load(), eyeAspect_.load(), hp.eye_w, hp.eye_h,
(hp.flags & DROIDDECK_HEADPOSE_MONO) ? ", one eye shown" : "", w, h);
}