unrealxr/libunreal/linux/__init__.py

84 lines
4.2 KiB
Python

import subprocess
import os
from libunreal.supported_devices import supported_devices
from libunreal.edid import UnrealXRDisplayMetadata
import pyedid
def upload_new_device_edid(display_spec: UnrealXRDisplayMetadata, edid: bytes | bytearray):
pass
def fetch_xr_glass_edid(allow_unsupported_devices) -> UnrealXRDisplayMetadata:
# Scan for all VGA devices and their IDs
pci_device_comand = subprocess.run(["lspci"], capture_output=True)
if pci_device_comand.returncode != 0:
raise OSError("Failed to scan PCI devices")
pci_devices: list[str] = pci_device_comand.stdout.decode("utf-8").split("\n")
pci_devices = pci_devices[:-1]
vga_devices: list[str] = []
for pci_device in pci_devices:
if "VGA compatible controller:" in pci_device:
vga_devices.append(pci_device[:pci_device.index(" ")])
# Attempt to find any XR glasses
for vga_device in vga_devices:
card_devices = list(os.listdir(f"/sys/devices/pci0000:00/0000:{vga_device}/drm/"))
for card_device in card_devices:
if "card" not in card_device:
continue
monitors = list(os.listdir(f"/sys/devices/pci0000:00/0000:{vga_device}/drm/{card_device}/"))
for monitor in monitors:
if card_device not in monitor:
continue
with open(f"/sys/devices/pci0000:00/0000:{vga_device}/drm/{card_device}/{monitor}/edid", "rb") as edid:
raw_edid_file = edid.read()
if len(raw_edid_file) == 0:
continue
edid = pyedid.parse_edid(raw_edid_file)
for manufacturer, manufacturer_supported_devices in supported_devices.items():
if edid.manufacturer_pnp_id == manufacturer and (edid.name in manufacturer_supported_devices or allow_unsupported_devices):
max_width = 0
max_height = 0
max_refresh = 0
for resolution in edid.resolutions:
if resolution[0] > max_width and resolution[1] > max_height:
max_width = resolution[0]
max_height = resolution[1]
max_refresh = max(max_refresh, int(resolution[2]))
if max_width == 0 or max_height == 0:
if "max_width" not in manufacturer_supported_devices[edid.name] or "max_height" not in manufacturer_supported_devices[edid.name]:
raise ValueError("Couldn't determine maximum width and height, and the maximum width and height isn't defined in the device quirks section")
max_width = int(manufacturer_supported_devices[edid.name]["max_width"])
max_height = int(manufacturer_supported_devices[edid.name]["max_height"])
if max_refresh == 0:
if "max_refresh" not in manufacturer_supported_devices[edid.name]:
raise ValueError("Couldn't determine maximum refresh rate, and the maximum refresh rate isn't defined in the device quirks section")
max_refresh = int(manufacturer_supported_devices[edid.name]["max_refresh"])
return UnrealXRDisplayMetadata(raw_edid_file, edid.manufacturer_pnp_id, manufacturer_supported_devices[edid.name], max_width, max_height, max_refresh, card_device, monitor.replace(f"{card_device}-", ""))
raise ValueError("Could not find supported device. Check if the device is plugged in. If it is plugged in and working correctly, check the README or open an issue.")
def upload_edid_firmware(display: UnrealXRDisplayMetadata, fw: bytes | bytearray):
if display.linux_drm_connector == "" or display.linux_drm_card == "":
raise ValueError("Linux DRM connector and/or Linux DRM card not specified!")
with open(f"/sys/kernel/debug/dri/{display.linux_drm_card.replace("card", "")}/{display.linux_drm_connector}/edid_override", "wb") as kernel_edid:
kernel_edid.write(fw)