-
-
Notifications
You must be signed in to change notification settings - Fork 644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cross platform GUI / 2D software rendering #35
Comments
Cosmopolitan currently has a razor sharp focus on tui interfaces because it's something we're able to do better than anyone else. I think cross-platform GUIs are great, but I need your support to raise the resources it requires. The way I'd likely approach the problem is by vendoring something like SDL into the codebase to give you a high-performance blank canvas with audio that works consistently across platforms. I think starting off this way makes the most sense, since games need high-performance graphics and therefore can't be written as web guis like most modern software these days. Please note that even GUI libraries as simple as SDL usually have a treasure trove of hidden dependencies. Cosmopolitan would need to vendor those too in order to uphold its mission of deterministic hermetically-sealed never-breaking behavior. We accomplish that by not making the assumption that the system did the legwork for us. Therefore it would some research to figure out the best way to vendor SDL dependencies and integrate with window management systems. Here's an example of the research that went into figuring out a way to portably integrate with kernels: libc/sysv/syscalls.sh, libc/sysv/consts.sh, and libc/nt/master.sh. I can make it happen. I believe it should happen. I don't think 200mb Electron hello world binaries are sustainable. Cosmopolitan can do it better than anyone else, if we raise the resources. So please check out https://github.com/sponsors/jart and tell your friends who might be interested in becoming sponsors. |
If you want to see some examples of the impact Cosmopolitan is already having in the terminal interface realm, then check out:
One of the reasons why we're able to do terminal interfaces so well, is because the technology is so old (teletypes were invented in the 19th century) that corporations have stopped bothering with the whole engineered incompatibility game and a consensus emerged surrounding the VT100 + termios interface that Cosmopolitan makes easy to use. |
Rather than SDL, maybe something like these "single header" and/or "ANSI C" GUI libraries might be easier to use:
|
The
It depends on what @jart wants to do, but I would recommend starting with basic provisions without hardware acceleration, like |
It took five hundred thousand lines of code to get stdio and sockets working across platforms without dependencies. Doing the same for GUIs would probably take 10x times that, which is roughly the size of the Chromium codebase. For example, there's an STB style header that does only audio integration which has 63,000 lines of code and it depends on lots of system libraries. Cosmopolitan makes it easy to take "the russians used a pencil" approach of just sending the raw audio samples to an cosmopolitan/examples/nesemu1.cc Lines 1704 to 1720 in d934f38
I think TUIs deserve more love. Modern terminal emulators make them better than they've ever been. I've recently used ANSI color for ASAN memory dumps. Here's a screenshot of the latest build of Blinkenlights which is an emulator TUI that's hosted in the Cosmopolitan codebase: Behold the paneling algorithm that makes it possible: cosmopolitan/tool/build/lib/panel.c Lines 28 to 155 in d934f38
Thanks to Cosmopolitan this emulator works exactly the same on FreeBSD, OpenBSD, Mac, and Windows. Here's a screenshot of it running a Linux ASAN binary on the Windows 10 DOS command prompt: Cosmopolitan also makes it easy to build offline web applications that can be distributed as a single file web server binary. See https://justine.lol/redbean/index.html which is hosted in the Cosmopolitan codebase. Those are just some examples of things we're already able to do better than anyone else. That's the best place to focus the 80% of attention: becoming better at the things we're already the best at. GUIs could be fruitful. I love STB style headers and this project has stb_image checked-in to third party. Although if I wanted to pursue GUIs then, based on what I just researched I'd probably try to find a way to build Chromium with Cosmopolitan. I've already borrowed a few things from their codebase, such as their zlib fork. It's astonishingly high quality code. |
What is the path of least resistance towards getting a no-hwaccel canvas running with the APE polyglot in use? Is this something that needs attention to specifics of the various platforms with fallbacks? If you believe this to be true @jart, I can get to work on that, going as far back as the original VGA spec, or even older if anyone cares. There sure is some novelty in Hercules and composite CGA, if nothing else. Also, what is the right approach towards having different codepaths depending on system features? In the basic sense, different windowing systems and old VGA-level stuff seems straightforward, but expanding that notion to the graphics APIs is something of a holy grail in this sense. It will be helpful to be able to detect details in a quasi-runtime state, even if that state is only known to the glue code provided by Cosmo, not the application itself. |
Cosmopolitan can already create a blank canvas on WIN32. If we can do the same thing for X11 then that will cover all our bases. Although on Mac it'd be a little ugly since the user would have to start the X11 program which IIRC comes included with Mac OS. The way I would probably approach the problem is to build the hello world x11 program from Rosetta Code and then use strace to reverse engineer the protocol. It appears the way it works is you need to open a UNIX domain socket to /tmp/.X11-unix/X0 and then you just send a bunch of binary frames back and forth. Here's what I got on Debian:
So yeah I would be pretty happy if we could talk to X11 directly without needing to touch Linux distro shared objects. X11 is a really old protocol that's been around since the 80's so I can't imagine its wire format will be changing anytime soon. Once we're able to talk to it, we just need to figure out what the magic numbers are to:
Then what you do with Cosmopolitan is you have if statements ilke this: if (IsWindows()) {
mdc = CreateCompatibleDC(ps.hdc);
mbm = CreateCompatibleBitmap(ps.hdc, r.right, r.bottom);
BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, r.right, r.bottom, mdc, 0, 0, kNtSrccopy);
// etc. etc. win32 mode
} else {
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0) = 3
rc = connect(fd, &(struct sockaddr_un){AF_UNIX, "/tmp/.X11-unix/X0"}, sizeof(struct sockaddr_un);
if {rc != -1) {
// etc. etc. x11 mode
} else {
for (y = 0; y < yn; y += 2) {
if (y) printf("\r\n");
for (x = 0; x < xn; ++x) {
printf("\033[48;2;%hhu;%hhu;%hhu;38;2;%hhu;%hhu;%hhum▄",
rgb[y + 0][x][0], rgb[y + 0][x][1], rgb[y + 0][x][2],
rgb[y + 1][x][0], rgb[y + 1][x][1], rgb[y + 1][x][2]);
// etc. etc. ansi terminal mode
}
} The last part for ANSI terminal mode is what I'd imagine would happen if the program can't figure out how to connect to the X11 server. See https://gist.github.com/jart/7428b2b955dfd6eff7b6d31e00414508 for an elegant explanation of how that's done. |
If Cosmo supports running from BIOS, doesn’t that necessitate VGA support? |
one simple approach on linux is to write directly into the active framebuffer: http://seenaburns.com/2018/04/04/writing-to-the-framebuffer/ |
Writing to |
Framebuffer is totally doable. Cosmopolitan already has support for it too. See PRINTVIDEO.COM which should still be able to play MPEG videos in the framebuffer even though that support was never fully fleshed out, since I normally only use Linux via SSH. cosmopolitan/tool/viz/printvideo.c Lines 1391 to 1463 in e345b42
cosmopolitan/tool/viz/lib/writetoframebuffer.c Lines 22 to 41 in e345b42
As for BIOS VGA that's equally simple to do. By default BIOS loads programs in teletype mode. With two lines of assembly e.g.
|
hi all! :) i just came to suggest some nice gems to check them out:
btw, u r about to go for x, but it can be considered to be depricated besides wayland, even if it will stay for a long while... (ps: im only around to learn some nice hacks, and cuz the c lib benchmarks are impressive, but multi platform stuffs are actually out of my interest. i might have a high latency, cuz of an extreme amount of todo...) bests, have fun! :) |
I'm closing this because Cosmopolitan intends to cater to the needs of people building online production services who want standard interfaces like serial / sockets / stdio / termios and tools like Wayland / X11 / Unity / TempleOS are the last thing they'd want going near production instances, although of the four TempleOS would probably be the least impactful since it uses VGA and SGABIOS is able to VGA displays back into SERIAL UART which effectively makes it headless once more. That said you can expect a change real soon where I'll be adding a linux kernel style negative memory managemer to your αcτµαlly pδrταblε εxεcµταblεs so that they'll be able to call C standard library functions like malloc() when you boot them on BIOS or UEFI. |
i didnt mean for those to be used as they are, on the 1st place, but basically as good resources... otherwise feel free to do whatever u want! :) |
Thou shalt not vendor TempleOS pls |
I do have a quick and dirty proof of concept (based on microui) for something that could work but isn't ideal at https://github.com/jacereda/rui/ rui.c is a microui renderer that sends quads via UDP to a local or remote program that will just render them using OpenGL (ruiview.c). The viewer sends back events to the microui side. The viewer should run on Windows/Mac/Unix. So, this is sort of poor man's Electron. What would be really nice is being able to embed the different platform versions of my canvas library (glcv) in the executable. It's really minimal and I guess the overhead would be a few KB. If I think something like what #278 describes could work for the X11/OpenGL use case, what do you think? |
All you have to do is put the platform local binaries inside the zip structure of the binary. You have to build the binary with a |
I have been exploring another approach and I think I can get cross-platform OpenGL rendering on the same process (no IPC). I've only tested the Linux side, I'll try to finish the Windows side to have a complete POC. |
@jacereda, nice! What are the dependencies here? |
It's just linking statically against a modified https://github.com/jacereda/glcv and loading at runtime opengl32.dll and dwmapi.dll (for the transparency support). On Linux, libGL, libX11, libXrender and libXcursor. |
And to lookup OpenGL functions I'm using a slightly modified Galogen file. The demo itself is from https://github.com/rxi/microui |
I need some time to cleanup the mess and publish the whole thing in a not-so-embarrassing state. |
Reopening because seeing is believing. @jacereda if you're willing to lead the Cosmopolitan GUI effort then I can support you. Your work is welcome here and would be appreciated by many people. For example @lemaitre recently began leading our Cosmopolitan Threads effort in #301 and #282 which is another exciting development, but still a work in progress. |
It's also worth mentioning that, thanks to @fabriziobertocci, we have support for UNIX domain sockets. Therefore it should now be possible to hack the X11 protocol to get a canvas. It'd be super cool if we could just do that without the runtime dependencies. Dependencies feel more real when you communicate with them using binary. It would also likely ensure it works on BSDs and probably XNU too since last time I checked Apple ships an X11 server that can be started. But you almost certainly can't rely on something like a libx11.so file being present somewhere on the file system. It's probably just the X11 wire format that all agree upon. In which case, all we need to do is figure out where the UNIX socket file is likely to be stored on all these systems. |
Possibly, but the idea's not without its problems. In staying with Cosmopolitan's stated principles, everything must be completely contained. That could be done, but it gets more difficult because of win32's built-in controls, all accessible through predefined window classes. That's potentially a lot of code, and and needs to stay small, IMO. However, all the graphics code would be platform-independent from the start, with only the frame buffer or FB emulator becoming platform dependent. I've been deep in your code learning about the repo and all that it contains, pretty amazing work. Now, I'm playing with various graphics ideas that could be somewhat easily "hermitically sealed" within Cosmopolitan, with win32 being the first. It has the benefit of being widely used, but disadvantage of possibly becoming too large. Another thought is the nuklear immediate-mode UI, which has some wide use. It's considerably lighter weight and has an updated look and feel. I have Nuklear now running direct to frame buffer emulator using an X11 frame buffer emulator to access it. This means it could be entirely encapsulated within Cosmopolitan fairly easily, and allow users to create their own UIs. Here it is running on framebuffer emulator on macOS, using an X11 client to access it, without flicker. (I'll create a movie of it if you like, which shows off much nicer): If the frame buffer emulator were rewritten to use SDL or something else rather than X11, and/or just move bits directly to a hardware Linux frame buffer, that might work well. |
Here is a nuklear immediate-mode UI movie demo using virtual frame buffer. This means all graphics programming could be completely encapsulated in a platform-independent way for each graphics application, whose authors would use the nuklear API to write their applications on top of Cosmopolitan. In this case, which is a bit different than win32, each nuklear application would be a Cosmopolitan binary, issuing small "nano-X" drawing commands over a named pipe to a nano-X server, which would be another Cosmopolitan binary. Since the applications are not doing any actual drawing, they remain quite small (kind of like X11 apps). The nano-X server does all the drawing, and allows multiple nuklear applications to attach simultaneously, acting like a window manager. However, the NX server draws only to a virtual frame buffer, so it could be quite platform independent. It gets its mouse and keyboard input via a fixed tiny protocol from the frame buffer emulator. The frame buffer emulator, here running as an X11 client on macOS, would probably not be a Cosmopolitan binary. It accesses the virtual frame buffer via a shared mmap file, and the keyboard/mouse via two named pipes. It all sounds a bit complicated, but the important point is the ability to keep the graphics component of the APE binaries very small and platform independent. Notice there is no flicker at all, even though all frame buffer bits are being rapidly interpreted (only when changed) by the frame buffer emulator. Screen.Recording.2022-03-31.at.8.06.40.PM.mov |
A lot of effort has gone into making everything completely contained. However I don't want hard stances to block progress on other things. For instance, I've had some local work in flight for a while to hopefully unblock the OpenBSD GUI work that's been happening in this thread. Since I think people want to see things happening above all (great screencasts by the way!) even though the most benefit is going to come from working towards a state where the user take full advantage of the self-definedness. That way you don't get things like distros changing DSOs ABIs breaking your apps. Not having to deal with ABIs has been a huge productivity booster for me, as anyone who's poked around the repo has probably noticed :-) |
One thing I'll note though is that, even if we need to link DSOs on some platform to support GUIs (like technically we link DSOs on WIN32 because there's no other way, but MS ABIs are super stable!) then it's absolutely never going to compromise the default link paths for platforms like Linux. Not ever. |
Hello @niutech, I am sorry, I don't yet have an APE binary of a Nuklear app to test with. I am still a couple steps away from that, and am gauging interest, to see whether this approach makes sense, or whether another method would work better. Also, in order for this to work with keyboard and mouse, a modified version of fbe would have to be used, which is currently tied to the nano-X window system for mouse and keyboard I/O. Both FBE versions require X11 for display output, and it would be nice to port FBE to SDL, for broader compatibility. So things are still a bit overly complicated. The next steps to getting a reasonable APE demo would require compiling Nuklear, as well as portions of the nano-X API and its underlying graphics engine with Cosmopolitan tools and header files. While the graphics sources are quite portable, I would like to do this without having to add them to the Cosmopolitan source tree, and would like to use standard header files. I am currently investigating how to best do this, while getting Cosmopolitan itself compiling well on macOS. Thank you! |
Hello @niutech, I (finally) have a Cosmopolitan APE binary demo of the Nuklear NodeEdit application I uploaded a screencast and screenshot of above. This is a completely self-contained binary which computes all graphics completely internally, as well as handles keyboard and mouse input: At this time, demo.com binary talks to an X11 based frame buffer emulator via some two shared memory files created in /tmp, as well a couple of named pipes in /tmp for keyboard and mouse input. These are created and handled automatically though:
You will have to use my enhanced FBE (frame buffer emulator), which comes from picoTK as yours did, but has enhancements to pass mouse and keyboard input over to the APE binary:
Then, run Note: all of this was created on macOS, which is not (yet) standardized on Cosmopolitan, but I hope will be shortly. @jart and I have a few more things to work out. Thus, this has not been tested on Linux! With a bit of work, it should be fairly easy to use Microwindows/nano-X to port any other Nuklear-based UI programs fairly easily to Cosmopolitan, without having to retrofit them with #include "cosmopolitan.h" or change from using the normal standard header files. That is, they would be ported without source code changes. Thank you! |
Thank you very much @ghaerr! I have compiled and run
even though these files exist:
I will try later on full Linux desktop. But how to run in on Windows or WSL? |
Hello @niutech,
The first error above is the graphics engine reporting failure on The two files /tmp/fbe-keyboard (and /tmp/fbe-mouse) are named pipes created by FBE using @jart may have some input on this, I haven't looked deeply into the named pipe translation, there have been a lot of Cosmopolitan enhancements for The New Technology (Windows) lately and my repo could be out of date. (I plan to fix that after getting macOS builds fully working shortly). [EDIT: Now that I think of it, my SUPPORT_VECTOR on macOS builds isn't yet set to include NT, but demo.com was built using a Cosmopolitan-provided v1.0 cosmopolitan.a which should have NT support included. Thus demo.com only has v1.0 NT support built in.] Thank you! |
I have now completed the work of getting nano-X building all the Nuklear and most nano-X demos for Cosmopolitan, including the nano-X server. This means that the file sizes for each of the graphical programs are smaller, as they don't do any actual drawing. Instead, each .com binary talks with the nano-X server via a UNIX socket, and the nano-X.com server talks with FBE via named pipes and a shared mmap file (described above). If interested, one can compile up and play with this themselves, by doing the following:
This will produce APE files in microwindows/src/bin, including bin/nano-X.com (the nano-X server) and demo-nuklear-*.com files, as well as the host bin/fbe (frame buffer emulator) . Executing the following will produce the demo shown below (yes, nano-X roaches hiding under windows thrown in for fun):
Cosmo.nano-X.movAny Nuklear graphical .com program started will automatically connect to the server, and work with the keyboard and mouse. It will exit when the close box is clicked. It would take some work, but FBE could be rewritten to use SDL or something more modern than X11, providing better portability for some systems. |
@ghaerr I can confirm your Now let's make it work in Windows. |
Hello @niutech, Glad it's working on Linux, thanks for the testing!
Now that you can compile up this demo directly yourself from the nano-X repo as described above, I suggest you do that linking with cosmopolitan.a from its latest version. You may find it all works, as my Cosmo repo is a bit outdated for the time being. Should it not work, perhaps @jart or @pkulchenko could tell how to turn on system call tracing so that we can determine what the problem might be. I am guessing that it is likely something to do with either UNIX sockets or named pipes on Windows, if a recompilation with the latest repo still fails. The vast majority of the nano-X code is completely portable across operating systems. Thank you! |
@niutech looking good on ubuntu 22.04 |
It segfaults on Ubuntu 18.04. |
It should probably be due to different glibc versions. The binary embeds prebuilt ELF files for this program: https://github.com/jacereda/cosmogfx/blob/main/helper.c Detecting glibc version and loading the appropriate helper binary could be an option, but I don't have the time/energy to write that. |
Hello everyone! |
@Alexiril Great work, thanks! I can confirm it works in Windows 11: Would you like to support Mac OS too? |
Thanks for testing!
Sure, once I understand how Cosmopolitan and SDL dylib libraries work in macOS. |
@Alexiril Could you add a link to your project to the wiki? https://github.com/jart/cosmopolitan/wiki You could also send a pull request (see CONTRIBUTING.md) creating a Headers like these: #include <libc/isystem/iostream>
#include <libc/isystem/memory>
#include <libc/isystem/string> Can be this, with cosmocc: #include <iostream>
#include <memory>
#include <string> That applies to the mono repo now too. Great work on the You may also want to join our Discord in the #gui channel. https://discord.gg/n66pHA3A |
related read about creating X11 windows without using Xlib or anything, just the X11 docs and socket syscalls: |
Hi, @jart. I don't know if you are aware of a less-known, but well-designed, cross-platform native GUI framework written in pure C called NAppGUI: https://github.com/frang75/nappgui_src I think it could work well with cosmopolitan. They share a very similar spirit, I think. |
It's not written in pure C if it depends on GUI libraries. NAppGUI won't work. What will work is SDL. That's what I recommend using with Cosmopolitan for GUIs. (Although creating a command line web server with a browser GUI is a better idea.) See the following project for a demo https://github.com/hclarke/triangle-sine Here's an even better demo of how to do it with cosmo: https://github.com/z-erica/cosmopolitan-sdl2 |
Well, it wraps the common subset of Win32/GDI, GTK and Cocoa controls into a very thin cross-platform layer that papers over their idiosyncrasies. It does not have any dependencies apart from the OS-provided libraries. Just like SDL2. It is its own thing. I don't think web stuff, Nuklear or ImGui are comparable to native controls, both from an accessibility and integration standpoint. They definitely aren't native in the way cosmopolitan aims. |
Here's 2k LOC in C that works on X11, cocoa, and WinAPI. It's built on fenster and microui and the line count includes both those libraries. I make no claims that it's fast |
@tekknolagi That's great! But does it compile with Cosmpolitan libc? Could you provide an APE binary for testing? |
I've noticed that cosmopolitan supports the creation of gui applications on windows.
I'm curious on your thoughts on how you'd go about extending this to the remaining platforms.
I'd be happy to make contributions in this direction but I'm not too familliar on how things work on Mac & BSD.
The text was updated successfully, but these errors were encountered: