Skip to content

Commit

Permalink
Implement slides userspace program
Browse files Browse the repository at this point in the history
  • Loading branch information
hgruniaux committed May 22, 2024
1 parent f21ec75 commit e3c1597
Show file tree
Hide file tree
Showing 17 changed files with 8,767 additions and 17 deletions.
5 changes: 1 addition & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,11 @@ add_compile_definitions(-DCONFIG_USE_NAIVE_WM_UPDATE)
# Use a naive malloc/free implementation that just allocate memory using the heap break
# and never free memory. This is a really bad allocator (as it never free memory), but
# it is guaranteed to work.
add_compile_definitions(-DCONFIG_USE_NAIVE_MALLOC)
# add_compile_definitions(-DCONFIG_USE_NAIVE_MALLOC)

# Enable the use of double buffering for the screen framebuffer (using mailbox set virtual offset).
# add_compile_definitions(-DCONFIG_USE_DOUBLE_BUFFERING)

# Include the wallpaper data and display it as the background in the window manager.
# add_compile_definitions(-DCONFIG_INCLUDE_WALLPAPER)

# Enable checks
option(ENABLE_CHECKS "Enable checks using clang-tidy" OFF)
if (${ENABLE_CHECKS})
Expand Down
Binary file added fs/slides/0.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions kernel/fs/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ bool File::write(const void* buffer, size_t bytes_to_write, size_t* wrote_bytes)
*wrote_bytes = wrote_bytes_bis;
return result == FR_OK;
#else
(void)buffer;
(void)bytes_to_write;
(void)wrote_bytes;
return false;
#endif
}
Expand Down
9 changes: 9 additions & 0 deletions kernel/graphics/graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,15 @@ uint32_t Painter::draw_text(int32_t x, int32_t y, int32_t w, const char* text, C
}
}

void Painter::blit(uint32_t x, uint32_t y, uint32_t width, uint32_t height, const uint32_t* argb_buffer) {
// TODO: Clipping
for (uint32_t i = 0; i < width; ++i) {
for (uint32_t j = 0; j < height; ++j) {
m_buffer[(x + i) + m_pitch * (y + j)] = argb_buffer[i + width * j];
}
}
}

void Painter::revert_clipping() {
m_clipping.x_min = 0;
m_clipping.y_min = 0;
Expand Down
3 changes: 3 additions & 0 deletions kernel/graphics/graphics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ class Painter {
uint32_t draw_text(int32_t x, int32_t y, int32_t w, const char* text);
uint32_t draw_text(int32_t x, int32_t y, int32_t w, const char* text, Color color);

// Image blit.
void blit(uint32_t x, uint32_t y, uint32_t width, uint32_t height, const uint32_t* argb_buffer);

// Clipping functions:
void revert_clipping();
void set_clipping(int32_t x_min, int32_t y_min, int32_t x_max, int32_t y_max);
Expand Down
19 changes: 19 additions & 0 deletions kernel/task/pika_syscalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,24 @@ static void pika_sys_gfx_draw_text(Registers& regs) {
set_error(regs, SYS_ERR_OK);
}

static void pika_sys_gfx_blit(Registers& regs) {
auto* window = (Window*)regs.gp_regs.x0;
if (!check_window(regs, window))
return;

uint32_t x, y;
uint32_t width, height;
unpack_couple(regs.gp_regs.x1, x, y);
unpack_couple(regs.gp_regs.x2, width, height);

const uint32_t* argb_buffer = (const uint32_t*)regs.gp_regs.x3;
if (!check_ptr(regs, (void*)argb_buffer))
return;

window->blit(x, y, width, height, argb_buffer);
set_error(regs, SYS_ERR_OK);
}

SyscallTable* create_pika_syscalls() {
SyscallTable* table = new SyscallTable;
KASSERT(table != nullptr);
Expand Down Expand Up @@ -474,6 +492,7 @@ SyscallTable* create_pika_syscalls() {
table->register_syscall(SYS_GFX_DRAW_RECT, pika_sys_gfx_draw_rect);
table->register_syscall(SYS_GFX_FILL_RECT, pika_sys_gfx_fill_rect);
table->register_syscall(SYS_GFX_DRAW_TEXT, pika_sys_gfx_draw_text);
table->register_syscall(SYS_GFX_BLIT, pika_sys_gfx_blit);

return table;
}
4 changes: 4 additions & 0 deletions kernel/wm/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ void Window::draw_text(uint32_t x, uint32_t y, const char* text, uint32_t argb)
m_painter.draw_text(x, y, text, argb);
}

void Window::blit(uint32_t x, uint32_t y, uint32_t width, uint32_t height, const uint32_t* argb_buffer) {
m_painter.blit(x, y, width, height, argb_buffer);
}

void Window::draw_frame() {
if (!m_has_frame)
return;
Expand Down
1 change: 1 addition & 0 deletions kernel/wm/window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Window {
void draw_rect(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t argb);
void fill_rect(uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t argb);
void draw_text(uint32_t x, uint32_t y, const char* text, uint32_t argb);
void blit(uint32_t x, uint32_t y, uint32_t width, uint32_t height, const uint32_t* argb_buffer);
// Draw the window frame decoration (title bar + borders).
void draw_frame();

Expand Down
22 changes: 15 additions & 7 deletions kernel/wm/window_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,21 @@ bool WindowManager::post_message(Window* window, sys_message_t message) {
void WindowManager::present_window(Window* window) {
KASSERT(is_valid(window));

(void)window;

// Let do a full update the next time.
// A partial update is more challenging as we should only draw the pixels that are visible on the screen.
// This is straightforward if the window is a top level window (e.g. has focus),
// but it becomes tricky if the window is behind other windows.
m_dirty = true; // mark the screen as dirty and needs an update
if (!m_dirty && window->has_focus()) {
// If no update is required for now and the window is at front (has focus), then
// only redraw the window.
DMARequestQueue dma_request_queue;
draw_window(window, {0, 0, m_screen_width, m_screen_height}, dma_request_queue);
#ifdef CONFIG_USE_DMA
dma_request_queue.execute_and_wait(m_dma_channel);
#endif // CONFIG_USE_DMA
} else {
// Let do a full update the next time.
// A partial update is more challenging as we should only draw the pixels that are visible on the screen.
// This is straightforward if the window is a top level window (e.g. has focus),
// but it becomes tricky if the window is behind other windows.
m_dirty = true; // mark the screen as dirty and needs an update
}
}

void WindowManager::mosaic_layout() {
Expand Down
1 change: 1 addition & 0 deletions lib/libsyscall/include/sys/syscall_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum {
SYS_GFX_DRAW_RECT,
SYS_GFX_FILL_RECT,
SYS_GFX_DRAW_TEXT,
SYS_GFX_BLIT
};

#endif // !__PIKAOS_LIBC_SYS_SYSCALL_TABLE_H__
6 changes: 6 additions & 0 deletions lib/libsyscall/include/sys/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ sys_error_t sys_gfx_fill_rect(sys_window_t* window,
uint32_t height,
uint32_t argb);
sys_error_t sys_gfx_draw_text(sys_window_t* window, uint32_t x, uint32_t y, const char* text, uint32_t argb);
sys_error_t sys_gfx_blit(sys_window_t* window,
uint32_t x,
uint32_t y,
uint32_t width,
uint32_t height,
const uint32_t* argb_buffer);

__SYS_EXTERN_C_END

Expand Down
13 changes: 13 additions & 0 deletions lib/libsyscall/src/sys/window.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,16 @@ sys_error_t sys_gfx_draw_text(sys_window_t* window, uint32_t x, uint32_t y, cons
const uint64_t param1 = (uint64_t)x | ((uint64_t)y << 32);
return __syscall4(SYS_GFX_DRAW_TEXT, window->kernel_handle, param1, (sys_word_t)text, argb);
}

sys_error_t sys_gfx_blit(sys_window_t* window,
uint32_t x,
uint32_t y,
uint32_t width,
uint32_t height,
const uint32_t* argb_buffer) {
assert(window != NULL);

const uint64_t param1 = (uint64_t)x | ((uint64_t)y << 32);
const uint64_t param2 = (uint64_t)width | ((uint64_t)height << 32);
return __syscall4(SYS_GFX_BLIT, window->kernel_handle, param1, param2, (sys_word_t)argb_buffer);
}
2 changes: 1 addition & 1 deletion usr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ endfunction()

add_userspace_executable(init init.c)
add_userspace_executable(credits credits.c)
add_userspace_executable(slides slides.c)
add_userspace_executable(slides slides.c stb_image.c)
2 changes: 1 addition & 1 deletion usr/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ int main() {
sys_print("Failed to spawn " program); \
} while (0)

LAUNCH("/usr/bin/credits");
// LAUNCH("/usr/bin/credits");
LAUNCH("/usr/bin/slides");

while (true)
Expand Down
166 changes: 162 additions & 4 deletions usr/slides.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/keyboard.h>
#include <sys/syscall.h>
#include <sys/window.h>

static void draw_slide(sys_window_t* window) {}
#include "stb_image.h"

static sys_window_t* window = NULL;
static int current_slide = 0;

static const uint32_t* slide_pixels = NULL;
static int slide_width = 0, slide_height = 0;

static void draw_slide() {
uint32_t win_width, win_height;
sys_window_get_geometry(window, NULL, NULL, &win_width, &win_height);

// The title bar is 30 pixels large.
#define TITLE_BAR_HEIGHT 30

win_height -= TITLE_BAR_HEIGHT;

uint32_t x = 0, y = TITLE_BAR_HEIGHT;
if ((uint32_t)slide_width < win_width)
x += win_width / 2 - slide_width / 2;
if ((uint32_t)slide_height < win_height)
y += win_height / 2 - slide_height / 2;

sys_gfx_blit(window, x, y, slide_width, slide_height, slide_pixels);
sys_window_present(window);
}

#if 0
static void cat_file(const char* path) {
sys_file_t* file = sys_open_file(path, SYS_FM_READ);
if (file == NULL) {
Expand All @@ -25,19 +53,143 @@ static void cat_file(const char* path) {

sys_close_file(file);
}
#endif

#define SLIDE_PATH_PREFIX "/slides/"
#define SLIDE_PATH_PREFIX_LEN 8

char* itoa(char* buffer, int res) {
int size = 0;
int t = res;

while (t / 10 != 0) {
t = t / 10;
size++;
}

size++;
t = res;
int i = size - 1;
while (i >= 0) {
buffer[i] = (t % 10) + '0';
t = t / 10;
i--;
}

return buffer + size;
}

static const char* get_slide_path(int idx) {
static char buffer[512];

char* it = buffer;
memcpy(it, SLIDE_PATH_PREFIX, SLIDE_PATH_PREFIX_LEN);
it = itoa(it + SLIDE_PATH_PREFIX_LEN, idx);
memcpy(it, ".jpg\0", 5);

return buffer;
}

static uint8_t* load_slide_image(int idx, int* buffer_length) {
const char* path = get_slide_path(idx);
sys_file_t* file = sys_open_file(path, SYS_FM_READ);
if (file == NULL)
return NULL;

const size_t file_size = sys_get_file_size(file);
uint8_t* buffer = malloc(sizeof(uint8_t) * file_size);
assert(buffer != NULL);

size_t read_bytes;
sys_file_read(file, buffer, file_size, &read_bytes);
assert(read_bytes == file_size);

*buffer_length = file_size;

sys_close_file(file);
return buffer;
}

static void convert_to_argb(uint32_t* pixels, int width, int height) {
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
// The image is in RGBA, we expect ABGR.
const uint32_t color = __builtin_bswap32(pixels[x + width * y]);
pixels[x + width * y] = color >> 8;
}
}
}

static void update_current_slide() {
int slide_buffer_len = 0;
uint8_t* slide_buffer = load_slide_image(current_slide, &slide_buffer_len);
if (slide_buffer == NULL) {
if (current_slide > 0)
current_slide--;

sys_print("Failed to open next slide (invalid file)");
return;
}

int width, height;
uint32_t* new_slide_pixels =
(uint32_t*)stbi_load_from_memory(slide_buffer, slide_buffer_len, &width, &height, NULL, 4);
free(slide_buffer);

if (new_slide_pixels == NULL) {
if (current_slide > 0)
current_slide--;

sys_print("Failed to open next slide (invalid image)");
return;
}

free((void*)slide_pixels);

convert_to_argb(new_slide_pixels, width, height);

slide_pixels = new_slide_pixels;
slide_width = width;
slide_height = height;

draw_slide();
}

static void handle_key_event(sys_key_event_t event) {
if (!sys_is_press_event(event))
return;

switch (sys_get_key_code(event)) {
case SYS_KEY_LEFT_ARROW:
if (current_slide == 0)
return;
current_slide--;
update_current_slide();
break;
case SYS_KEY_SPACE:
case SYS_KEY_RIGHT_ARROW:
current_slide++;
update_current_slide();
break;
default:
break;
}
}

int main() {
sys_print("SLIDES");

#if 0
cat_file("/keep.me");
#endif

sys_window_t* window = sys_window_create("Slides", SYS_POS_CENTERED, SYS_POS_CENTERED, 800, 600, SYS_WF_DEFAULT);
window = sys_window_create("Slides", SYS_POS_CENTERED, SYS_POS_CENTERED, 800, 600, SYS_WF_DEFAULT);
if (window == NULL) {
sys_print("Failed to create window for slides");
return 1;
}

draw_slide(window);
update_current_slide();

bool should_close = false;
while (!should_close) {
Expand All @@ -48,13 +200,19 @@ int main() {
should_close = true;
break;
case SYS_MSG_RESIZE:
draw_slide(window);
draw_slide();
break;
case SYS_MSG_KEYDOWN:
handle_key_event(message.param1);
break;
default:
break;
}
}

if (slide_pixels != NULL)
free((void*)slide_pixels);

sys_window_destroy(window);
return 0;
}
2 changes: 2 additions & 0 deletions usr/stb_image.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
Loading

0 comments on commit e3c1597

Please sign in to comment.