Skip to content

Commit

Permalink
#3560 make mode calculations re-usable
Browse files Browse the repository at this point in the history
  • Loading branch information
totaam committed Jun 22, 2022
1 parent aa042ad commit cee954d
Showing 1 changed file with 84 additions and 77 deletions.
161 changes: 84 additions & 77 deletions xpra/x11/bindings/randr_bindings.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -556,9 +556,9 @@ cdef class RandRBindingsInstance(X11CoreBindingsInstance):
def set_screen_size(self, width, height):
return self._set_screen_size(width, height)

def add_screen_size(self, unsigned int w, unsigned int h):
name = "%sx%s" % (w, h)
mode = self.do_add_screen_size(name, w, h)
def add_screen_size(self, unsigned int w, unsigned int h, unsigned int vrefresh=DEFAULT_VSYNC):
name = "%sx%s@%s" % (w, h, vrefresh)
mode = self.do_add_screen_size(name, w, h, vrefresh)
#now add it to the output:
cdef RROutput output
if mode:
Expand All @@ -567,79 +567,14 @@ cdef class RandRBindingsInstance(X11CoreBindingsInstance):
XRRAddOutputMode(self.display, output, mode)
return mode

cdef do_add_screen_size(self, name, unsigned int w, unsigned int h, unsigned int vsync=0):
cdef do_add_screen_size(self, name, unsigned int w, unsigned int h, unsigned int vrefresh):
self.context_check("do_add_screen_size")
log("do_add_screen_size(%s, %i, %i)", name, w, h)
cdef RRMode mode

#monitor settings as set in xorg.conf...
cdef unsigned int maxPixelClock = 230*1000*1000 #230MHz
cdef unsigned int minHSync = 1*1000 #1KHz
cdef unsigned int maxHSync = 300*1000 #300KHz
cdef unsigned int minVSync = 1 #1Hz
cdef unsigned int maxVSync = 300 #30Hz
cdef double idealVSync = vsync or DEFAULT_VSYNC
cdef double timeHFront = 0.07 #0.074219; 0.075; Width of the black border on right edge of the screen
cdef double timeHSync = 0.1 #0.107422; 0.1125; Sync pulse duration
cdef double timeHBack = 0.15 #0.183594; 0.1875; Width of the black border on left edge of the screen
cdef double timeVBack = 0.06 #0.031901; 0.055664; // Adjust this to move picture up/down
cdef double yFactor = 1 #no interlace (0.5) or doublescan (2)

bname = strtobytes(name)
cdef Window window = XDefaultRootWindow(self.display)
cdef XRRModeInfo *new_mode = XRRAllocModeInfo(bname, len(bname))
log("do_add_screen_size(%s, %i, %i, %i)", name, w, h, vrefresh)
cdef XRRModeInfo *new_mode = self.calculate_mode(name, w, h, vrefresh)
assert new_mode!=NULL

cdef unsigned long clock
cdef RRMode mode = 0
cdef Window window = XDefaultRootWindow(self.display)
try:
xFront = int(w * timeHFront)
xSync = int(w * timeHSync)
xBack = int(w * timeHBack)
xTotal = w + xFront + xSync + xBack
yFront = 1
ySync = 3
yBack = int(h * timeVBack)
yTotal = h + yFront + ySync + yBack

modeMaxClock = maxPixelClock
if (maxHSync * xTotal)<maxPixelClock:
modeMaxClock = maxHSync * xTotal
tmp = maxVSync * xTotal * yTotal * yFactor
if tmp<modeMaxClock:
modeMaxClock = tmp
modeMinClock = minHSync * xTotal
# Monitor minVSync too low? => increase mode minimum pixel clock
tmp = minVSync * xTotal * yTotal * yFactor
if tmp > modeMinClock:
modeMinClock = tmp
# If minimum clock > maximum clock, the mode is impossible...
if modeMinClock > modeMaxClock:
log.warn("Warning: cannot add mode %s", name)
log.warn(" clock %iHz is above maximum value %iHz", modeMinClock, modeMaxClock)
log.warn(" no suitable clocks could be found")
return False

idealClock = idealVSync * xTotal * yTotal * yFactor
clock = idealClock;
if clock < modeMinClock:
clock = modeMinClock
elif clock > modeMaxClock:
clock = modeMaxClock

log("Modeline %sx%s %s %s %s %s %s %s %s %s %s", w, h, clock/1000/1000,
w, w+xFront, w+xFront+xSync, xTotal,
h, h+yFront, h+yFront+ySync, yTotal)
new_mode.width = w
new_mode.height = h
new_mode.dotClock = clock
new_mode.hSyncStart = int(w+xFront)
new_mode.hSyncEnd = int(w+xFront+xSync)
new_mode.hTotal = int(xTotal)
new_mode.hSkew = 0
new_mode.vSyncStart = int(h+yFront)
new_mode.vSyncEnd = int(h+yFront+ySync)
new_mode.vTotal = int(yTotal)
new_mode.modeFlags = 0
mode = XRRCreateMode(self.display, window, new_mode)
log("XRRCreateMode returned %#x" % mode)
if mode<=0:
Expand All @@ -658,6 +593,77 @@ cdef class RandRBindingsInstance(X11CoreBindingsInstance):
log("failed to remove older mode", exc_info=True)
return mode

cdef XRRModeInfo *calculate_mode(self, name, unsigned int w, unsigned int h, unsigned int vrefresh):
log("calculate_mode(%s, %i, %i, %i)", name, w, h, vrefresh)
#monitor settings as set in xorg.conf...
cdef unsigned int maxPixelClock = 230*1000*1000 #230MHz
cdef unsigned int minHSync = 1*1000 #1KHz
cdef unsigned int maxHSync = 300*1000 #300KHz
cdef unsigned int minVSync = 1 #1Hz
cdef unsigned int maxVSync = 600 #60Hz
cdef double idealVSync = vrefresh
cdef double timeHFront = 0.07 #0.074219; 0.075; Width of the black border on right edge of the screen
cdef double timeHSync = 0.1 #0.107422; 0.1125; Sync pulse duration
cdef double timeHBack = 0.15 #0.183594; 0.1875; Width of the black border on left edge of the screen
cdef double timeVBack = 0.06 #0.031901; 0.055664; // Adjust this to move picture up/down
cdef double yFactor = 1 #no interlace (0.5) or doublescan (2)

bname = strtobytes(name)
cdef Window window = XDefaultRootWindow(self.display)
cdef XRRModeInfo *mode = XRRAllocModeInfo(bname, len(bname))
assert mode!=NULL

cdef unsigned long clock
xFront = int(w * timeHFront)
xSync = int(w * timeHSync)
xBack = int(w * timeHBack)
xTotal = w + xFront + xSync + xBack
yFront = 1
ySync = 3
yBack = int(h * timeVBack)
yTotal = h + yFront + ySync + yBack

modeMaxClock = maxPixelClock
if (maxHSync * xTotal)<maxPixelClock:
modeMaxClock = maxHSync * xTotal
tmp = maxVSync * xTotal * yTotal * yFactor
if tmp<modeMaxClock:
modeMaxClock = tmp
modeMinClock = minHSync * xTotal
# Monitor minVSync too low? => increase mode minimum pixel clock
tmp = minVSync * xTotal * yTotal * yFactor
if tmp > modeMinClock:
modeMinClock = tmp
# If minimum clock > maximum clock, the mode is impossible...
if modeMinClock > modeMaxClock:
log.warn("Warning: cannot add mode %s", name)
log.warn(" clock %iHz is above maximum value %iHz", modeMinClock, modeMaxClock)
log.warn(" no suitable clocks could be found")
return NULL

idealClock = idealVSync * xTotal * yTotal * yFactor
clock = idealClock;
if clock < modeMinClock:
clock = modeMinClock
elif clock > modeMaxClock:
clock = modeMaxClock

log("Modeline %sx%s %s %s %s %s %s %s %s %s %s", w, h, clock/1000/1000,
w, w+xFront, w+xFront+xSync, xTotal,
h, h+yFront, h+yFront+ySync, yTotal)
mode.width = w
mode.height = h
mode.dotClock = clock
mode.hSyncStart = int(w+xFront)
mode.hSyncEnd = int(w+xFront+xSync)
mode.hTotal = int(xTotal)
mode.hSkew = 0
mode.vSyncStart = int(h+yFront)
mode.vSyncEnd = int(h+yFront+ySync)
mode.vTotal = int(yTotal)
mode.modeFlags = 0
return mode

def remove_screen_size(self, unsigned int w, unsigned int h):
#TODO: instead of keeping the mode ID,
#we should query the output and find the mode dynamically...
Expand Down Expand Up @@ -1008,7 +1014,7 @@ cdef class RandRBindingsInstance(X11CoreBindingsInstance):
screen_h = max(screen_h, y+height)
log("total screen area is: %ix%i", screen_w, screen_h)
if not self.has_mode(screen_w, screen_h):
self.add_screen_size(screen_w, screen_h)
self.add_screen_size(screen_w, screen_h, DEFAULT_VSYNC)
self.set_screen_size(screen_w, screen_h)
self.xrr_set_screen_size(screen_w, screen_h, dpi96(screen_w), dpi96(screen_h))
root_w, root_h = self.get_screen_size()
Expand Down Expand Up @@ -1070,6 +1076,7 @@ cdef class RandRBindingsInstance(X11CoreBindingsInstance):
if m.get("primary", False):
primary = i
x, y, width, height = m["geometry"]
vrefresh = m.get("vertical-refresh", DEFAULT_VSYNC)
#find an existing mode matching this resolution:
for j in range(output_info.nmode):
#find this RRMode in the screen modes info:
Expand All @@ -1093,13 +1100,13 @@ cdef class RandRBindingsInstance(X11CoreBindingsInstance):
mode_name, mode, width, height)
break
if not mode:
mode_name = "%sx%s" % (width, height)
mode_name = "%ix%i@%i" % (width, height, vrefresh)
#may have already been added:
mode = new_modes.get(mode_name, 0)
if not mode:
mode = self.do_add_screen_size(mode_name, width, height)
mode = self.do_add_screen_size(mode_name, width, height, vrefresh)
new_modes[mode_name] = mode
assert mode!=0, "mode %ix%i not found" % (width, height)
assert mode!=0, "mode %ix%i@%i not found" % (width, height, vrefresh)
XRRAddOutputMode(self.display, output, mode)
log("mode %r (%#x) added to output %i (%i)", mode_name, mode, i, output)
else:
Expand Down

0 comments on commit cee954d

Please sign in to comment.