summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2025-02-11 11:06:28 +0100
committerMitya Selivanov <automainint@guattari.tech>2025-02-11 11:06:28 +0100
commit2d71f1099f0eb3ef6e17316a520d3d710dec1ac0 (patch)
tree32d2db34046c1496f20650e1d3857aa5d3f9c2d7
parented275e1296defb6cc5450cf5996cf97c1fa32dfa (diff)
downloadreduced_system_layer-2d71f1099f0eb3ef6e17316a520d3d710dec1ac0.zip
Memory buffer fixes
-rw-r--r--examples/screenshot.c31
-rwxr-xr-xgraphics.c42
-rwxr-xr-xreduced_system_layer.c218
3 files changed, 123 insertions, 168 deletions
diff --git a/examples/screenshot.c b/examples/screenshot.c
index c3c0ebd..11b2385 100644
--- a/examples/screenshot.c
+++ b/examples/screenshot.c
@@ -1,23 +1,34 @@
#include "../graphics.c"
-i64 width = 0;
-i64 height = 0;
-b8 has_screenshot = 0;
+enum {
+ MAX_NUM_PIXELS = 10 * 1024 * 1024,
+};
+
+b8 has_screenshot = 0;
+i64 width = 0;
+i64 height = 0;
+vec4_f32 pixels[MAX_NUM_PIXELS] = {0};
void update_and_render_frame(void) {
if (!has_screenshot) {
- take_screenshot(MAX_NUM_PIXELS, &width, &height, g_platform.sketch);
+ take_screenshot(MAX_NUM_PIXELS, &width, &height, pixels);
has_screenshot = 1;
}
handle_main_window_events();
- draw_pixels((Brush) { .quick = 1, }, 0, 0, g_platform.real_width, g_platform.real_height, (Pixel_Buffer) {
- .width = width,
- .height = height,
- .stride = width,
- .pixels = g_platform.sketch,
- });
+ draw_pixels_quick(
+ (Box) {
+ .width = g_platform.real_width,
+ .height = g_platform.real_height,
+ },
+ (Pixel_Buffer) {
+ .width = width,
+ .height = height,
+ .stride = width,
+ .pixels = pixels,
+ }
+ );
render_main_window_frame();
}
diff --git a/graphics.c b/graphics.c
index 95cff6b..670610b 100755
--- a/graphics.c
+++ b/graphics.c
@@ -248,6 +248,10 @@ enum {
CHAR_NUM_BITS_ = CHAR_NUM_BITS_X_ * CHAR_NUM_BITS_Y_,
};
+static i64 min2_i64_(i64 x, i64 y) {
+ return x < y ? x : y;
+}
+
static f32 max2_f32_(f32 a, f32 b) {
return a < b ? b : a;
}
@@ -344,11 +348,25 @@ void draw_pixels_to_buffer(Pixel_Buffer dst, Box area, Pixel_Buffer src) {
for (i64 j = j0; j < j1; ++j) {
i64 src_j = (i64) floor(((j - area.y + .5) * src.height) * h_inv);
if (src_j < 0 || src_j >= src.height) continue;
- i64 src_n = src_j * src.stride;
+ vec4_f32 *q = src.pixels + src_j * src.stride;
+ vec4_f32 *p = dst.pixels + j * dst.stride + i0;
for (i64 i = i0; i < i1; ++i) {
i64 src_i = (i64) floor(((i - area.x + .5) * src.width) * w_inv);
if (src_i < 0 || src_i >= src.width) continue;
- put_pixel_(dst, src.pixels[src_n + src_i], i, j);
+ vec4_f32 color = q[src_i];
+ if (color.w == 1.f)
+ *p = color;
+ else {
+ vec4_f32 dst_color = *p;
+ f32 dst_amount = 1. - color.w;
+ *p = (vec4_f32) {
+ .x = dst_color.x * dst_amount + color.x * color.w,
+ .y = dst_color.y * dst_amount + color.y * color.w,
+ .z = dst_color.z * dst_amount + color.z * color.w,
+ .w = max2_f32_(dst_color.w, color.w),
+ };
+ }
+ ++p;
}
}
}
@@ -1948,8 +1966,10 @@ static void scale_and_perform_graphics_request_(Graphics_Context context, Graphi
static Graphics_Context graphics_context_defaults_(Graphics_Context context) {
if (context.dst.pixels == NULL) {
+ i64 max_height = g_platform.num_pixels / g_platform.frame_width;
+
context.dst.width = g_platform.frame_width;
- context.dst.height = g_platform.frame_height;
+ context.dst.height = min2_i64_(max_height, g_platform.frame_height);
context.dst.stride = g_platform.frame_width;
context.dst.pixels = g_platform.pixels;
@@ -2076,19 +2096,19 @@ TEST("colors") {
REQUIRE_EQ((purple.z + 2e-7) * 100, 100);
}
-Pixel_Buffer pixels = {
+static Pixel_Buffer _test_pixels = {
.width = 1280,
.height = 720,
.stride = 1280,
.pixels = (vec4_f32[1280 * 720]) {0},
};
-vec4_f32 color = { 1., 1., 1., 1., };
+static vec4_f32 _test_color = { 1., 1., 1., 1., };
BENCHMARK("fill rectangle") {
BENCHMARK_BEGIN;
{
- fill_rectangle_to_buffer(pixels, color, (Box) { .x = 100, .y = 100, .width = 300, .height = 200, });
+ fill_rectangle_to_buffer(_test_pixels, _test_color, (Box) { .x = 100, .y = 100, .width = 300, .height = 200, });
}
BENCHMARK_END;
}
@@ -2096,7 +2116,7 @@ BENCHMARK("fill rectangle") {
BENCHMARK("fill triangle") {
BENCHMARK_BEGIN;
{
- fill_triangle_to_buffer(pixels, color, (vec2[3]) {
+ fill_triangle_to_buffer(_test_pixels, _test_color, (vec2[3]) {
{ 100, 100 },
{ 300, 100 },
{ 200, 250 },
@@ -2108,7 +2128,7 @@ BENCHMARK("fill triangle") {
BENCHMARK("fill quad") {
BENCHMARK_BEGIN;
{
- fill_quad_to_buffer(pixels, color, (vec2[4]) {
+ fill_quad_to_buffer(_test_pixels, _test_color, (vec2[4]) {
{ 100, 100 },
{ 300, 100 },
{ 300, 200 },
@@ -2121,7 +2141,7 @@ BENCHMARK("fill quad") {
BENCHMARK("fill ellipse") {
BENCHMARK_BEGIN;
{
- fill_ellipse_to_buffer(pixels, color, (Box) { .x = 80, .y = 80, .width = 340, .height = 240, });
+ fill_ellipse_to_buffer(_test_pixels, _test_color, (Box) { .x = 80, .y = 80, .width = 340, .height = 240, });
}
BENCHMARK_END;
}
@@ -2129,7 +2149,7 @@ BENCHMARK("fill ellipse") {
BENCHMARK("fill line") {
BENCHMARK_BEGIN;
{
- fill_line_to_buffer(pixels, color, (vec2[2]) {
+ fill_line_to_buffer(_test_pixels, _test_color, (vec2[2]) {
{ 100, 100 },
{ 300, 200 },
}, 40);
@@ -2141,7 +2161,7 @@ BENCHMARK("draw text area") {
BENCHMARK_BEGIN;
{
c32 text[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'S', 'a', 'i', 'l', 'o', 'r', '!', };
- draw_text_area_to_buffer(pixels, color, (Box) { .x = 100, .y = 100, .width = 300, .height = 200, }, (vec2) { 100, 200 }, sizeof text / sizeof *text, text);
+ draw_text_area_to_buffer(_test_pixels, _test_color, (Box) { .x = 100, .y = 100, .width = 300, .height = 200, }, (vec2) { 100, 200 }, sizeof text / sizeof *text, text);
}
BENCHMARK_END;
}
diff --git a/reduced_system_layer.c b/reduced_system_layer.c
index ad5e990..3d6a08d 100755
--- a/reduced_system_layer.c
+++ b/reduced_system_layer.c
@@ -111,6 +111,9 @@
#/ - macOS support
#/ - Mobile devices support
#/
+#/ Bugs
+#/ - Buffer overflow after resizing the window.
+#/
#/ Done
#/
#/ - Examples
@@ -249,7 +252,7 @@ i32 main(i32 argc, c8 **argv);
#endif
#ifndef STATIC_MEMORY_BUFFER_SIZE
-#define STATIC_MEMORY_BUFFER_SIZE (10 * 1024 * 1024)
+#define STATIC_MEMORY_BUFFER_SIZE (20 * 1024 * 1024)
#endif
#ifndef MEMORY_CHUNK_SIZE
@@ -288,11 +291,11 @@ i32 main(i32 argc, c8 **argv);
#endif
#ifndef NUM_FRAMES_AVERAGED
-#define NUM_FRAMES_AVERAGED 400
+#define NUM_FRAMES_AVERAGED 600
#endif
#ifndef AVERAGE_FRAME_BIAS
-#define AVERAGE_FRAME_BIAS (0.02)
+#define AVERAGE_FRAME_BIAS (0.03)
#endif
#ifndef MAX_NUM_KEYS
@@ -616,8 +619,8 @@ typedef struct {
i64 num_sound_samples_elapsed;
i64 num_pixels;
- i64 sketch_len;
i64 input_len;
+ i64 input_capacity;
i64 num_drop_files;
i64 clipboard_text_len;
i64 clipboard_image_width;
@@ -626,11 +629,7 @@ typedef struct {
i64 num_clipboard_sound_samples;
i64 clipboard_sound_len;
- i64 pixels_capacity;
- i64 input_capacity;
-
vec4_f32 *pixels;
- f32 *sketch;
Input_Key *input;
Drop_File *drop_files;
c8 *clipboard_text;
@@ -713,12 +712,10 @@ extern Platform g_platform;
Platform g_platform = {0};
-static i64 _sound_clock_time = 0;
-static i64 _sound_clock_carry = 0;
-static i64 _sound_position = 0;
-static i64 _frame_index = 0;
-static i64 _drop_files_buffer_len = 0;
-static u8 *_drop_files_buffer = NULL;
+static i64 _sound_clock_time = 0;
+static i64 _sound_clock_carry = 0;
+static i64 _sound_position = 0;
+static i64 _frame_index = 0;
static f32 _sound_ring [MAX_NUM_PRIMARY_SOUND_FRAMES] = {0};
static i64 _frame_duration [NUM_FRAMES_AVERAGED] = {0};
@@ -792,10 +789,13 @@ void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *p
g_platform.memory_buffer = memory_buffer_;
}
- i64 occupied_len = memory_buffer_occupied_len_(g_platform.memory_buffer_size);
- u64 *occupied = (u64 *) g_platform.memory_buffer;
+ i64 occupied_len = memory_buffer_occupied_len_(g_platform.memory_buffer_size);
+ i64 occupied_len_bytes = occupied_len * 8;
+ i64 occupied_len_bits = occupied_len * 64;
+
+ u64 *occupied = (u64 *) g_platform.memory_buffer;
- if (g_platform.memory_buffer_size <= occupied_len * 64) {
+ if (g_platform.memory_buffer_size <= occupied_len_bytes) {
LOG_ERROR("Memory buffer too small.");
return NULL;
}
@@ -820,7 +820,7 @@ void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *p
return NULL;
}
- u8 *data = g_platform.memory_buffer + occupied_len * 64;
+ u8 *data = g_platform.memory_buffer + occupied_len_bytes;
i64 prev_num_chunks = 0;
i64 prev_chunk = 0;
@@ -835,31 +835,26 @@ void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *p
// Search free space
i64 i0 = 0;
- while (i0 < occupied_len && occupied[i0] == ~0ull)
- ++i0;
- for (i64 i = i0; i < occupied_len * 64; ++i) {
+ while (i0 < occupied_len_bits && occupied[i0 / 64] == ~0ull)
+ i0 += 64;
+ for (i64 i = i0; i < occupied_len_bits; ++i) {
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;
+ if ((occupied[j / 64] & (1ull << (j % 64))) == 0) continue;
is_occupied = 1;
break;
}
-
- if (is_occupied) {
+ if (!is_occupied) {
chunk = i;
break;
}
}
- u8 *src = data + prev_chunk * MEMORY_CHUNK_SIZE;
- u8 *dst = data + chunk * MEMORY_CHUNK_SIZE;
- i64 len = size < previous_size ? size : previous_size;
-
// 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.");
+ LOG_ERROR("Out of memory: %lld bytes", size - previous_size);
return NULL;
}
@@ -868,6 +863,8 @@ void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *p
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];
@@ -901,6 +898,7 @@ void resize_dynamic_array_exact(i64 *num, void **data, i64 element_size, i64 new
);
if (new_data == NULL && new_num > 0)
+ // Out of memory.
return;
*num = new_num;
@@ -916,7 +914,8 @@ void resize_dynamic_array_capacity(i64 *num, i64 *capacity, void **data, i64 ele
if (new_num > *capacity)
resize_dynamic_array_exact(capacity, data, element_size, new_num);
- *num = new_num;
+ if (new_num <= *capacity)
+ *num = new_num;
}
// ================================================================
@@ -982,19 +981,6 @@ static b8 native_little_endian_(void) {
return ((u8 *) &(u32) { 1 })[0] == 1;
}
-static u32 load32_(void *src) {
- if (native_little_endian_())
- return *( u32 * )( src );
- else {
- u8 *p = ( u8 * )src;
- u32 w = *p++;
- w |= ( u32 )( *p++ ) << 8;
- w |= ( u32 )( *p++ ) << 16;
- w |= ( u32 )( *p++ ) << 24;
- return w;
- }
-}
-
static u64 load64_(void *src) {
if (native_little_endian_())
return *( u64 * )( src );
@@ -1040,39 +1026,6 @@ static void store64_(void *dst, u64 w) {
}
}
-static u64 load48_(void *src) {
- u8 *p = ( u8 * )src;
- u64 w = *p++;
- w |= ( u64 )( *p++ ) << 8;
- w |= ( u64 )( *p++ ) << 16;
- w |= ( u64 )( *p++ ) << 24;
- w |= ( u64 )( *p++ ) << 32;
- w |= ( u64 )( *p++ ) << 40;
- return w;
-}
-
-static void store48_(void *dst, u64 w) {
- u8 *p = ( u8 * )dst;
- *p++ = ( u8 )w; w >>= 8;
- *p++ = ( u8 )w; w >>= 8;
- *p++ = ( u8 )w; w >>= 8;
- *p++ = ( u8 )w; w >>= 8;
- *p++ = ( u8 )w; w >>= 8;
- *p++ = ( u8 )w;
-}
-
-static u32 rotl32_(u32 w, u32 c) {
- return ( w << c ) | ( w >> ( 32 - c ) );
-}
-
-static u64 rotl64_(u64 w, u32 c) {
- return ( w << c ) | ( w >> ( 64 - c ) );
-}
-
-static u32 rotr32_(u32 w, u32 c) {
- return ( w >> c ) | ( w << ( 32 - c ) );
-}
-
static u64 rotr64_(u64 w, u32 c) {
return ( w >> c ) | ( w << ( 64 - c ) );
}
@@ -1087,11 +1040,6 @@ static i32 blake2b_set_lastnode_(Blake2b_State *S) {
return 0;
}
-static i32 blake2b_clear_lastnode_(Blake2b_State *S) {
- S->f[1] = 0ull;
- return 0;
-}
-
static i32 blake2b_set_lastblock_(Blake2b_State *S) {
if( S->last_node ) blake2b_set_lastnode_( S );
@@ -1099,64 +1047,12 @@ static i32 blake2b_set_lastblock_(Blake2b_State *S) {
return 0;
}
-static i32 blake2b_clear_lastblock_(Blake2b_State *S) {
- if( S->last_node ) blake2b_clear_lastnode_( S );
-
- S->f[0] = 0ull;
- return 0;
-}
-
static i32 blake2b_increment_counter_(Blake2b_State *S, u64 inc) {
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
return 0;
}
-static i32 blake2b_param_set_digest_length_(Blake2b_Param *P, u8 digest_length) {
- P->digest_length = digest_length;
- return 0;
-}
-
-static i32 blake2b_param_set_fanout_(Blake2b_Param *P, u8 fanout) {
- P->fanout = fanout;
- return 0;
-}
-
-static i32 blake2b_param_set_max_depth_(Blake2b_Param *P, u8 depth) {
- P->depth = depth;
- return 0;
-}
-
-static i32 blake2b_param_set_leaf_length_(Blake2b_Param *P, u32 leaf_length) {
- store32_( &P->leaf_length, leaf_length );
- return 0;
-}
-
-static i32 blake2b_param_set_node_offset_(Blake2b_Param *P, u64 node_offset) {
- store64_( &P->node_offset, node_offset );
- return 0;
-}
-
-static i32 blake2b_param_set_node_depth_(Blake2b_Param *P, u8 node_depth) {
- P->node_depth = node_depth;
- return 0;
-}
-
-static i32 blake2b_param_set_inner_length_(Blake2b_Param *P, u8 inner_length) {
- P->inner_length = inner_length;
- return 0;
-}
-
-static i32 blake2b_param_set_salt_(Blake2b_Param *P, u8 salt[BLAKE2B_SALTBYTES]) {
- mem_cpy_( P->salt, salt, BLAKE2B_SALTBYTES );
- return 0;
-}
-
-static i32 blake2b_param_set_personal_(Blake2b_Param *P, u8 personal[BLAKE2B_PERSONALBYTES]) {
- mem_cpy_( P->personal, personal, BLAKE2B_PERSONALBYTES );
- return 0;
-}
-
static i32 blake2b_init0_(Blake2b_State *S) {
i32 i;
mem_set_( S, 0, sizeof( Blake2b_State ) );
@@ -1511,11 +1407,6 @@ static void drop_files_clean_(void) {
}
resize_dynamic_array_exact(&g_platform.num_drop_files, (void **) &g_platform.drop_files, sizeof *g_platform.drop_files, 0);
- resize_dynamic_array_exact(&_drop_files_buffer_len, (void **) &_drop_files_buffer, 1, 0);
-}
-
-static i64 align_size_(i64 x) {
- return (x + 7) & ~7ll;
}
static void drop_files_set_num_(i64 num) {
@@ -1693,6 +1584,8 @@ static void network_cleanup_(void) {
close(_sockets[i].socket);
_sockets[i].ready = 0;
}
+
+ resize_dynamic_array_exact(&_num_sockets, (void **) &_sockets, sizeof *_sockets, 0);
}
static b8 network_open_(u16 slot, IP_Address address, u16 *local_port) {
@@ -2674,6 +2567,19 @@ static i32 x11_error_handler_(Display *display, XErrorEvent *event) {
return 0;
}
+void update_main_window_frame_(void) {
+ i64 num_pixels = g_platform.frame_width * g_platform.frame_height;
+
+ if (g_platform.num_pixels < num_pixels)
+ resize_dynamic_array_exact(&g_platform.num_pixels, (void **) &g_platform.pixels, sizeof *g_platform.pixels, num_pixels);
+ if (_pixels_scaled_len < num_pixels)
+ resize_dynamic_array_exact(&_pixels_scaled_len, (void **) &_pixels_scaled, sizeof *_pixels_scaled, num_pixels);
+ if (_pixels_internal_len < num_pixels)
+ resize_dynamic_array_exact(&_pixels_internal_len, (void **) &_pixels_internal, sizeof *_pixels_internal, num_pixels);
+
+ _image.data = (c8 *) _pixels_internal;
+}
+
void init_main_window(void) {
for (i64 i = 0; i < NUM_FRAMES_AVERAGED; ++i)
_frame_duration[i] = (MIN_FRAME_DURATION + MAX_FRAME_DURATION) / 2;
@@ -2851,9 +2757,7 @@ void init_main_window(void) {
.width = g_platform.frame_width,
.height = g_platform.frame_height,
.depth = depth,
- .xoffset = 0,
.format = ZPixmap,
- .data = (c8 *) _pixels_internal,
.byte_order = LSBFirst,
.bitmap_unit = 32,
.bitmap_bit_order = LSBFirst,
@@ -2865,6 +2769,8 @@ void init_main_window(void) {
.blue_mask = 0x0000ff,
};
+ update_main_window_frame_();
+
XInitImage(&_image);
_wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", False);
@@ -2915,6 +2821,15 @@ void shutdown_all_systems(void) {
_window = 0;
_display = NULL;
+ drop_files_clean_();
+ g_platform.input_len = 0;
+
+ resize_dynamic_array_exact(&_pixels_scaled_len, (void **) &_pixels_scaled, sizeof *_pixels_scaled, 0);
+ resize_dynamic_array_exact(&_pixels_internal_len, (void **) &_pixels_internal, sizeof *_pixels_internal, 0);
+ resize_dynamic_array_exact(&g_platform.num_pixels, (void **) &g_platform.pixels, sizeof *g_platform.pixels, 0);
+ resize_dynamic_array_exact(&g_platform.input_capacity, (void **) &g_platform.input, sizeof *g_platform.input, 0);
+ resize_dynamic_array_exact(&g_platform.clipboard_text_len, (void **) &g_platform.clipboard_text, 1, 0);
+
network_cleanup_();
sound_cleanup_();
}
@@ -3466,11 +3381,7 @@ void render_main_window_frame(void) {
_mapped = 1;
}
- i64 num_pixels = g_platform.frame_width * g_platform.frame_height;
- if (_pixels_scaled_len < num_pixels)
- resize_dynamic_array_exact(&_pixels_scaled_len, (void **) &_pixels_scaled, sizeof *_pixels_scaled, num_pixels);
- if (_pixels_internal_len < num_pixels)
- resize_dynamic_array_exact(&_pixels_internal_len, (void **) &_pixels_internal, sizeof *_pixels_internal, num_pixels);
+ update_main_window_frame_();
if (g_platform.frame_width == _image.width && g_platform.frame_height == _image.height) {
i64 size = g_platform.frame_width * g_platform.frame_height;
@@ -3815,18 +3726,31 @@ i32 wait_main_window_events(void) {
void render_main_window_frame(void) {
if (_frame_width == g_platform.frame_width && _frame_height == g_platform.frame_height) {
i64 size = g_platform.frame_width * g_platform.frame_height;
+ if (size > g_platform.num_pixels)
+ size = g_platform.num_pixels;
+ if (size > _pixels_internal_len)
+ size = _pixels_internal_len;
+
for (i64 i = 0; i < size; ++i)
_pixels_internal[i] = 0xff000000u | rgb_u32_from_f32_((vec3_f32) { g_platform.pixels[i].z, g_platform.pixels[i].y, g_platform.pixels[i].x });
} else {
i64 size = g_platform.frame_width * g_platform.frame_height;
+ if (size > g_platform.num_pixels)
+ size = g_platform.num_pixels;
+ if (size > _pixels_scaled_len)
+ size = _pixels_scaled_len;
+
for (i64 i = 0; i < size; ++i)
_pixels_scaled[i] = rgb_u32_from_f32_((vec3_f32) { g_platform.pixels[i].z, g_platform.pixels[i].y, g_platform.pixels[i].x });
for (i64 j = 0; j < _frame_height; ++j) {
i64 j0 = (j * g_platform.frame_height) / _frame_height;
+ if ((j0 + 1) * _frame_width > _pixels_internal_len) break;
for (i64 i = 0; i < _frame_width; ++i) {
i64 i0 = (i * g_platform.frame_width) / _frame_width;
- _pixels_internal[j * _frame_width + i] = 0xff000000u | _pixels_scaled[j0 * g_platform.frame_width + i0];
+ i64 n0 = j0 * g_platform.frame_width + i0;
+ if (n0 > _pixels_scaled_len) break;
+ _pixels_internal[j * _frame_width + i] = 0xff000000u | _pixels_scaled[n0];
}
}
}