use std::collections::list instead of custom fifo

This commit is contained in:
Alessandro Mauri 2025-10-05 01:24:56 +02:00
parent d7cab085f7
commit 2bb907d523
4 changed files with 32 additions and 120 deletions

View File

@ -1,7 +1,7 @@
module ugui; module ugui;
import std::ascii;
import std::io; import std::io;
import std::collections::list;
// command type // command type
enum CmdType { enum CmdType {
@ -49,6 +49,10 @@ struct Cmd (Printable) {
} }
} }
// command queue
alias CmdQueue = list::List{Cmd};
fn int Cmd.compare_to(Cmd a, Cmd b) fn int Cmd.compare_to(Cmd a, Cmd b)
{ {
if (a.z_index == b.z_index) return 0; if (a.z_index == b.z_index) return 0;
@ -87,21 +91,21 @@ macro bool cull_rect(Rect rect, Rect clip = {0,0,short.max,short.max})
} }
// FIXME: this whole thing could be done at compile time, maybe // FIXME: this whole thing could be done at compile time, maybe
macro Ctx.push_cmd(&ctx, Cmd *cmd, int z_index) macro Ctx.push_cmd(&ctx, Cmd cmd, int z_index)
{ {
cmd.z_index = z_index; cmd.z_index = z_index;
Rect rect; Rect rect;
switch (cmd.type) { switch (cmd.type) {
case CMD_RECT: rect = cmd.rect.rect; case CMD_RECT: rect = cmd.rect.rect;
case CMD_SPRITE: rect = cmd.sprite.rect; case CMD_SPRITE: rect = cmd.sprite.rect;
default: return ctx.cmd_queue.enqueue(cmd); default: return ctx.cmd_queue.push(cmd);
} }
if (cull_rect(rect, ctx.div_scissor)) { if (cull_rect(rect, ctx.div_scissor)) {
// println("NOPE: ", cmd.rect.rect, cmd.z_index); // println("NOPE: ", cmd.rect.rect, cmd.z_index);
// unreachable(); // unreachable();
return; return;
} }
return ctx.cmd_queue.enqueue(cmd); return ctx.cmd_queue.push(cmd);
} }
fn void? Ctx.push_scissor(&ctx, Rect rect, int z_index) fn void? Ctx.push_scissor(&ctx, Rect rect, int z_index)
@ -110,10 +114,10 @@ fn void? Ctx.push_scissor(&ctx, Rect rect, int z_index)
.type = CMD_SCISSOR, .type = CMD_SCISSOR,
.scissor.rect = rect.intersection(ctx.div_scissor), .scissor.rect = rect.intersection(ctx.div_scissor),
}; };
ctx.push_cmd(&sc, z_index)!; ctx.push_cmd(sc, z_index);
} }
fn void? Ctx.reset_scissor(&ctx, int z_index) => ctx.push_cmd(&&(Cmd){.type=CMD_SCISSOR,.scissor.rect=ctx.div_scissor}, z_index)!; fn void? Ctx.reset_scissor(&ctx, int z_index) => ctx.push_cmd({.type=CMD_SCISSOR,.scissor.rect=ctx.div_scissor}, z_index);
fn void? Ctx.push_rect(&ctx, Rect rect, int z_index, Style* style) fn void? Ctx.push_rect(&ctx, Rect rect, int z_index, Style* style)
{ {
@ -130,7 +134,7 @@ fn void? Ctx.push_rect(&ctx, Rect rect, int z_index, Style* style)
.rect.color = border_color, .rect.color = border_color,
.rect.radius = radius + border.x, .rect.radius = radius + border.x,
}; };
ctx.push_cmd(&cmd, z_index)!; ctx.push_cmd(cmd, z_index);
} }
Cmd cmd = { Cmd cmd = {
@ -144,7 +148,7 @@ fn void? Ctx.push_rect(&ctx, Rect rect, int z_index, Style* style)
.rect.color = bg, .rect.color = bg,
.rect.radius = radius, .rect.radius = radius,
}; };
ctx.push_cmd(&cmd, z_index)!; ctx.push_cmd(cmd, z_index);
} }
// TODO: accept a Sprite* instead of all this shit // TODO: accept a Sprite* instead of all this shit
@ -158,7 +162,7 @@ fn void? Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id, int z_i
.sprite.texture_id = texture_id, .sprite.texture_id = texture_id,
.sprite.hue = hue, .sprite.hue = hue,
}; };
ctx.push_cmd(&cmd, z_index)!; ctx.push_cmd(cmd, z_index);
} }
fn void? Ctx.push_update_atlas(&ctx, Atlas* atlas) fn void? Ctx.push_update_atlas(&ctx, Atlas* atlas)
@ -174,7 +178,7 @@ fn void? Ctx.push_update_atlas(&ctx, Atlas* atlas)
}, },
}; };
// update the atlases before everything else // update the atlases before everything else
ctx.push_cmd(&up, -1)!; ctx.push_cmd(up, -1);
} }
macro Ctx.dbg_rect(&ctx, Rect r, uint c = 0xff000042u) => ctx.push_rect(r, int.max, &&(Style){.bg=c.to_rgba()})!!; macro Ctx.dbg_rect(&ctx, Rect r, uint c = 0xff000042u) => ctx.push_rect(r, int.max, &&(Style){.bg=c.to_rgba()})!!;

View File

@ -69,29 +69,25 @@ struct Elem {
} }
} }
const uint MAX_ELEMENTS = 256;
const uint MAX_COMMANDS = 2048;
const uint STACK_STEP = 10;
const uint ROOT_ID = 1;
const uint TEXT_MAX = 64;
// Tuple of Element pointers, used when it is useful to get both parent and child // Tuple of Element pointers, used when it is useful to get both parent and child
alias PElemTuple = pair::Pair{Elem*, Elem*}; alias PElemTuple = pair::Pair{Elem*, Elem*};
// relationships between elements are stored in a tree, it stores just the ids // relationships between elements are stored in a tree, it stores just the ids
alias IdTree = mtree::MTree{Id}; alias IdTree = mtree::MTree{Id};
// elements themselves are kept in a cache // elements themselves are kept in a cache
const uint MAX_ELEMENTS = 256;
alias ElemCache = cache::Cache{Id, Elem, MAX_ELEMENTS}; alias ElemCache = cache::Cache{Id, Elem, MAX_ELEMENTS};
alias CmdQueue = fifo::Fifo{Cmd};
faultdef INVALID_SIZE, EVENT_UNSUPPORTED, WRONG_ELEMENT_TYPE, WRONG_ID; faultdef INVALID_SIZE, EVENT_UNSUPPORTED, WRONG_ELEMENT_TYPE, WRONG_ID;
const Rect DIV_FILL = { .x = 0, .y = 0, .w = 0, .h = 0 };
const uint STACK_STEP = 10;
const uint MAX_ELEMS = 128;
const uint MAX_CMDS = 2048;
const uint ROOT_ID = 1;
const uint TEXT_MAX = 64;
struct Ctx { struct Ctx {
IdTree tree; IdTree tree;
ElemCache cache; ElemCache cache;
@ -216,7 +212,7 @@ fn void? Ctx.init(&ctx, Allocator allocator)
ctx.cache.init(allocator)!; ctx.cache.init(allocator)!;
defer catch { (void)ctx.cache.free(); } defer catch { (void)ctx.cache.free(); }
ctx.cmd_queue.init(MAX_CMDS, allocator)!; ctx.cmd_queue.init(allocator::mem, MAX_COMMANDS);
defer catch { (void)ctx.cmd_queue.free(); } defer catch { (void)ctx.cmd_queue.free(); }
ctx.styles.init(allocator); ctx.styles.init(allocator);
@ -311,13 +307,13 @@ $if $feature(DEBUG_POINTER):
}, },
.rect.color = 0xff00ffffu.to_rgba() .rect.color = 0xff00ffffu.to_rgba()
}; };
ctx.cmd_queue.enqueue(&cmd)!; ctx.cmd_queue.push(cmd);
$endif $endif
// sort the command buffer by the z-index // sort the command buffer by the z-index
// FIXME: sorting the buffer fucks with scissor commands that have to be kept in place // FIXME: sorting the buffer fucks with scissor commands that have to be kept in place
// TODO: instead of sorting at the end perform ordered inserts into the command buffer // TODO: instead of sorting at the end perform ordered inserts into the command buffer
ctx.cmd_queue.sort()!; //ctx.cmd_queue.sort()!;
// foreach (i, c: ctx.cmd_queue) { // foreach (i, c: ctx.cmd_queue) {
// io::printf("[%d]: ", i); // io::printf("[%d]: ", i);

View File

@ -1,93 +0,0 @@
module fifo::faults;
faultdef FULL, EMPTY;
module fifo{Type};
import std::core::mem;
import std::sort;
// TODO: specify the allocator
struct Fifo {
Allocator allocator;
Type[] arr;
usz out;
usz count;
}
fn void? Fifo.init(&fifo, usz size, Allocator allocator)
{
fifo.allocator = allocator;
fifo.arr = allocator::new_array(fifo.allocator, Type, size);
fifo.out = 0;
fifo.count = 0;
}
fn void Fifo.free(&fifo)
{
(void)allocator::free(fifo.allocator, fifo.arr);
}
fn void? Fifo.enqueue(&fifo, Type *elem)
{
if (fifo.count >= fifo.arr.len) {
return fifo::faults::FULL?;
}
usz in = (fifo.out + fifo.count) % fifo.arr.len;
fifo.arr[in] = *elem;
fifo.count++;
}
fn Type*? Fifo.dequeue(&fifo)
{
if (fifo.count == 0) {
return fifo::faults::EMPTY?;
}
Type *ret = &fifo.arr[fifo.out];
fifo.count--;
fifo.out = (fifo.out + 1) % fifo.arr.len;
return ret;
}
macro Type Fifo.get(&fifo, usz i) @operator([])
{
return fifo.arr[(fifo.out + i) % fifo.arr.len];
}
fn void Fifo.set(&fifo, usz i, Type val) @operator([]=)
{
fifo.arr[(fifo.out + i) % fifo.arr.len] = val;
}
macro Type* Fifo.get_ref(&fifo, usz i) @operator(&[])
{
return &fifo.arr[(fifo.out + i) % fifo.arr.len];
}
macro usz Fifo.len(&fifo) @operator(len)
{
return fifo.count;
}
fn void? Fifo.sort(&fifo)
{
Type[] arr = allocator::new_array(fifo.allocator, Type, fifo.count);
defer allocator::free(fifo.allocator, arr);
foreach(i, c: fifo) {
arr[i] = c;
}
// doesn't keep ordering
//sort::quicksort(arr);
// seems to keep the right order but we will never know...
// also since most things are already ordered the time is closer to O(n) than to O(n^2)
sort::insertionsort(arr);
fifo.count = 0;
fifo.out = 0;
foreach (&c: arr) {
fifo.enqueue(c)!;
}
}

View File

@ -990,7 +990,12 @@ fn void Renderer.render_ugui(&self, CmdQueue* queue)
uint calls = 0; uint calls = 0;
uint off; uint off;
for (Cmd* cmd; (cmd = queue.dequeue() ?? null) != null;) { while (true) {
Cmd? cmd = queue.pop_first();
if (catch e = cmd) {
if (e != NO_MORE_ELEMENT) unreachable();
break;
}
switch (cmd.type) { switch (cmd.type) {
case CMD_UPDATE_ATLAS: case CMD_UPDATE_ATLAS:
// TODO: verify the correct type // TODO: verify the correct type
@ -1011,7 +1016,7 @@ fn void Renderer.render_ugui(&self, CmdQueue* queue)
uint count = 1; uint count = 1;
while (queue.len() != 0 && (queue.get(0).type == CMD_RECT || queue.get(0).type == CMD_SPRITE)) { while (queue.len() != 0 && (queue.get(0).type == CMD_RECT || queue.get(0).type == CMD_SPRITE)) {
count++; count++;
(void)queue.dequeue(); (void)queue.pop_first();
} }
self.draw_quads(off, count); self.draw_quads(off, count);
off += count; off += count;