From be691582ee12613278af24cb5a824eeb357f6324 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Mon, 29 Jul 2024 11:27:22 -0400 Subject: some work on compositor --- applications/goldman/makefile | 2 +- applications/goldman/source/input.cpp | 21 ++++ applications/goldman/source/input.hpp | 3 + applications/goldman/source/main.cpp | 84 ++++------------ applications/goldman/source/main.hpp | 5 + applications/goldman/source/renderer.cpp | 102 +++++++++++++++++++ applications/goldman/source/renderer.hpp | 61 ++++++++++++ applications/goldman/source/socket.cpp | 162 +++++++++++++++++++++++++++++++ applications/goldman/source/socket.hpp | 5 + applications/goldman/source/window.hpp | 14 +++ applications/hello/makefile | 12 +++ applications/hello/source/main.cpp | 37 +++++++ 12 files changed, 444 insertions(+), 64 deletions(-) create mode 100644 applications/goldman/source/input.cpp create mode 100644 applications/goldman/source/input.hpp create mode 100644 applications/goldman/source/main.hpp create mode 100644 applications/goldman/source/renderer.cpp create mode 100644 applications/goldman/source/renderer.hpp create mode 100644 applications/goldman/source/socket.cpp create mode 100644 applications/goldman/source/socket.hpp create mode 100644 applications/goldman/source/window.hpp create mode 100644 applications/hello/makefile create mode 100644 applications/hello/source/main.cpp (limited to 'applications') diff --git a/applications/goldman/makefile b/applications/goldman/makefile index 56f633d..c6de0e7 100644 --- a/applications/goldman/makefile +++ b/applications/goldman/makefile @@ -1,5 +1,5 @@ SOURCES = \ - main.cpp + main.cpp renderer.cpp input.cpp socket.cpp build/%.cpp.o: source/%.cpp @mkdir -p $(@D) diff --git a/applications/goldman/source/input.cpp b/applications/goldman/source/input.cpp new file mode 100644 index 0000000..0cd6922 --- /dev/null +++ b/applications/goldman/source/input.cpp @@ -0,0 +1,21 @@ +#include "input.hpp" +#include "main.hpp" + +[[noreturn]] void input_thread_main() { + + euler::syscall::set_thread_name("input thread"); + + while (true) { + + auto result = euler::syscall::get_input_packet(); + if (std::holds_alternative(result)) { + auto packet = std::get(result); + r->lock(); + r->bump_cursor(packet.x_changed, packet.y_changed); + r->unlock(); + r->dispatch_render(); + } + + } + +} diff --git a/applications/goldman/source/input.hpp b/applications/goldman/source/input.hpp new file mode 100644 index 0000000..108cdad --- /dev/null +++ b/applications/goldman/source/input.hpp @@ -0,0 +1,3 @@ +#pragma once + +[[noreturn]] void input_thread_main(); diff --git a/applications/goldman/source/main.cpp b/applications/goldman/source/main.cpp index d74eaad..475129f 100644 --- a/applications/goldman/source/main.cpp +++ b/applications/goldman/source/main.cpp @@ -1,79 +1,37 @@ #include #include +#include "renderer.hpp" +#include "socket.hpp" +#include "input.hpp" +#include "main.hpp" -daguerre::hilbert_color trans_color; +//TODO: handle errors -void convert_pointer( - daguerre::hilbert_color &dest, const daguerre::hilbert_color &src) { - if (src != trans_color) - dest = src; -} +renderer *r; int main(int, char **) { - trans_color = euler::syscall::encode_color(0xff, 0x00, 0xff); - - daguerre::image framebuffer = - daguerre::get_hilbert_framebuffer(); - - int fw = framebuffer.width; - int fh = framebuffer.height; - - daguerre::image double_buffer(fw, fh); + euler::syscall::listener_handle listener; + euler::syscall::create_socket_listener("hilbert.compositor", listener); - std::optional> - background_original = daguerre::try_load_ppm("/assets/background.ppm"); - - daguerre::image background; - - if (background_original.has_value()) - background = background_original->stretch(fw, fh); - else { - background = daguerre::image(fw, fh); - background.fill(euler::syscall::encode_color(0, 0, 0)); - } + r = new renderer( + daguerre::get_hilbert_framebuffer(), + *daguerre::try_load_ppm("/assets/background.ppm"), + euler::syscall::encode_color(0x00, 0x00, 0x00), + *daguerre::try_load_ppm("/assets/pointer.ppm"), + euler::syscall::encode_color(0xff, 0x00, 0xff)); - std::optional> - pointer_original = daguerre::try_load_ppm("/assets/pointer.ppm"); + euler::syscall::start_thread([]() { r->render_thread_main(); }); + euler::syscall::start_thread(input_thread_main); - if (!pointer_original.has_value()) - //TODO - while (1) - ; + r->dispatch_render(); - daguerre::image - pointer = std::move(*pointer_original); - - int mouse_x = fw / 2; - int mouse_y = fh / 2; + euler::syscall::set_thread_name("socket listener thread"); while (true) { - - double_buffer.copy_from(background, 0, 0); - double_buffer.convert_from(pointer, mouse_x, mouse_y, 0, 0, - std::min(pointer. width, double_buffer. width - mouse_x), - std::min(pointer.height, double_buffer.height - mouse_y), - &convert_pointer); - - framebuffer.copy_from(double_buffer, 0, 0); - - auto result = euler::syscall::get_input_packet(); - if (std::holds_alternative(result)) { - const auto &packet = std::get(result); - mouse_x += packet.x_changed; - mouse_y += packet.y_changed; - if (mouse_x < 0) - mouse_x = 0; - else if (mouse_x >= fw) - mouse_x = fw - 1; - if (mouse_y < 0) - mouse_y = 0; - else if (mouse_y >= fh) - mouse_y = fh - 1; - } - + euler::syscall::stream_handle socket; + euler::syscall::accept_socket_connection(listener, socket); + euler::syscall::start_thread(socket_thread_main, socket); } - return 0; - } diff --git a/applications/goldman/source/main.hpp b/applications/goldman/source/main.hpp new file mode 100644 index 0000000..57de676 --- /dev/null +++ b/applications/goldman/source/main.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include "renderer.hpp" + +extern renderer *r; diff --git a/applications/goldman/source/renderer.cpp b/applications/goldman/source/renderer.cpp new file mode 100644 index 0000000..629c375 --- /dev/null +++ b/applications/goldman/source/renderer.cpp @@ -0,0 +1,102 @@ +#include "renderer.hpp" + +renderer::renderer( + daguerre::image &&fb, + daguerre::image &&bg, + daguerre::hilbert_color bgc, + daguerre::image &&c, + daguerre::hilbert_color cbg) + +: framebuffer(std::move(fb)), + double_buffer(framebuffer.width, framebuffer.height), + background(std::move(bg)), cursor(std::move(c)), cursor_background(cbg), + cursor_x(framebuffer.width / 2), cursor_y(framebuffer.height / 2) { + + euler::syscall::create_private_socket(dispatcher_handle_1, dispatcher_handle_2); + + if (background.width != framebuffer.width || + background.height != framebuffer.height) { + + daguerre::image + new_background(framebuffer.width, framebuffer.height); + + new_background.fill(bgc); + + int from_x = 0; + int from_y = 0; + int to_x = framebuffer.width / 2 - background.width / 2; + int to_y = framebuffer.height / 2 - background.height / 2; + int width = background.width; + int height = background.height; + + daguerre::make_safe(to_x, from_x, width, 0, framebuffer.width); + daguerre::make_safe(to_y, from_y, height, 0, framebuffer.height); + + new_background.copy_from(background, to_x, to_y, from_x, from_y, width, height); + background = std::move(new_background); + + } + +} + +template +void overlay_trans(color_t &to, const color_t &from, const color_t ¶m) { + if (from != param) + to = from; +} + +void renderer::do_render() { + + double_buffer.copy_from(background, 0, 0); + + for (auto it = windows.begin(); it != windows.end(); ++it) + + double_buffer.copy_from( + (*it)->contents, (*it)->x, (*it)->y, 0, 0, + std::min((*it)->contents.width, double_buffer.width - (*it)->x), + std::min((*it)->contents.height, double_buffer.height - (*it)->y)); + + double_buffer.convert_from( + cursor_background, cursor, cursor_x, cursor_y, 0, 0, + std::min(cursor.width, framebuffer.width - cursor_x), + std::min(cursor.height, framebuffer.height - cursor_y), + &overlay_trans); + +} + +[[noreturn]] void renderer::render_thread_main() { + euler::syscall::set_thread_name("render thread"); + while (true) { + uint8_t byte; + euler::syscall::read_from_stream(dispatcher_handle_2, 1, &byte); + mut.lock(); + euler::syscall::clear_socket_read_queue(dispatcher_handle_2); + do_render(); + mut.unlock(); + framebuffer.copy_from(double_buffer, 0, 0); + } +} + +void renderer::bump_cursor(int x_offset, int y_offset) { + + cursor_x += x_offset; + if (cursor_x < 0) + cursor_x = 0; + else if (cursor_x >= framebuffer.width) + cursor_x = framebuffer.width - 1; + + cursor_y += y_offset; + if (cursor_y < 0) + cursor_y = 0; + else if (cursor_y >= framebuffer.height) + cursor_y = framebuffer.height - 1; + +} + +void renderer::add_window(const window *w) { + windows.push_back(w); +} + +void renderer::remove_window(const window *w) { + windows.remove(w); +} diff --git a/applications/goldman/source/renderer.hpp b/applications/goldman/source/renderer.hpp new file mode 100644 index 0000000..14a5964 --- /dev/null +++ b/applications/goldman/source/renderer.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include "window.hpp" +#include +#include + +class renderer { + + daguerre::image framebuffer; + daguerre::image double_buffer; + + daguerre::image background; + daguerre::image cursor; + daguerre::hilbert_color cursor_background; + + int cursor_x; + int cursor_y; + + //bottom to top + std::list windows; + + std::mutex mut; + + euler::syscall::stream_handle + dispatcher_handle_1, dispatcher_handle_2; + + void do_render(); + +public: + renderer( + daguerre::image &&framebuffer, + daguerre::image &&background, + daguerre::hilbert_color background_color, + daguerre::image &&cursor, + daguerre::hilbert_color cursor_background); + + inline ~renderer() { + euler::syscall::close_stream(dispatcher_handle_1); + euler::syscall::close_stream(dispatcher_handle_2); + } + + renderer(const renderer &) = delete; + renderer &operator =(const renderer &) = delete; + + [[noreturn]] void render_thread_main(); + + inline void lock() { mut.lock(); } + inline void unlock() { mut.unlock(); } + + inline void dispatch_render() { + uint8_t byte = 0; + euler::syscall::write_to_stream(dispatcher_handle_1, 1, &byte); + } + + void bump_cursor(int x_offset, int y_offset); + + void add_window(const window *w); + void remove_window(const window *w); + +}; diff --git a/applications/goldman/source/socket.cpp b/applications/goldman/source/socket.cpp new file mode 100644 index 0000000..b175fe9 --- /dev/null +++ b/applications/goldman/source/socket.cpp @@ -0,0 +1,162 @@ +#include +#include "socket.hpp" +#include "window.hpp" +#include "main.hpp" +#include +#include + +struct socket_state { + + euler::syscall::stream_handle socket; + std::vector windows; + daguerre::hilbert_color window_bg = euler::syscall::encode_color(0, 0, 0); + + bool try_open_window() { + + struct [[gnu::packed]] { + uint32_t width; + uint32_t height; + } body; + + if (euler::syscall::read_from_stream(socket, sizeof(body), &body) != + euler::syscall::stream_result::success) + return false; + + window *w = new window(body.width, body.height); + w->contents.fill(window_bg); + + uint16_t wid = 0; + + while (wid < windows.size()) + if (windows[wid] != 0) + ++wid; + else + break; + + if (wid == windows.size()) + windows.push_back(w); + else + windows[wid] = w; + + r->lock(); + r->add_window(w); + r->unlock(); + + struct [[gnu::packed]] { + uint8_t type; + uint16_t the_window; + } response { + .type = 0x00, + .the_window = wid + }; + + return + euler::syscall::write_to_stream(socket, sizeof(response), &response) == + euler::syscall::stream_result::success; + + } + + bool try_update_window_region() { + + struct [[gnu::packed]] { + uint16_t window; + uint32_t start_x; + uint32_t start_y; + uint32_t width; + uint32_t height; + } body_head; + + if (euler::syscall::read_from_stream(socket, sizeof(body_head), &body_head) != + euler::syscall::stream_result::success) + return false; + + std::vector data(body_head.width * body_head.height); + + if (euler::syscall::read_from_stream(socket, data.size() * 4, data.data()) != + euler::syscall::stream_result::success) + return false; + + daguerre::image + data_as_image(body_head.width, body_head.height, data.data(), body_head.width, false); + + if (body_head.window >= windows.size() || !windows[body_head.window]) + return false; + + window *w = windows[body_head.window]; + + r->lock(); + + if ((int)body_head.start_x + data_as_image.width > w->contents.width || + (int)body_head.start_y + data_as_image.height > w->contents.height) { + r->unlock(); + return false; + } + + w->contents.copy_from(data_as_image, body_head.start_x, body_head.start_y); + + r->unlock(); + r->dispatch_render(); + return true; + + } + + bool try_close_window() { + + uint16_t wid; + + if (euler::syscall::read_from_stream(socket, 2, &wid) != + euler::syscall::stream_result::success) + return false; + + if (wid >= windows.size() || !windows[wid]) + return false; + + r->lock(); + + r->remove_window(windows[wid]); + windows[wid] = 0; + + r->unlock(); + r->dispatch_render(); + return true; + + } + + bool try_process_request() { + + uint8_t type; + if (euler::syscall::read_from_stream(socket, 1, &type) != + euler::syscall::stream_result::success) + return false; + + switch (type) { + case 0x00: return try_open_window(); + case 0x01: return try_update_window_region(); + case 0x02: return try_close_window(); + default: return false; + } + + } + +}; + +[[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket) { + + euler::syscall::set_thread_name("socket thread"); + + socket_state *state = new socket_state { + .socket = socket, .windows = {} }; + while (state->try_process_request()) ; + + r->lock(); + for (unsigned i = 0; i < state->windows.size(); ++i) { + r->remove_window(state->windows[i]); + delete state->windows[i]; + } + r->unlock(); + + delete state; + euler::syscall::close_stream(socket); + euler::syscall::end_this_thread(0); + +} diff --git a/applications/goldman/source/socket.hpp b/applications/goldman/source/socket.hpp new file mode 100644 index 0000000..a9dbeb2 --- /dev/null +++ b/applications/goldman/source/socket.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +[[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket); diff --git a/applications/goldman/source/window.hpp b/applications/goldman/source/window.hpp new file mode 100644 index 0000000..008af2f --- /dev/null +++ b/applications/goldman/source/window.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +struct window { + + daguerre::image contents; + + int x; + int y; + + window(int width, int height) : contents(width, height), x(0), y(0) {} + +}; diff --git a/applications/hello/makefile b/applications/hello/makefile new file mode 100644 index 0000000..5e12644 --- /dev/null +++ b/applications/hello/makefile @@ -0,0 +1,12 @@ +SOURCES = \ + main.cpp + +build/%.cpp.o: source/%.cpp + @mkdir -p $(@D) + $(HILBERT_CC) -c $^ -o $@ + +build/hello.elf: $(SOURCES:%=build/%.o) + $(HILBERT_CC) $^ -ldaguerre -o $@ + +clean: + rm -rf build diff --git a/applications/hello/source/main.cpp b/applications/hello/source/main.cpp new file mode 100644 index 0000000..3f132c6 --- /dev/null +++ b/applications/hello/source/main.cpp @@ -0,0 +1,37 @@ +#include +#include + +template +void overlay(color_t &to, const bool &from, const color_t ¶m) { + if (from) + to = param; +} + +int main(int, char **) { + + auto bg = euler::syscall::encode_color(0xaa, 0xaa, 0xaa); + auto fg = euler::syscall::encode_color(0x00, 0x00, 0x00); + + daguerre::image image(300, 200); + image.fill(bg); + + auto font = daguerre::try_load_psf("/assets/terminus-bold-18x10.psf"); + image.render_text(*font, fg, 10, 10, "Hello, world!", &overlay); + + euler::syscall::stream_handle s; + euler::syscall::connect_to_socket("hilbert.compositor", s); + + goldman::protocol::send_open_window(s, 300, 200); + + uint8_t byte; + euler::syscall::read_from_stream(s, 1, &byte); + + auto w = goldman::protocol::get_window_opened_body(s); + + goldman::protocol::send_update_window_region( + s, w, 0, 0, 300, 200, image.buffer, image.buffer_pitch); + + euler::syscall::read_from_stream(s, 1, &byte); + __builtin_unreachable(); + +} -- cgit v1.2.3