Moving to offscreen Driver
This commit is contained in:
@@ -8,8 +8,8 @@ Type=simple
|
|||||||
User=pi
|
User=pi
|
||||||
WorkingDirectory=/opt/KH_Clock
|
WorkingDirectory=/opt/KH_Clock
|
||||||
|
|
||||||
# Tell SDL to render via KMS/DRM (required on Le Potato and similar ARM boards)
|
# SDL renders offscreen; pixels are blit directly to /dev/fb0 (Amlogic kmsdrm is unsupported)
|
||||||
Environment=SDL_VIDEODRIVER=kmsdrm
|
Environment=SDL_VIDEODRIVER=offscreen
|
||||||
|
|
||||||
# Disable console blanking so the TV stays on
|
# Disable console blanking so the TV stays on
|
||||||
ExecStartPre=/bin/sh -c 'echo -ne "\033[9;0]" > /dev/tty1'
|
ExecStartPre=/bin/sh -c 'echo -ne "\033[9;0]" > /dev/tty1'
|
||||||
|
|||||||
36
display.py
36
display.py
@@ -1,3 +1,4 @@
|
|||||||
|
import mmap
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@@ -147,7 +148,9 @@ class DisplayThread(threading.Thread):
|
|||||||
if self.dev_mode:
|
if self.dev_mode:
|
||||||
os.environ.setdefault("SDL_VIDEODRIVER", "x11")
|
os.environ.setdefault("SDL_VIDEODRIVER", "x11")
|
||||||
else:
|
else:
|
||||||
os.environ["SDL_VIDEODRIVER"] = "kmsdrm"
|
# SDL kmsdrm is incompatible with the Amlogic MESON DRM driver.
|
||||||
|
# Use offscreen rendering and blit pixels directly to /dev/fb0.
|
||||||
|
os.environ["SDL_VIDEODRIVER"] = "offscreen"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pygame.init()
|
pygame.init()
|
||||||
@@ -166,6 +169,19 @@ class DisplayThread(threading.Thread):
|
|||||||
clock = pygame.time.Clock()
|
clock = pygame.time.Clock()
|
||||||
screen_w, screen_h = screen.get_size()
|
screen_w, screen_h = screen.get_size()
|
||||||
|
|
||||||
|
# Open /dev/fb0 for direct pixel writes (framebuffer mode only)
|
||||||
|
fb0_mmap = None
|
||||||
|
fb0_file = None
|
||||||
|
if not self.dev_mode:
|
||||||
|
try:
|
||||||
|
bpp = int(Path("/sys/class/graphics/fb0/bits_per_pixel").read_text())
|
||||||
|
fb0_file = open("/dev/fb0", "rb+")
|
||||||
|
fb0_mmap = mmap.mmap(fb0_file.fileno(), screen_w * screen_h * (bpp // 8))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[display] Failed to open /dev/fb0: {e}")
|
||||||
|
pygame.quit()
|
||||||
|
return
|
||||||
|
|
||||||
clock_font_path = _find_font(self.config.clock_font_path, _CLOCK_FONT_CANDIDATES)
|
clock_font_path = _find_font(self.config.clock_font_path, _CLOCK_FONT_CANDIDATES)
|
||||||
msg_font_path = _find_font(self.config.message_font_path, _MESSAGE_FONT_CANDIDATES)
|
msg_font_path = _find_font(self.config.message_font_path, _MESSAGE_FONT_CANDIDATES)
|
||||||
|
|
||||||
@@ -205,9 +221,17 @@ class DisplayThread(threading.Thread):
|
|||||||
last_msg_text = None
|
last_msg_text = None
|
||||||
self._draw_clock(screen, clock_font, screen_w, screen_h)
|
self._draw_clock(screen, clock_font, screen_w, screen_h)
|
||||||
|
|
||||||
pygame.display.flip()
|
if fb0_mmap is not None:
|
||||||
|
fb0_mmap.seek(0)
|
||||||
|
fb0_mmap.write(pygame.image.tostring(screen, "BGRA"))
|
||||||
|
else:
|
||||||
|
pygame.display.flip()
|
||||||
clock.tick(self.config.fps)
|
clock.tick(self.config.fps)
|
||||||
|
|
||||||
|
if fb0_mmap:
|
||||||
|
fb0_mmap.close()
|
||||||
|
if fb0_file:
|
||||||
|
fb0_file.close()
|
||||||
pygame.quit()
|
pygame.quit()
|
||||||
|
|
||||||
def _create_surface(self) -> pygame.Surface:
|
def _create_surface(self) -> pygame.Surface:
|
||||||
@@ -218,10 +242,10 @@ class DisplayThread(threading.Thread):
|
|||||||
pygame.display.set_caption("KH Clock [DEV]")
|
pygame.display.set_caption("KH Clock [DEV]")
|
||||||
return surface
|
return surface
|
||||||
|
|
||||||
flags = pygame.FULLSCREEN | pygame.NOFRAME
|
# Read actual framebuffer dimensions from sysfs
|
||||||
if self.config.width and self.config.height:
|
size_str = Path("/sys/class/graphics/fb0/virtual_size").read_text().strip()
|
||||||
return pygame.display.set_mode((self.config.width, self.config.height), flags)
|
w, h = map(int, size_str.split(","))
|
||||||
return pygame.display.set_mode((0, 0), flags)
|
return pygame.display.set_mode((w, h))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _draw_clock(
|
def _draw_clock(
|
||||||
|
|||||||
Reference in New Issue
Block a user