A mysterious USB device appears.
-
max@max-VirtualBox:~$ ssh root@192.168.1.150 root@192.168.1.150's password: BusyBox v1.25.1 () built-in shell (ash) ____ _ ____ / __ \___ (_)__ ___ / __ \__ _ ___ ___ ____ _ / /_/ / _ \/ / _ \/ _ \ / /_/ / ' \/ -_) _ `/ _ `/ \____/_//_/_/\___/_//_/ \____/_/_/_/\__/\_, /\_,_/ W H A T W I L L Y O U I N V E N T ? /___/ ----------------------------------------------------- Ω-ware: 0.2.0 b196 ----------------------------------------------------- root@Omega-C465:~# dmesg [...] [ 4128.461155] usb 1-1: new high-speed USB device number 3 using ehci-platform [ 4133.581154] usb 1-1: device descriptor read/64, error -145 [ 4133.842306] usb 1-1: New USB device found, idVendor=17e9, idProduct=0290 [ 4133.849139] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [ 4133.856428] usb 1-1: Product: DL-165 Adapter [ 4133.860770] usb 1-1: Manufacturer: DisplayLink [ 4133.865303] usb 1-1: SerialNumber: 861145 [ 4133.889629] [drm] vendor descriptor length:22 data:22 5f 01 00 20 05 00 01 03 04 02 [ 4134.068033] udl 1-1:1.0: fb0: udldrmfb frame buffer device [ 4134.074640] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013). [ 4134.081415] [drm] No driver support for vblank timestamp query. [ 4134.087415] [drm] Initialized udl on minor 0 root@Omega-C465:~# ls -l /dev/fb* crw------- 1 root root 29, 0 Jan 1 1970 /dev/fb0 root@Omega-C465:~# ls -l /dev/dri/ crw------- 1 root root 226, 0 Jan 1 1970 card0 crw------- 1 root root 226, 64 Jan 1 1970 controlD64 root@Omega-C465:~# ./modetest -M udl -c Connectors: id encoder status name size (mm) modes encoders 22 0 connected DVI-I-1 510x290 13 21 modes: name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot) 1920x1080 60 1920 1968 2000 2080 1080 1083 1088 1111 flags: phsync, nvsync; type: preferred, driver 1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 flags: phsync, pvsync; type: driver 1680x1050 60 1680 1728 1760 1840 1050 1053 1059 1080 flags: phsync, nvsync; type: driver 1280x1024 75 1280 1296 1440 1688 1024 1025 1028 1066 flags: phsync, pvsync; type: driver 1280x1024 60 1280 1328 1440 1688 1024 1025 1028 1066 flags: phsync, pvsync; type: driver 1152x864 75 1152 1216 1344 1600 864 865 868 900 flags: phsync, pvsync; type: driver 1024x768 75 1024 1040 1136 1312 768 769 772 800 flags: phsync, pvsync; type: driver 1024x768 60 1024 1048 1184 1344 768 771 777 806 flags: nhsync, nvsync; type: driver 800x600 75 800 816 896 1056 600 601 604 625 flags: phsync, pvsync; type: driver 800x600 60 800 840 968 1056 600 601 605 628 flags: phsync, pvsync; type: driver 640x480 75 640 656 720 840 480 481 484 500 flags: nhsync, nvsync; type: driver 640x480 60 640 656 752 800 480 490 492 525 flags: nhsync, nvsync; type: driver 720x400 70 720 738 846 900 400 412 414 449 flags: nhsync, pvsync; type: driver props: 1 EDID: flags: immutable blob blobs: value: 00ffffffffffff001e6d1c57973e0300 0a130103ea331d78eaaec5a2574a9c25 125054a54b00b300818f8180714f0101 0101010101011a3680a070381f403020 3500fe221100001a023a801871382d40 582c4500fe221100001e000000fd0038 4b1e530f000a202020202020000000fc 0057323434330a2020202020202000ad 2 DPMS: flags: enum enums: On=0 Standby=1 Suspend=2 Off=3 value: 0 18 dirty: flags: immutable enum enums: Off=0 On=1 Annotate=2 value: 1 root@Omega-C465:~# ./modetest -M udl -s 22:1920x1080 setting mode 1920x1080-60Hz@XR24 on connectors 22, crtc 20
Yep, that's an Omega2 outputting a 1920x1080p@60Hz HDMI video signal. With a little help via USB.
More soon ;).
-
Using kmscon:
root@Omega-C465:/# kmscon --font-engine unifont --render-engine bbulk [0000.000000] NOTICE: kmscon Revision kmscon-8 Oct 6 2018 12:10:18 [0000.297721] NOTICE: vt: using tty /dev/tty2
A login shell via the HDMI output and a USB keyboard!
It's still a bit slow, though. Anyways, I'll now look into how I can write to the framebuffer directly either using the Linux DRI/DRM system or the mirrored
/dev/fb0
..
-
Okay, all of this Direct Rendering Instrastructure (DRI) and Direct Renderer Manager (DRM) is weird and probably more overhead than needed.
I got mesa3D (
libGL
with OpenGL(ES)) support to compile, but the kmscube demo just won't display anything on its output.. A very simple DRM test program seems to recognize the correct resolution but just displays a black screen (not "no signal", but "all pixels are black").I'm thinking about compiling X11/Xorg server for the heck of it, just to see if it runs.. Maybe even LXDE on top of it?
Anyways, on Wikipedia I found libdlo. A libusb-0.1 library to bypass all the kernel drivers and directly talk to the DisplayLink USB device. With the
libusb-compat_0.1.4-2_mipsel_24kc.ipk
installed on the Omega2 and the library and its test-program cross-compiled, it actually does produce an output! Maybe I'll use this for a small test program until I figure out why writing to/dev/fb0
leaves the video signal on "disconnected" or figure out the right sequence of DRM commands with which themodetest
program could output its nice colored test signal.root@Omega-C465:~# test1 test: argv[0]: test1 test: init... test: basic graphics tests... test: device info: uid &77B93C20 test: device info: serial 861145 test: device info: type &F test: native mode info... 1920x1080 @ 59 Hz 24 bpp base &0 test: set_mode... test: mode info... 1920x1080 @ 59 Hz 24 bpp base &0 test: cls... took 40 ms test: random white dots... took 41 ms test: random rectangles... took 50 ms test: central rectangles... took 75 ms test: white box outline... took 1 ms test: copy central box... took 9 ms test: copy central box (off edges of viewport)... took 4 ms est: overlapping copy tests... test: viewport tests... test: cls (three banks)... took 117 ms test: plot crosses (three banks)... took 29 ms test: switching to screen bank 1... test: switching to screen bank 2... test: switching to screen bank 0... test: screen scraping tests... test: bitmap file 'test08.bmp' bmp->hdr.magic 4D42 bmp->hdr.file_sz 00001F8E (8078) bmp->hdr.reserved1 0000 bmp->hdr.reserved2 0000 bmp->hdr.pix_offset 00000436 bmp->dib.dib_hdr_sz 00000028 bmp->dib.width 0000008C (140) bmp->dib.height 00000032 (50) bmp->dib.col_planes 0001 bmp->dib.bpp 0008 (8) bmp->dib.compression 00000000 bmp->dib.raw_size 00001B58 (7000) bmp->dib.x_pix_meter 00000DD7 bmp->dib.y_pix_meter 00000DD7 bmp->dib.pal_entries 00000100 (256) bmp->dib.imp_cols 00000000 test: bitmap file 'test16.bmp' bmp->hdr.magic 4D42 bmp->hdr.file_sz 000036E6 (14054) bmp->hdr.reserved1 0000 bmp->hdr.reserved2 0000 bmp->hdr.pix_offset 00000036 bmp->dib.dib_hdr_sz 00000028 bmp->dib.width 0000008C (140) bmp->dib.height 00000032 (50) bmp->dib.col_planes 0001 bmp->dib.bpp 0010 (16) bmp->dib.compression 00000000 bmp->dib.raw_size 000036B0 (14000) bmp->dib.x_pix_meter 00000DD7 bmp->dib.y_pix_meter 00000DD7 bmp->dib.pal_entries 00000000 (0) bmp->dib.imp_cols 00000000 test: bitmap file 'test24.bmp' bmp->hdr.magic 4D42 bmp->hdr.file_sz 0000523E (21054) bmp->hdr.reserved1 0000 bmp->hdr.reserved2 0000 bmp->hdr.pix_offset 00000036 bmp->dib.dib_hdr_sz 00000028 bmp->dib.width 0000008C (140) bmp->dib.height 00000032 (50) bmp->dib.col_planes 0001 bmp->dib.bpp 0018 (24) bmp->dib.compression 00000000 bmp->dib.raw_size 00005208 (21000) bmp->dib.x_pix_meter 00000DD7 bmp->dib.y_pix_meter 00000DD7 bmp->dib.pal_entries 00000000 (0) bmp->dib.imp_cols 00000000 test: bitmap file 'test32.bmp' bmp->hdr.magic 4D42 bmp->hdr.file_sz 00006D96 (28054) bmp->hdr.reserved1 0000 bmp->hdr.reserved2 0000 bmp->hdr.pix_offset 00000036 bmp->dib.dib_hdr_sz 00000028 bmp->dib.width 0000008C (140) bmp->dib.height 00000032 (50) bmp->dib.col_planes 0001 bmp->dib.bpp 0020 (32) bmp->dib.compression 00000000 bmp->dib.raw_size 00006D60 (28000) bmp->dib.x_pix_meter 00000DD7 bmp->dib.y_pix_meter 00000DD7 bmp->dib.pal_entries 00000000 (0) bmp->dib.imp_cols 00000000 test: bitmap clipping test... bmp->hdr.magic 4D42 bmp->hdr.file_sz 00001F8E (8078) bmp->hdr.reserved1 0000 bmp->hdr.reserved2 0000 bmp->hdr.pix_offset 00000436 bmp->dib.dib_hdr_sz 00000028 bmp->dib.width 0000008C (140) bmp->dib.height 00000032 (50) bmp->dib.col_planes 0001 bmp->dib.bpp 0008 (8) bmp->dib.compression 00000000 bmp->dib.raw_size 00001B58 (7000) bmp->dib.x_pix_meter 00000DD7 bmp->dib.y_pix_meter 00000DD7 bmp->dib.pal_entries 00000100 (256) bmp->dib.imp_cols 00000000 test: release &77B93C20... test: final... test: finished. root@Omega-C465:~# ls
cls... took 40 ms
benchmarks the time it takes to fill the entire screen with black pixels and send it to the framebuffer. This should be more or less the time it takes to copy an in-RAM framebuffer via USB to the display. And 40ms on 1920x1080p means 25FPS. Pretty respectable for a USB 2.0 device.But my little gameboy emulator doesn't need that many pixels, so switching to a 240p resolution should make this thing waaaaay faster :). Full-Speed emulation for a Game Boy Color, at least. Less CPU time needed for pushing a framebuffer means that also higher console generation tiers (NES, SNES,..) might be possible with this approach.
Let's see where this goes.
-
So I did compile this
libDLO
library and the performance was terrible. 23 FPS for copying a 160x144 RGB16 framebuffer over USB to the device. Turns out the above 40ms for filling the entire screen with one color uses a different code path, a way more efficient one, for crafting the USB packet. Will look into that.However, it turns out that this library internally converts the given framebuffer to a 24bit RGB framebuffer, pixel-by-pixel, and then tries to send entire rows to the USB device. Also, when
make
-ing the library, it compiled it without optimizations!So I did use
CFLAGS="-O3"
, inserted the optimized library, and tada.. Game Boy Color emulation at ~90FPS. Internally I set the resolution to 640x480 and use thedlo_copy_host_bmp()
function to copy the smaller framebuffer to the right position of the device's framebuffer.root@Omega-C465:~# ./gnuboy Pokemon\ Gold\ \(G\)\ [C][!].gbc test: device info: uid &77B2AC70 test: device info: serial 861145 test: device info: type &F test: native mode info... 1920x1080 @ 59 Hz 24 bpp base &0 test: set_mode... test: mode info... 640x480 @ 60 Hz 24 bpp base &0 DisplayLink Init OK pcm_init() Doing joy_init. Init done. [-] Skipping data decompression. vid_settitle: POKEMON_GLDAAUD. FPS: 88.372 delta micros 1357896 for 120 frames FPS: 87.144 delta micros 1377025 for 120 frames FPS: 81.944 delta micros 1464420 for 120 frames
Will update the repos soon. So now you can play GameBoy and GameBoy Color on a normal monitor with HDMI/DVI/VGA input and this USB graphics card.
However, this is still way to slow. The to-be-transfered framebuffer was really tiny here and the transfor should have gone even fast than that. The pixel-by-pixel conversion definitely hurts performance. Also I'm completly bypassing the entire Linux by not using the framebuffer device or the DRI/DRM functions, but writing directly to the USB device using
libusb
.I'll look into the performance of these two other methods once I get them working. Right now writing to
/dev/fb0
doesn't update the screen and only one out of 2 test programs for the DRI/DRM system are working. Maybe has to do something with the kernel-mode-setting (KMS) routines. Another option would be optimizing the libDLO library to omit some sanity checks and use a more efficient frame buffer format that does not require pixel-by-pixel transforms. I'll see.
-
Here's a link to a demonstration video! GameBoy Color emulation at 60FPS, properly synchronized using the audio. Using a DisplayLink DL-165, a FullHD monitor, a USB audio card and a WiiClassic I²C controller.
Most of the CPU time is taken up by the routine that sends the framebuffer via USB. If that were not there, the CPU load would go down from 60% to about 26%. Which means that there's a lot of things to optimize here yet...
I'll go the 'X11 Xorg server' route for a while and see where that takes me :).