diff options
Diffstat (limited to 'reduced_system_layer.c')
-rwxr-xr-x | reduced_system_layer.c | 211 |
1 files changed, 136 insertions, 75 deletions
diff --git a/reduced_system_layer.c b/reduced_system_layer.c index ae28109..5e5bfdf 100755 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -287,8 +287,12 @@ i32 main(i32 argc, c8 **argv); // The pixel size will increase when the frame duration is higher. #ifndef MAX_FRAME_DURATION +#if defined(__wasm__) +#define MAX_FRAME_DURATION 33 +#else #define MAX_FRAME_DURATION 83 #endif +#endif // The pixel size value will reset if the frame duration is higher. #ifndef FRAME_DURATION_HARD_LIMIT @@ -761,7 +765,17 @@ static i64 max2_i64_(i64 x, i64 y) { // TEMP #if defined(__wasm__) -#define LOG_ERROR(...) do { } while (0) +void log_error_impl(i32 file_len, c8 const *file, i32 line, i32 func_len, c8 const *func, i32 text_len, c8 const *text); +#define LOG_ERROR(text_, ...) \ + do { \ + i32 len = 0; \ + while ((text_)[len] != '\0') ++len; \ + log_error_impl( \ + sizeof(__FILE__) - 1, __FILE__, \ + __LINE__, \ + sizeof(__func__) - 1, __func__, \ + len, text_); \ + } while (0) #else #include <stdio.h> #define LOG_ERROR(...) \ @@ -848,52 +862,68 @@ void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *p i64 num_chunks = (align_(size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE; i64 chunk = (g_platform.memory_buffer_size + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE; - // Search free space - for (i64 i = 0;; ++i) { - while ((i % 64) == 0 - && i < occupied_len_bits - && (i + 64 <= prev_chunk || i >= prev_chunk + prev_num_chunks) - && occupied[i / 64] == ~0ull) - i += 64; - while ((i % 8) == 0 - && i < occupied_len_bits - && (i + 8 <= prev_chunk || i >= prev_chunk + prev_num_chunks) - && ((u8 *) occupied)[i / 8] == 255u) - i += 8; - if (i >= occupied_len_bits) break; - b8 is_occupied = 0; - for (i64 j = i; j < i + num_chunks; ++j) { - if (j >= prev_chunk && j < prev_chunk + prev_num_chunks) continue; - if ((occupied[j / 64] & (1ull << (j % 64))) == 0) continue; - is_occupied = 1; - break; + if (num_chunks == prev_num_chunks) + return previous_data; + + u8 *dst = NULL; + + if (num_chunks < prev_num_chunks) { + // Reuse previously allocated space. + chunk = prev_chunk; + dst = data + chunk * MEMORY_CHUNK_SIZE; + } else { + // Search free space + for (i64 i = 0;; ++i) { + while ((i % 64) == 0 + && i < occupied_len_bits + && (i + 64 <= prev_chunk || i >= prev_chunk + prev_num_chunks) + && occupied[i / 64] == ~0ull) + i += 64; + while ((i % 8) == 0 + && i < occupied_len_bits + && (i + 8 <= prev_chunk || i >= prev_chunk + prev_num_chunks) + && ((u8 *) occupied)[i / 8] == 255u) + i += 8; + if (i >= occupied_len_bits) break; + b8 is_occupied = 0; + for (i64 j = i; j < i + num_chunks; ++j) { + if (j >= prev_chunk && j < prev_chunk + prev_num_chunks) continue; + if ((occupied[j / 64] & (1ull << (j % 64))) == 0) continue; + is_occupied = 1; + break; + } + if (!is_occupied) { + chunk = i; + break; + } } - if (!is_occupied) { - chunk = i; - break; + + // Check if out of memory + dst = data + chunk * MEMORY_CHUNK_SIZE; + if (dst + size > g_platform.memory_buffer + g_platform.memory_buffer_size) { + LOG_ERROR("Out of memory: %lld bytes", size - previous_size); + return NULL; } - } - // Check if out of memory - u8 *dst = data + chunk * MEMORY_CHUNK_SIZE; - if (dst + size > g_platform.memory_buffer + g_platform.memory_buffer_size) { - LOG_ERROR("Out of memory: %lld bytes", size - previous_size); - return NULL; + // Claim required space + for (i64 j = chunk; j < chunk + num_chunks; ++j) + occupied[j / 64] |= 1ull << (j % 64); } - // Claim required space - for (i64 j = chunk; j < chunk + num_chunks; ++j) - occupied[j / 64] |= 1ull << (j % 64); - - // Copy data - u8 *src = data + prev_chunk * MEMORY_CHUNK_SIZE; - i64 len = size < previous_size ? size : previous_size; - if (dst > src) - for (i64 k = len - 1; k >= 0; --k) - dst[k] = src[k]; - else - for (i64 k = 0; k < len; ++k) - dst[k] = src[k]; + if (chunk != prev_chunk) { + // Copy data + i64 len = size < previous_size ? size : previous_size; + u8 *s0 = data + prev_chunk * MEMORY_CHUNK_SIZE; + u8 *s1 = s0 + len - 1; + u8 *d0 = dst; + u8 *d1 = dst + len - 1; + if (d0 > s0) + for (u8 *d = d1, *s = s1; d >= d0; --d, --s) + *d = *s; + else + for (u8 *d = d0, *s = s0; d <= d1; ++d, ++s) + *d = *s; + } // Free previous space for (i64 j = prev_chunk; j < prev_chunk + prev_num_chunks; ++j) { @@ -2079,7 +2109,7 @@ void handle_primary_sound(void) { if (num_frames > MAX_NUM_PRIMARY_SOUND_FRAMES) { LOG_ERROR("Sound buffer overflow."); - num_frames = MAX_NUM_PRIMARY_SOUND_FRAMES; + num_frames %= MAX_NUM_PRIMARY_SOUND_FRAMES; } i32 s; @@ -2559,7 +2589,7 @@ b8 wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pi if (state.display == NULL) { LOG_ERROR("wl_display_connect failed."); - goto finalize; + goto _finalize; } state.registry = wl_display_get_registry(state.display); @@ -2572,17 +2602,17 @@ b8 wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pi if (state.shm == NULL) { LOG_ERROR("Compositor does not support wl_shm."); - goto finalize; + goto _finalize; } if (wl_list_empty(&state.outputs)) { LOG_ERROR("No wl_output."); - goto finalize; + goto _finalize; } if (state.screencopy_manager == NULL) { LOG_ERROR("Compositor does not support wlr-screencopy-unstable-v1."); - goto finalize; + goto _finalize; } u64 n_pending = 0; @@ -2605,71 +2635,82 @@ b8 wayland_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pi if (n_pending == 0) { LOG_ERROR("Supplied geometry did not intersect with any outputs."); - goto finalize; + goto _finalize; } b8 done = 0; while (!done && wl_display_dispatch(state.display) != -1) { if (!state.ok) - goto finalize; + goto _finalize; usleep(0); done = (state.n_done == n_pending); } if (!done) { LOG_ERROR("Failed to screenshoot all outputs."); - goto finalize; + goto _finalize; } *width = 0; *height = 0; + // NOTE: We grab only one output. + + // TODO: Allow to choose the desired output. + wl_list_for_each(output, &state.outputs, link) { WL_Buffer_ *buffer = output->buffer; if (buffer == NULL) continue; if (!check_format_(buffer->format)) continue; - if (*width < buffer->width) - *width = buffer->width; - *height += buffer->height; + *width = buffer->width; + *height = buffer->height; + break; } if (pixels == NULL || *width * *height > max_num_pixels) { ok = 1; - goto finalize; + goto _finalize; } for (i32 i = 0; i < *width * *height; ++i) pixels[i] = (vec4_f32) { 0.f, 0.f, 0.f, 1.f }; - i32 y0 = 0; - wl_list_for_each(output, &state.outputs, link) { WL_Buffer_ *buffer = output->buffer; if (buffer == NULL) continue; if (!check_format_(buffer->format)) continue; - for (i32 j = 0; j < buffer->height; ++j) - for (i32 i = 0; i < buffer->width; ++i) { - vec3_f32 c = rgb_f32_from_u32_(((u32 *) buffer->data)[j * (buffer->stride / 4) + i]); + if (*width != buffer->width) { + LOG_ERROR("Sanity"); + break; + } + + for (i32 j = 0; j < buffer->height; ++j) { + vec4_f32 *d = pixels + j * *width; + vec4_f32 *d_end = d + *width; + u32 *s = ((u32 *) buffer->data) + j * (buffer->stride / 4); - pixels[(y0 + j) * *width + i] = (vec4_f32) { + for (; d < d_end; ++d, ++s) { + vec3_f32 c = rgb_f32_from_u32_(*s); + *d = (vec4_f32) { .x = c.x, .y = c.y, .z = c.z, .w = 1.f, }; } + } - y0 += buffer->height; + break; } ok = 1; WL_Output_ *output_tmp; -finalize: +_finalize: wl_list_for_each_safe(output, output_tmp, &state.outputs, link) { wl_list_remove(&output->link); free(output->name); @@ -3579,6 +3620,20 @@ void write_clipboard_text(i64 size, c8 *data) { XSetSelectionOwner(_display, _clipboard, _window, CurrentTime); } +b8 x11_get_root_(void) { + Window root, parent, *children; + u32 num_children; + + if(!XQueryTree(_display, _window, &root, &parent, &children, &num_children)) + return 0; + + if (children != NULL) + XFree((c8 *) children); + + _root_window = root; + return 1; +} + b8 x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { if (_display == NULL) { LOG_ERROR("No display."); @@ -3589,6 +3644,8 @@ b8 x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels i32 display_width = DisplayWidth (_display, screen); i32 display_height = DisplayHeight(_display, screen); + x11_get_root_(); + XImage *image = XGetImage(_display, _root_window, 0, 0, display_width, display_height, AllPlanes, ZPixmap); if (image == NULL) { @@ -3600,17 +3657,22 @@ b8 x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels *height = image->height; if (pixels != NULL && image->width * image->height <= max_num_pixels) - for (i64 j = 0; j < image->height; ++j) - for (i64 i = 0; i < image->width; ++i) { - vec3_f32 f = rgb_f32_from_u32_(XGetPixel(image, i, j)); - - pixels[j * image->width + i] = (vec4_f32) { - .x = f.x, - .y = f.y, - .z = f.z, + for (i64 j = 0; j < image->height; ++j) { + vec4_f32 *d = pixels + j * image->width; + vec4_f32 *d_first = d; + vec4_f32 *d_end = d + image->width; + + for (; d < d_end; ++d) { + vec3_f32 c = rgb_f32_from_u32_(XGetPixel(image, d - d_first, j)); + + *d = (vec4_f32) { + .x = c.x, + .y = c.y, + .z = c.z, .w = 1.f, }; } + } XDestroyImage(image); return 1; @@ -3980,11 +4042,7 @@ __attribute__((export_name("js_title"))) void *js_title(void) { return g_platform.title; } -__attribute__((export_name("js_pixels"))) void *js_pixels(void) { - return _internal_pixels; -} - -__attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 frame_height, i32 num_samples) { +__attribute__((export_name("js_frame"))) void *js_frame(i32 frame_width, i32 frame_height, i32 num_samples) { i64 frame_time = current_utc_time_in_milliseconds(); _num_events += pixel_size_update_(frame_width, frame_height); @@ -4010,6 +4068,8 @@ __attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 fram if (do_render) pixel_size_calibrate_(current_utc_time_in_milliseconds() - frame_time); + + return _internal_pixels; } __attribute__((export_name("js_mousemove"))) void js_mousemove(i32 x, i32 y) { @@ -4111,6 +4171,7 @@ __attribute__((export_name("js_drop"))) i32 js_drop(i32 name_len, i32 data_size) drop_files_set_name_(n, 0, NULL); drop_files_set_data_(n, 0); drop_files_set_num_(n); + LOG_ERROR("File too big."); return 0; } |