From ba4131abbfab9a92100caddbca63f1a990b41842 Mon Sep 17 00:00:00 2001 From: veclavtlica Date: Sun, 11 Oct 2026 00:25:39 +0300 Subject: [PATCH] progress on x11 --- Common/Std/libc.c | 8 +- Common/Std/linux-amd64.c | 9 +- Common/Std/linux-x86.c | 9 +- Common/Std/stub.c | 8 +- Common/std.h | 8 +- Player/Display/x11.c | 297 ++++++++++++++++++++++++++++++++++++++- Player/draw.c | 8 +- 7 files changed, 317 insertions(+), 30 deletions(-) diff --git a/Common/Std/libc.c b/Common/Std/libc.c index a13f86c..f295321 100644 --- a/Common/Std/libc.c +++ b/Common/Std/libc.c @@ -23,7 +23,7 @@ double com_std_fabs(double v) { return fabs(v); } double com_std_sin(double v) { return sin(v); } double com_std_cos(double v) { return cos(v); } -com_std_fd com_std_open(char *path, uint32_t flags) { +com_std_fd com_std_open(char const *path, uint32_t flags) { com_std_assert(flags != 0); char *mode = flags & COM_STD_OPEN_READ && flags & COM_STD_OPEN_WRITE ? "r+" : flags & COM_STD_OPEN_READ ? "r" @@ -31,14 +31,14 @@ com_std_fd com_std_open(char *path, uint32_t flags) { return fopen(path, mode); } -bool com_std_write(com_std_fd fd, char *data, uint32_t bytes) { +bool com_std_write(com_std_fd fd, void const *data, uint32_t bytes) { com_std_assert(fd != NULL && data != NULL && bytes != 0); bool s = fwrite(data, 1, bytes, fd) == bytes; fflush(fd); return s; } -int32_t com_std_read(com_std_fd fd, char *data, uint32_t upto) { +int32_t com_std_read(com_std_fd fd, void *data, uint32_t upto) { com_std_assert(fd != NULL && data != NULL && upto != 0); return fread(data, 1, upto, fd); } @@ -56,7 +56,7 @@ com_std_fd com_std_socket(bool isnetwork) { return NULL; } -bool com_std_connect(com_std_fd fd, bool isnetwork, char *address) { +bool com_std_connect(com_std_fd fd, bool isnetwork, char const *address) { com_std_assert(address != NULL); if (!isnetwork) { struct sockaddr_un addr = {.sun_family = AF_UNIX}; diff --git a/Common/Std/linux-amd64.c b/Common/Std/linux-amd64.c index 60ac7f4..9337a7f 100644 --- a/Common/Std/linux-amd64.c +++ b/Common/Std/linux-amd64.c @@ -10,7 +10,7 @@ #include #include -inline com_std_fd com_std_open(char *path, uint32_t flags) { +inline com_std_fd com_std_open(char const *path, uint32_t flags) { com_std_assert(flags != 0); uint32_t mode = flags & COM_STD_OPEN_READ && flags & COM_STD_OPEN_WRITE ? O_RDWR @@ -26,7 +26,7 @@ inline com_std_fd com_std_open(char *path, uint32_t flags) { return (void *)ret; } -inline bool com_std_write(com_std_fd fd, char const *data, uint32_t bytes) { +inline bool com_std_write(com_std_fd fd, void const *data, uint32_t bytes) { long ret; __asm__ volatile("syscall" : "=a"(ret) @@ -35,7 +35,7 @@ inline bool com_std_write(com_std_fd fd, char const *data, uint32_t bytes) { return ret == bytes; } -inline int32_t com_std_read(com_std_fd fd, char *data, uint32_t upto) { +inline int32_t com_std_read(com_std_fd fd, void *data, uint32_t upto) { long ret; __asm__ volatile("syscall" : "=a"(ret) @@ -67,7 +67,8 @@ inline com_std_fd com_std_socket(bool isnetwork) { return NULL; } -inline bool com_std_connect(com_std_fd fd, bool isnetwork, char *address) { +inline bool com_std_connect(com_std_fd fd, bool isnetwork, + char const *address) { com_std_assert(address != NULL); if (!isnetwork) { struct sockaddr_un addr = {.sun_family = AF_UNIX}; diff --git a/Common/Std/linux-x86.c b/Common/Std/linux-x86.c index e5572ce..0595a8f 100644 --- a/Common/Std/linux-x86.c +++ b/Common/Std/linux-x86.c @@ -10,7 +10,7 @@ #include #include -inline com_std_fd com_std_open(char *path, uint32_t flags) { +inline com_std_fd com_std_open(char const *path, uint32_t flags) { com_std_assert(flags != 0); uint32_t mode = flags & COM_STD_OPEN_READ && flags & COM_STD_OPEN_WRITE ? O_RDWR @@ -26,7 +26,7 @@ inline com_std_fd com_std_open(char *path, uint32_t flags) { return (void *)ret; } -inline bool com_std_write(com_std_fd fd, char const *data, uint32_t bytes) { +inline bool com_std_write(com_std_fd fd, void const *data, uint32_t bytes) { long ret; __asm__ volatile("int $0x80" : "=a"(ret) @@ -35,7 +35,7 @@ inline bool com_std_write(com_std_fd fd, char const *data, uint32_t bytes) { return ret == bytes; } -inline int32_t com_std_read(com_std_fd fd, char *data, uint32_t upto) { +inline int32_t com_std_read(com_std_fd fd, void *data, uint32_t upto) { long ret; __asm__ volatile("int $0x80" : "=a"(ret) @@ -67,7 +67,8 @@ inline com_std_fd com_std_socket(bool isnetwork) { return NULL; } -inline bool com_std_connect(com_std_fd fd, bool isnetwork, char *address) { +inline bool com_std_connect(com_std_fd fd, bool isnetwork, + char const *address) { com_std_assert(address != NULL); if (!isnetwork) { struct sockaddr_un addr = {.sun_family = AF_UNIX}; diff --git a/Common/Std/stub.c b/Common/Std/stub.c index 9020ac7..ba844bf 100644 --- a/Common/Std/stub.c +++ b/Common/Std/stub.c @@ -18,14 +18,14 @@ double com_std_sin(double v) { return 0; } double com_std_cos(double v) { return 0; } #endif -com_std_fd com_std_open(char *path, uint32_t flags) { return NULL; } -bool com_std_write(com_std_fd fd, char const *data, uint32_t bytes) { +com_std_fd com_std_open(char const *path, uint32_t flags) { return NULL; } +bool com_std_write(com_std_fd fd, void const *data, uint32_t bytes) { return false; } -int32_t com_std_read(com_std_fd fd, char *data, uint32_t upto) { return -1; } +int32_t com_std_read(com_std_fd fd, void *data, uint32_t upto) { return -1; } bool com_std_sfwd(com_std_fd fd, uint32_t bytes) { return false; } com_std_fd com_std_socket(bool isnetwork) { return NULL; } -bool com_std_connect(com_std_fd fd, bool isnetwork, char *address) { +bool com_std_connect(com_std_fd fd, bool isnetwork, char const *address) { return false; } void com_std_exit(uint32_t status) { diff --git a/Common/std.h b/Common/std.h index 95da2bf..1979476 100644 --- a/Common/std.h +++ b/Common/std.h @@ -14,12 +14,12 @@ typedef void *com_std_fd; #define COM_STD_OPEN_READ (1 << 0) #define COM_STD_OPEN_WRITE (1 << 1) -com_std_fd com_std_open(char *path, uint32_t flags); -bool com_std_write(com_std_fd fd, char const *data, uint32_t bytes); -int32_t com_std_read(com_std_fd fd, char *data, uint32_t upto); +com_std_fd com_std_open(char const *path, uint32_t flags); +bool com_std_write(com_std_fd fd, void const *data, uint32_t bytes); +int32_t com_std_read(com_std_fd fd, void *data, uint32_t upto); bool com_std_sfwd(com_std_fd fd, uint32_t bytes); com_std_fd com_std_socket(bool isnetwork); -bool com_std_connect(com_std_fd sock, bool isnetwork, char *address); +bool com_std_connect(com_std_fd sock, bool isnetwork, char const *address); void com_std_exit(uint32_t status) __attribute__((noreturn)); void com_std_close(com_std_fd fd); diff --git a/Player/Display/x11.c b/Player/Display/x11.c index b8d992c..3bd332d 100644 --- a/Player/Display/x11.c +++ b/Player/Display/x11.c @@ -8,6 +8,7 @@ #include #include "../../Common/bin.h" +#include "../../Common/bits.h" #include "../../Common/buf.h" #include "../../Common/cfg.h" #include "../../Common/lzw.h" @@ -21,6 +22,30 @@ /* https://gaultier.github.io/blog/write_a_video_game_from_scratch_like_1987.html */ +static struct { + uint32_t id; + uint32_t colormap; + uint32_t white; + uint32_t black; + uint32_t input_mask; + uint16_t width; + uint16_t height; + uint16_t width_mm; + uint16_t height_mm; + uint16_t maps_min; + uint16_t maps_max; + uint32_t root_visual_id; + uint8_t backing_store; + uint8_t save_unders; + uint8_t root_depth; + uint8_t depths_count; +} plr_x11_root_screen; + +static struct { + uint32_t resource_id_base; + uint32_t resource_id_mask; +} plr_x11_connection; + bool quited = false; bool fileread(void *ctx, char *into, uint32_t bytes) { @@ -73,7 +98,8 @@ BREAK: return result; } -static bool plr_x11_handshake(struct plr_x11_auth_entry auth_entry) { +static bool plr_x11_handshake(com_std_fd xfd, + struct plr_x11_auth_entry auth_entry) { struct { uint8_t endianness; uint8_t pad0; @@ -82,15 +108,245 @@ static bool plr_x11_handshake(struct plr_x11_auth_entry auth_entry) { uint16_t auth_len; uint16_t auth_data_len; uint16_t pad1; - } __attribute__((packed)) request = { + } request = { .endianness = 'l', .major_version = 11, .auth_len = sizeof(AUTH_ENTRY_MAGIC_COOKIE) - 1, // IS -1 NEEDED? .auth_data_len = auth_entry.auth_data->len, }; + + if (!com_std_write(xfd, &request, sizeof request)) + return false; + if (!com_std_write(xfd, AUTH_ENTRY_MAGIC_COOKIE, + sizeof AUTH_ENTRY_MAGIC_COOKIE - 1)) + return false; + /* Use 2 bytes back for padding. */ + if (!com_std_write(xfd, &auth_entry.auth_data->data[-2], + auth_entry.auth_data->len + 2)) + return false; + + struct { + uint8_t success; + uint8_t pad1; + uint16_t major_version; + uint16_t minor_version; + uint16_t length; + } response; + + if (!com_std_read(xfd, &response, sizeof response)) + return false; + if (response.success != 1) + return false; + + struct { + uint32_t release_number; + uint32_t resource_id_base; + uint32_t resource_id_mask; + uint32_t motion_buffer_size; + uint16_t vendor_length; + uint16_t maximum_request_length; + uint8_t screens_in_root_count; + uint8_t formats_count; + uint8_t image_byte_order; + uint8_t bitmap_format_bit_order; + uint8_t bitmap_format_scanline_unit; + uint8_t bitmap_format_scanline_pad; + uint8_t min_keycode; + uint8_t max_keycode; + uint32_t pad2; + } dyn_response; + + if (!com_std_read(xfd, &dyn_response, sizeof dyn_response)) + return false; + + /* Skip vendor and format info. */ + char scratch[1024]; + uint32_t skip = com_bits_nalign(dyn_response.vendor_length, 4); + com_std_assert(skip <= sizeof scratch); + com_std_assert(8 * dyn_response.formats_count <= sizeof scratch); + if (!com_std_read(xfd, scratch, skip)) + return false; + if (!com_std_read(xfd, scratch, 8 * dyn_response.formats_count)) + return false; + if (!com_std_read(xfd, &plr_x11_root_screen, sizeof plr_x11_root_screen)) + return false; + + plr_x11_connection.resource_id_base = dyn_response.resource_id_base; + plr_x11_connection.resource_id_mask = dyn_response.resource_id_mask; + return true; } +static inline uint32_t plr_x11_next_id(void) { + static uint32_t cur_id = 0; + cur_id = 1 + ((plr_x11_connection.resource_id_mask & (cur_id)) | + plr_x11_connection.resource_id_base); + return cur_id; +} + +static uint32_t plr_x11_create_graphical_context(com_std_fd xfd) { + uint32_t const gc_id = plr_x11_next_id(); + struct { + uint8_t opcode; + uint8_t pad1; + uint16_t length; + uint32_t id; + uint32_t drawable; + uint32_t bitmask; + uint32_t value1; + } request = { + .opcode = 55, + .length = 5, + .id = gc_id, + .drawable = plr_x11_root_screen.id, + .bitmask = 8, /* TODO: Figure out. */ + .value1 = 0x0000ff00, + }; + + if (com_std_write(xfd, &request, sizeof request)) + return gc_id; + else + return 0; +} + +static uint32_t plr_x11_create_window(com_std_fd xfd) { +/* TODO: Use the ones provided in headers ? */ +#define FLAG_WIN_BG_PIXEL 2 +#define FLAG_WIN_EVENT 0x800 +#define EVENT_FLAG_EXPOSURE 0x8000 +#define EVENT_FLAG_KEY_PRESS 0x1 +#define EVENT_FLAG_KEY_RELEASE 0x2 +#define EVENT_FLAG_BUTTON_PRESS 0x4 +#define EVENT_FLAG_BUTTON_RELEASE 0x8 + + uint32_t const window_id = plr_x11_next_id(); + struct { + uint8_t opcode; + uint8_t depth; + uint16_t request_length; + uint32_t window_id; + uint32_t parent_id; + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + uint16_t border_width; + uint16_t class; + uint32_t root_visual_id; + uint32_t bitmask; + uint32_t value1; + uint32_t value2; + } request = { + .opcode = 1, + .depth = 32, + .request_length = 8 + 2, + .window_id = window_id, + .parent_id = plr_x11_root_screen.id, + .width = COM_CFG_WIDTH, + .height = COM_CFG_HEIGHT, + .border_width = 0, + .class = 1, + .root_visual_id = plr_x11_root_screen.root_visual_id, + .bitmask = FLAG_WIN_BG_PIXEL | FLAG_WIN_EVENT, + .value1 = 0x00ffff00, + .value2 = EVENT_FLAG_EXPOSURE | EVENT_FLAG_BUTTON_RELEASE | + EVENT_FLAG_BUTTON_PRESS | EVENT_FLAG_KEY_PRESS | + EVENT_FLAG_KEY_RELEASE, + }; + + if (com_std_write(xfd, &request, sizeof request)) + return window_id; + else + return 0; +} + +static bool plr_x11_show_window(com_std_fd xfd, uint32_t window_id) { + struct { + uint8_t opcode; + uint8_t pad1; + uint16_t request_length; + uint32_t window_id; + } request = { + .opcode = 8, + .request_length = 2, + .window_id = window_id, + }; + return com_std_write(xfd, &request, sizeof request); +} + +static uint32_t plr_x11_create_pixmap(com_std_fd xfd, uint32_t window_id) { + uint32_t const pixmap_id = plr_x11_next_id(); + struct { + uint8_t opcode; + uint8_t depth; + uint16_t length; + uint32_t pixmap_id; + uint32_t drawable; + uint16_t width; + uint16_t height; + } request = { + .opcode = 53, + .depth = 32, + .length = 4, + .pixmap_id = pixmap_id, + .drawable = window_id, + .width = COM_CFG_WIDTH, + .height = COM_CFG_HEIGHT, + }; + + if (com_std_write(xfd, &request, sizeof request)) + return pixmap_id; + else + return 0; +} + +static bool +plr_x11_put_framebuffer(com_std_fd xfd, uint32_t gc_id, uint32_t window_id, + uint32_t pixmap_id, + uint32_t pixels[COM_CFG_WIDTH * COM_CFG_HEIGHT]) { + uint32_t const padded = + com_bits_nalign(4 * COM_CFG_WIDTH * COM_CFG_HEIGHT, 4); + + struct { + uint8_t opcode; + uint8_t format; + uint16_t request_length; + uint32_t drawable_id; + uint32_t gc_id; + uint16_t width; + uint16_t height; + uint16_t dst_x; + uint16_t dst_y; + uint8_t left_pad; + uint8_t depth; + uint16_t pad1; + } request = { + .opcode = 72, + .format = 2, // ZPixmap + .request_length = 6 + padded / 4, + .drawable_id = pixmap_id, + .gc_id = gc_id, + .width = COM_CFG_WIDTH, + .height = COM_CFG_HEIGHT, + .dst_x = 0, + .dst_y = 0, + .depth = 32, + }; + + if (!com_std_write(xfd, &request, sizeof request)) + return false; + if (!com_std_write(xfd, pixels, 4 * COM_CFG_WIDTH * COM_CFG_HEIGHT)) + return false; + /* Use request memory for pad, it doesn't matter what we write. */ + uint32_t const padfinal = padded - (4 * COM_CFG_WIDTH * COM_CFG_HEIGHT); + if (padfinal && !com_std_write(xfd, &request, padfinal)) + return false; + + return true; +} + +static uint32_t pixel_buffer[COM_CFG_WIDTH * COM_CFG_HEIGHT]; + // TODO: correct error handling. extern int plr_display_x11_main(int argc, char *argv[]) { char test_string[] = "what is this?"; @@ -135,7 +391,7 @@ extern int plr_display_x11_main(int argc, char *argv[]) { /* First we need to authenticate X11 connection, which requires some funk. */ /* We assume that $XAUTHORITY is set and I hope it is true. */ - char *xauthpath = NULL; + char const *xauthpath = NULL; for (char **envp = &argv[argc + 1]; *envp != NULL; ++envp) { static const struct com_str xauthlit = com_str_lit("XAUTHORITY="); if (com_str_ext_prefixed(*envp, xauthlit)) { @@ -171,12 +427,30 @@ extern int plr_display_x11_main(int argc, char *argv[]) { com_std_close(xauthfd); /* TODO: Check for auth_entry.name == MAGIC ? */ - plr_x11_handshake(auth_entry); + if (!plr_x11_handshake(xfd, auth_entry)) { + com_std_printf("Failure to initialize X11\n"); + return -1; + } com_buf_free(xauthbuf); - char sendbuf[16 * 1024] = {}; - char readbuf[16 * 1024] = {}; + uint32_t const gc = plr_x11_create_graphical_context(xfd); + if (!gc) { + com_std_printf("Failure to initialize X11\n"); + return -1; + } + + uint32_t const win = plr_x11_create_window(xfd); + if (!win) { + com_std_printf("Failure to initialize X11\n"); + return -1; + } + + uint32_t const fb = plr_x11_create_pixmap(xfd, win); + if (!fb) { + com_std_printf("Failure to initialize X11\n"); + return -1; + } // Display *display = XOpenDisplay(NULL); // if (NULL == display) { @@ -274,6 +548,17 @@ extern int plr_display_x11_main(int argc, char *argv[]) { // XCloseDisplay(display); while (1) { + plr_draw_screen((uint8_t *)pixel_buffer); + + if (!plr_x11_put_framebuffer(xfd, gc, win, fb, pixel_buffer)) { + com_std_printf("Failure to drive X11\n"); + return -1; + } + + if (!plr_x11_show_window(xfd, win)) { + com_std_printf("Failure to drive X11\n"); + return -1; + } } return 0; diff --git a/Player/draw.c b/Player/draw.c index 9458854..0ff81bf 100644 --- a/Player/draw.c +++ b/Player/draw.c @@ -60,10 +60,10 @@ com_def_export_sym("plr_draw_screen") void plr_draw_screen( uint8_t cc2 = com_gem_clip_vis_project(c2, &p2); uint8_t cc3 = com_gem_clip_vis_project(c3, &p3); - com_std_printf("%i, %i\n", p0.a[0], p0.a[1]); - com_std_printf("%i, %i\n", p1.a[0], p1.a[1]); - com_std_printf("%i, %i\n", p2.a[0], p2.a[1]); - com_std_printf("%i, %i\n", p3.a[0], p3.a[1]); + // com_std_printf("%i, %i\n", p0.a[0], p0.a[1]); + // com_std_printf("%i, %i\n", p1.a[0], p1.a[1]); + // com_std_printf("%i, %i\n", p2.a[0], p2.a[1]); + // com_std_printf("%i, %i\n", p3.a[0], p3.a[1]); uint8_t tex[32 * 32 * 3] = {0}; for (int y = 0; y < 32; ++y) {