I think I've got another solution to this but I haven't had the opportunity to test it on my projector yet. But based on the kernel code I think it should work. Basically the kernel and x11 appear to have all the required code to work properly right now. It is just xrandr which lacks support for the required drm mode flags (it doesn't support beyond "-CSync").
https://gitlab.freedesktop.org/xorg/app/xrandr/-/blob/master/xrandr.c#L90
You can see in the kernel all the flags are there though.
https://github.com/torvalds/linux/blob/5437f30d3458ad36e83ab96088d490ebfee844d8/include/drm/drm_modes.h#L303
https://github.com/torvalds/linux/blob/5437f30d3458ad36e83ab96088d490ebfee844d8/include/uapi/drm/drm_mode.h#L89
Also the kernel side(?) xlib xrandr library appears to just accept a 32bit mode flag and doesn't restrict it like the xrandr client side application does.
As such if you write some code to interface directly with the xlib xrandr library and send the proper 32 bit mode flag when you create your mode, you can create a monitor mode with the required "DRM_MODE_FLAG_3D_XXXXX"
Below is a simple python script showing how to create such a monitor mode.
I haven't tested it yet, but based on my understanding when you switch to that mode it should send the proper hdmi mode flag.
from __future__ import print_function
from Xlib import X, display
from Xlib.ext import randr
mode_flags = {
'DRM_MODE_FLAG_PHSYNC': (1<<0),
'DRM_MODE_FLAG_NHSYNC': (1<<1),
'DRM_MODE_FLAG_PVSYNC': (1<<2),
'DRM_MODE_FLAG_NVSYNC': (1<<3),
'DRM_MODE_FLAG_INTERLACE': (1<<4),
'DRM_MODE_FLAG_DBLSCAN': (1<<5),
'DRM_MODE_FLAG_CSYNC': (1<<6),
'DRM_MODE_FLAG_PCSYNC': (1<<7),
'DRM_MODE_FLAG_NCSYNC': (1<<8),
'DRM_MODE_FLAG_HSKEW': (1<<9), # /* hskew provided /
'DRM_MODE_FLAG_BCAST': (1<<10), # / deprecated /
'DRM_MODE_FLAG_PIXMUX': (1<<11), # / deprecated */
'DRM_MODE_FLAG_DBLCLK': (1<<12),
'DRM_MODE_FLAG_CLKDIV2': (1<<13),
#'DRM_MODE_FLAG_3D_NONE': (0<<14)
'DRM_MODE_FLAG_3D_FRAME_PACKING': (1<<14),
'DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE': (2<<14),
'DRM_MODE_FLAG_3D_LINE_ALTERNATIVE': (3<<14),
'DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL': (4<<14),
'DRM_MODE_FLAG_3D_L_DEPTH': (5<<14),
'DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH': (6<<14),
'DRM_MODE_FLAG_3D_TOP_AND_BOTTOM': (7<<14),
'DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF': (8<<14),
#'DRM_MODE_FLAG_3D_MASK': (0x1f<<14),
#'DRM_MODE_FLAG_PIC_AR_MASK': (0x0F<<19),
}
d = display.Display()
s = d.screen()
window = s.root.create_window(0, 0, 1, 1, 1, s.root_depth)
def get_modes():
res = randr.get_screen_resources(window)
for mode in res.modes:
mode_string = ''
for n, i in mode_flags.items():
if mode.flags & i == i:
mode_string += f' +{n}'
print(f'{mode.id} {mode.name if hasattr(mode, "name") else "noname"} {mode.name_length} {mode.width}, height: {mode.height}, mode_flags: {mode.flags}, mode_string: {mode_string}')
def create_mode():
based on existing timings "1920x2205_24.00" 148.5 1920 2366 2454 2750 2205 2209 2214 2250 +hsync +vsync
based on hdmi 3d spec "1920x2205_24.00" 148.5 1920 2558 2602 2750 2205 2209 2214 2250 +hsync +vsync https://archive.org/details/HDMI-1.4a-3D-Extract/page/n9/mode/1up
name = '1920x2205_24.00'
flags = mode_flags['DRM_MODE_FLAG_PHSYNC'] | mode_flags['DRM_MODE_FLAG_PVSYNC'] | mode_flags['DRM_MODE_FLAG_3D_FRAME_PACKING']
randr.create_mode(
window,
mode={
'id': 900,
'width': 1920,
'height': 2205,
'dot_clock': 148500000,
'h_sync_start': 2366,
'h_sync_end': 2454,
'h_total': 2750,
'h_skew': 0,
'v_sync_start': 2209,
'v_sync_end': 2214,
'v_total': 2250,
'name_length': len(name),
'flags': flags
},
name='1920x2205_24.00'
)
xrandr --addmode HDMI-1-1 "1920x2205_24.00"
xrandr --delmode HDMI-1-1 "1920x2205_24.00"
xrandr --rmmode "1920x2205_24.00"
create_mode()
get_modes()