summaryrefslogtreecommitdiff
path: root/reduced_system_layer.c
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2025-02-22 00:23:06 +0100
committerMitya Selivanov <automainint@guattari.tech>2025-02-22 00:23:06 +0100
commit2e193910ca6de4486eb39e9a7decf162cfa1f160 (patch)
treec3e76de0e0eaf8325dc05b1b99fc41863ac5d6fb /reduced_system_layer.c
parent7d92468a5d298ec6dd6455482ff0521efecf9541 (diff)
downloadreduced_system_layer-2e193910ca6de4486eb39e9a7decf162cfa1f160.zip
Fix web pixel buffer access
Diffstat (limited to 'reduced_system_layer.c')
-rwxr-xr-xreduced_system_layer.c211
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;
}