Skip to content

Commit

Permalink
#4201 test tool for opengl backing
Browse files Browse the repository at this point in the history
  • Loading branch information
totaam committed Aug 1, 2024
1 parent 272016d commit cadfa0d
Showing 1 changed file with 212 additions and 0 deletions.
212 changes: 212 additions & 0 deletions tests/xpra/clients/gl_scroll.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
#!/usr/bin/env python3
# This file is part of Xpra.
# Copyright (C) 2012-2016 Antoine Martin <[email protected]>
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.

import sys
import struct
from io import BytesIO
from typing import TypeAlias

from PIL import Image

from xpra.log import Logger
from xpra.os_util import gi_import, POSIX, OSX
from xpra.util.io import load_binary_file
from xpra.util.objects import typedict
from xpra.gtk.window import add_close_accel
from xpra.gtk.signals import install_signal_handlers
from xpra.client.gl.window import get_gl_client_window_module
from xpra.common import force_size_constraint
from xpra.client.gui.fake_client import FakeClient
from xpra.client.gui.window_border import WindowBorder

Gtk = gi_import("Gtk")
Pango = gi_import("Pango")

log = Logger()


ScreenUpdate: TypeAlias = tuple[int, int, int, int, str, bytes | tuple, int, typedict]


class TestGLRender:

def __init__(self):
from xpra.codecs.loader import load_codec
load_codec("dec_pillow")

self.ww = 800
self.wh = 600

self.index = 0
self.updates = self.gen_updates()

self.opengl_props, gl_client_window_module = get_gl_client_window_module("force")
self.GLClientWindowClass = gl_client_window_module.GLClientWindow

self.gl_window = self.init_gl_window()
self.control_window = self.init_control_window()

def gen_updates(self) -> list[ScreenUpdate]:
# fake some draw packets
w = self.ww
h = self.wh

def fullrgb(data: bytes) -> ScreenUpdate:
return 0, 0, w, h, "rgb32", data, w * 4, typedict()

def b(v: int) -> bytes:
return struct.pack("@B", v)

packets = [
# clear it
fullrgb(b"\0"*4*w*h),
# white:
fullrgb(b"\xff" * 4 * w * h),
# gradient grey:
fullrgb(b"".join(b(round(y * 255 / h)) * 4 * w for y in range(h))),
# gradient grey:
fullrgb(b"".join((b(round(y * 255 / h)) + b"\x80\x40\xff") * w for y in range(h)))
]

def add_scroll(dy: int, fill: bytes):
# scroll data: (x, y, w, h, xdelta, ydelta)
scroll_h = abs(dy)
scrolls = [
(0, max(0, -dy), w, h-scroll_h, 0, dy)
]
packets.append((0, 0, w, h, "scroll", scrolls, 0, typedict({"flush": 1})))
stride = w * 4
data = fill * stride * scroll_h
if dy > 0:
# scrolling down, fill the top:
filly = 0
else:
filly = h + dy
packets.append((0, filly, w, scroll_h, "rgb32", data, stride, typedict()))
# scroll up:
add_scroll(-10, b"\xff")
# scroll down:
add_scroll(-20, b"\x80")

from xpra.platform.paths import get_icon_filename
filename = get_icon_filename("xpra")
ext = filename.split(".")[-1]
icon = load_binary_file(filename)
img = Image.open(BytesIO(icon))
iw, ih = img.size
assert icon

def add_icon(x: int, y: int, options: typedict) -> None:
packets.append((x, y, iw, ih, ext, icon, iw*4, options))
count = h // ih + 1
for y in range(count):
add_icon(w // 2, y * ih, typedict({"flush": count-1-y}))
return packets

def init_control_window(self) -> None:
window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL)
window.set_transient_for(self.gl_window)
window.set_size_request(1920, 720)

vbox = Gtk.VBox(homogeneous=False, spacing=0)

hbox = Gtk.HBox(homogeneous=True, spacing=10)
vbox.pack_start(hbox, False, False, 10)

pu = Gtk.Button(label="Previous Update")
pu.connect("clicked", self.previous_update)
hbox.add(pu)
nu = Gtk.Button(label="Next Update")
nu.connect("clicked", self.next_update)
hbox.add(nu)

self.label = Gtk.Label()
fontdesc = Pango.FontDescription("monospace 9")
self.label.modify_font(fontdesc)
self.label.set_margin_start(10)
self.label.set_xalign(0)
self.label.set_line_wrap(True)
vbox.pack_start(self.label, True, True, 0)

window.add(vbox)

window.connect("delete-event", self.close)
add_close_accel(window, self.close)
return window

def init_gl_window(self) -> None:
noclient = FakeClient()
x = 2000
y = 1000
metadata = typedict({"has-alpha": True})
metadata.update(force_size_constraint(self.ww, self.wh))
border = WindowBorder()
max_window_size = (4096, 4096)
default_cursor_data = None
pixel_depth = 32

window = self.GLClientWindowClass(noclient, None, 0, 2 ** 32 - 1, x, y, self.ww, self.wh, self.ww, self.wh,
metadata, False, typedict({}),
border, max_window_size, default_cursor_data, pixel_depth)
window_backing = window._backing
window.realize()
window_backing.paint_screen = True
window.connect("delete-event", self.close)
add_close_accel(window, self.close)
return window

def previous_update(self, *_args) -> None:
if self.index > 0:
self.index -= 1
self.show_update()

def next_update(self, *_args) -> None:
if self.index < len(self.updates) - 1:
self.index += 1
self.show_update()

def show_update(self) -> None:
update = self.updates[self.index]

def show_result(*args):
log.info(f"show_result%s for {update[4]}", args)

self.gl_window.draw_region(*update, callbacks=[show_result])
encoding = update[4]
x = update[0]
y = update[1]
self.label.set_text(f"{encoding} at {x}x{y}")

def run(self) -> None:
install_signal_handlers("test-gl-scroll", self.close)
self.gl_window.show_all()
self.control_window.show_all()
self.show_update()
Gtk.main()
self.control_window.close()
self.gl_window.close()

def close(self, *_args) -> None:
Gtk.main_quit()


def main() -> int:
from xpra.platform import program_context
from xpra.platform.gui import init as gui_init
from xpra.log import enable_color, consume_verbose_argv
with program_context("OpenGL Native Context Check"):
if POSIX and not OSX:
from xpra.x11.gtk.display_source import init_gdk_display_source
init_gdk_display_source()
gui_init()
enable_color()
consume_verbose_argv(sys.argv, "opengl")
TestGLRender().run()
return 0


if __name__ == "__main__":
sys.exit(main())

0 comments on commit cadfa0d

Please sign in to comment.