1import os 2import time 3 4import infra.basetest 5 6 7class TestWeston(infra.basetest.BRTest): 8 config = \ 9 """ 10 BR2_aarch64=y 11 BR2_TOOLCHAIN_EXTERNAL=y 12 BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y 13 BR2_TARGET_GENERIC_GETTY_PORT="ttyAMA0" 14 BR2_ROOTFS_OVERLAY="{}" 15 BR2_PER_PACKAGE_DIRECTORIES=y 16 BR2_LINUX_KERNEL=y 17 BR2_LINUX_KERNEL_CUSTOM_VERSION=y 18 BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.1.44" 19 BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y 20 BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/aarch64-virt/linux.config" 21 BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="{}" 22 BR2_PACKAGE_LIBDRM=y 23 BR2_PACKAGE_MESA3D=y 24 BR2_PACKAGE_MESA3D_GALLIUM_DRIVER_SWRAST=y 25 BR2_PACKAGE_MESA3D_LLVM=y 26 BR2_PACKAGE_MESA3D_OPENGL_EGL=y 27 BR2_PACKAGE_MESA3D_OPENGL_ES=y 28 BR2_PACKAGE_WAYLAND_UTILS=y 29 BR2_PACKAGE_WESTON=y 30 BR2_PACKAGE_WESTON_SIMPLE_CLIENTS=y 31 BR2_TARGET_ROOTFS_CPIO=y 32 BR2_TARGET_ROOTFS_CPIO_GZIP=y 33 # BR2_TARGET_ROOTFS_TAR is not set 34 """.format( 35 infra.filepath("tests/package/test_weston/overlay"), 36 infra.filepath("tests/package/test_weston/linux-vkms.fragment") 37 ) 38 39 def gen_read_disp_crcs_cmd(self, count=1): 40 # DRM CRCs are exposed through a sysfs pseudo file, one measure 41 # per line. The first column is the frame number, the second 42 # column is the CRC measure. We use "head" to get the needed 43 # CRC count. 44 disp_crc_path = "/sys/kernel/debug/dri/0/crtc-0/crc/data" 45 cmd = f"head -{count} {disp_crc_path}" 46 47 # The DRM CRC sysfs pseudo file lines are terminated by '\n' 48 # and '\0'. We remove the '\0' to have a text-only output. 49 cmd += " | tr -d '\\000'" 50 51 # Finally, we drop the frame counter, and keep only the second 52 # column (CRC values) 53 cmd += " | cut -f 2 -d ' '" 54 55 return cmd 56 57 def gen_count_unique_disp_crcs_cmd(self, count=10): 58 # We get the command generating one CRC per line... 59 cmd = self.gen_read_disp_crcs_cmd(count) 60 # ...then count the number of unique values 61 cmd += " | uniq | wc -l" 62 return cmd 63 64 def start_weston(self): 65 self.assertRunOk("export XDG_RUNTIME_DIR=/tmp") 66 67 cmd = "weston" 68 cmd += " --config=/etc/weston.ini" 69 cmd += " --continue-without-input" 70 cmd += " --log=/tmp/weston.log" 71 cmd += " &> /dev/null &" 72 self.assertRunOk(cmd) 73 74 self.assertRunOk("export WAYLAND_DISPLAY=wayland-1") 75 76 def wait_for_weston(self): 77 # We wait for the wayland socket to appear... 78 wayland_socket = "${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" 79 cmd = f"while [ ! -e \"{wayland_socket}\" ] ; do sleep 1 ; done" 80 self.assertRunOk(cmd, timeout=10) 81 time.sleep(4) 82 83 def stop_weston(self): 84 cmd = "killall weston && sleep 3" 85 self.assertRunOk(cmd) 86 87 def test_run(self): 88 img = os.path.join(self.builddir, "images", "rootfs.cpio.gz") 89 kern = os.path.join(self.builddir, "images", "Image") 90 self.emulator.boot(arch="aarch64", 91 kernel=kern, 92 kernel_cmdline=["console=ttyAMA0"], 93 options=["-M", "virt", 94 "-cpu", "cortex-a57", 95 "-smp", "4", 96 "-m", "256M", 97 "-initrd", img]) 98 self.emulator.login() 99 100 # Check the weston binary can execute 101 self.assertRunOk("weston --version") 102 103 self.start_weston() 104 self.wait_for_weston() 105 106 # Check a simple info client can communicate with the compositor 107 self.assertRunOk("wayland-info", timeout=10) 108 109 # This test will use the Kernel VKMS DRM Display CRC support, 110 # which is exposed in debugfs. See: 111 # https://docs.kernel.org/gpu/drm-uapi.html#display-crc-support 112 self.assertRunOk("mount -t debugfs none /sys/kernel/debug/") 113 114 # We get 10 consecutive DRM frame CRCs and count how many 115 # unique CRCs we have. Since weston is supposed to run idle, 116 # we should have 10 times the same display CRC. 117 cmd = self.gen_count_unique_disp_crcs_cmd() 118 output, exit_code = self.emulator.run(cmd) 119 self.assertEqual(exit_code, 0) 120 self.assertEqual(int(output[0]), 1) 121 122 # We save the CRC value of an empty weston desktop for 123 # later... 124 cmd = self.gen_read_disp_crcs_cmd() 125 output, exit_code = self.emulator.run(cmd) 126 self.assertEqual(exit_code, 0) 127 weston_desktop_crc = int(output[0], 16) 128 129 # We start the weston-simple-egl in background... Every 130 # rendered frame is supposed to be different (as the triangle 131 # animation is derived from the system time). Since all the 132 # rendering (client application and compositor) is in 133 # software, we sleep a bit to let those program to settle. 134 self.assertRunOk("weston-simple-egl >/dev/null 2>&1 &") 135 time.sleep(8) 136 137 # Since the weston-simple-egl client is supposed to run and 138 # display something, we are now supposed to measure a 139 # different display CRC than the one we measured when the 140 # desktop was empty. 141 cmd = self.gen_read_disp_crcs_cmd() 142 output, exit_code = self.emulator.run(cmd) 143 self.assertEqual(exit_code, 0) 144 self.assertNotEqual(int(output[0], 16), weston_desktop_crc) 145 146 # While weston-simple-egl is running, we check the VKMS DRM 147 # CRCs are now changing. We get many CRCs, one per display 148 # driver refresh (at ~60Hz). Since all the rendering is in 149 # software, we can expect a slow frame rate. In 300 captured 150 # CRCs (5s), we expect at least 5 different values (i.e. 1 fps). 151 # This guarantees the rendering pipeline is working, while we 152 # remain very permissive to slow emulation situations. 153 # Increase timeout, as the command is expected to run about 5s, 154 # which is the default timeout. 155 cmd = self.gen_count_unique_disp_crcs_cmd(300) 156 output, exit_code = self.emulator.run(cmd, timeout=10) 157 self.assertEqual(exit_code, 0) 158 self.assertGreaterEqual(int(output[0]), 5) 159 160 # We stop weston-simple-egl, and sleep a bit to let Weston do 161 # its cleanup and desktop repaint refresh... 162 self.assertRunOk("killall weston-simple-egl") 163 time.sleep(4) 164 165 # After we stopped the application, we should have the initial 166 # weston desktop background. The CRC we measure now should be 167 # the same as the one we saved earlier. 168 cmd = self.gen_read_disp_crcs_cmd() 169 output, exit_code = self.emulator.run(cmd) 170 self.assertEqual(exit_code, 0) 171 self.assertEqual(int(output[0], 16), weston_desktop_crc) 172 173 self.stop_weston() 174 175 # Now weston is supposed to be stopped, 176 # a simple client is expected to fail. 177 _, exit_code = self.emulator.run("wayland-info") 178 self.assertNotEqual(exit_code, 0) 179