summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app.hpp2
-rw-r--r--c2.cpp66
-rw-r--r--intermediate/ui.glsl23
-rw-r--r--ui.cpp605
-rw-r--r--ui.hpp124
-rw-r--r--video.cpp8
6 files changed, 379 insertions, 449 deletions
diff --git a/app.hpp b/app.hpp
index df16bd9..d26003a 100644
--- a/app.hpp
+++ b/app.hpp
@@ -1,7 +1,7 @@
#ifndef app_hpp
#define app_hpp
-#define app_memory_size (1024 * 1024 * 32)
+#define app_memory_size (1024 * 1024 * 512)
#include <new>
#include <stdint.h>
diff --git a/c2.cpp b/c2.cpp
index e8e6c82..3c862a6 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -17,7 +17,7 @@ extern "C" {
#define video_arena_size (1024 * 1024 * 16)
#define asset_arena_size (1024 * 1024 * 4)
-#define ui_arena_size (1024 * 16)
+#define ui_arena_size (1024 * 1024 * 64)
#define scene_arena_size (1024)
#define per_frame_memory_size (1024 * 1024)
@@ -645,6 +645,8 @@ struct C2 : public App {
Buffer_Id vbo, cbuf;
Sampler_Id clamped_linear;
Texture_Id hdr_target;
+ Texture_Id ui_texture;
+ Buffer_Id ui_buffer;
Line_Renderer lr;
World* world;
UI* ui;
@@ -683,6 +685,7 @@ struct C2 : public App {
dev = Device::create(&video_arena, this);
default_texture = make_default_texture(dev);
make_hdr_target();
+ make_ui_texture();
model_loader.init(dev, &assets);
mat_loader.init(&assets, default_texture);
register_asset_loader("MODL", &model_loader);
@@ -705,7 +708,7 @@ struct C2 : public App {
clamped_linear = create_clamped_linear(dev);
world = (World*)arena_alloc(arena, sizeof *world);
world->init(arena);
- ui = UI::create(dev, this, &ui_arena, ui_shader->id);
+ ui = UI::create(this, &ui_arena);
init_editor(ui, world);
lr.init(dev, &assets);
assert(per_frame != 0);
@@ -876,7 +879,39 @@ struct C2 : public App {
ctx.debug_pop();
ctx.debug_push("ui");
- ui->render(&frame_arena, dev->get_backbuffer());
+ ui->render(&frame_arena);
+ {
+ int s = ui->ren.bound.w * ui->ren.bound.h * 4;
+ void* pixels = dev->map_buffer(ui_buffer, 0, s);
+ memcpy(pixels, ui->ren.pixels, s);
+ dev->unmap_buffer(ui_buffer);
+ ctx.copy(ui_texture, ui_buffer);
+
+ pb.begin_rp();
+ pb.rp_target(dev->get_backbuffer(), Clear_Mode::restore);
+ Render_Pass& ui_pass = pb.build_rp();
+
+ pb.begin();
+ pb.shader(ui_shader->id);
+ pb.vertex_format(ui_shader->vf);
+ pb.blend(
+ Blend_Mode::add,
+ Blend_Factor::src_alpha,
+ Blend_Factor::inv_src_alpha
+ );
+ pb.texture(
+ ui_shader->descriptor_binding("atlas"),
+ ui_texture,
+ clamped_linear
+ );
+ Pipeline& ui_pip = pb.build();
+ quad.render(
+ ctx,
+ ui_pip,
+ ui_pass,
+ ui_shader->binding_index("verts")
+ );
+ }
ctx.debug_pop();
if (mjp(mbtn_left)) {
@@ -920,6 +955,8 @@ struct C2 : public App {
assets.destroy();
dev->destroy_texture(default_texture);
dev->destroy_texture(hdr_target);
+ dev->destroy_texture(ui_texture);
+ dev->destroy_buffer(ui_buffer);
dev->destroy_sampler(clamped_linear);
dev->destroy_buffer(vbo);
dev->destroy_buffer(cbuf);
@@ -930,7 +967,10 @@ struct C2 : public App {
ui->layout(w, h);
dev->on_resize();
dev->destroy_texture(hdr_target);
+ dev->destroy_texture(ui_texture);
+ dev->destroy_buffer(ui_buffer);
make_hdr_target();
+ make_ui_texture();
}
void make_hdr_target() {
@@ -947,6 +987,26 @@ struct C2 : public App {
);
}
+ void make_ui_texture() {
+ ui_texture = dev->create_texture(
+ "UI texture",
+ texture_format_rgba8i,
+ Texture_Flags::sampleable | Texture_Flags::copy_dst,
+ w,
+ h,
+ 1,
+ 1,
+ 1,
+ Buffer_Id(0)
+ );
+ ui_buffer = dev->create_buffer(
+ "UI Buffer",
+ w * h * 4,
+ Buffer_Flags::copy_src |
+ Buffer_Flags::cpu_readwrite
+ );
+ }
+
void on_text_input(const char* buf) override {
ui->text_input(buf);
}
diff --git a/intermediate/ui.glsl b/intermediate/ui.glsl
index 095d4df..7dd361d 100644
--- a/intermediate/ui.glsl
+++ b/intermediate/ui.glsl
@@ -13,28 +13,11 @@ type: vec2
[attribute]
name: uv
type: vec2
-[attribute]
-name: colour
-type: vec4
[interpolator]
-name: colour
-type: vec4
-[interpolator]
name: uv
type: vec2
-[struct]
-name: Config
-[variable]
-name: projection
-type: mat4
-
-[cbuffer]
-name: config_buffer
-type: Config
-stage: vertex
-
[texture]
name: atlas
stage: fragment
@@ -49,9 +32,8 @@ type: vec4
#ifdef VERTEX_SHADER
void main() {
- interpolator.colour = colour;
interpolator.uv = uv;
- gl_Position = config_buffer.projection * vec4(position, 0.0, 1.0);
+ gl_Position = vec4(position, 1.0, 1.0);
}
#endif
@@ -59,8 +41,7 @@ void main() {
#ifdef FRAGMENT_SHADER
void main() {
- vec4 c = texture(atlas, interpolator.uv).r.xxxx;
- c *= interpolator.colour;
+ vec4 c = texture(atlas, interpolator.uv).rgba;
colour = c;
}
diff --git a/ui.cpp b/ui.cpp
index 6b282f9..387b5ac 100644
--- a/ui.cpp
+++ b/ui.cpp
@@ -14,6 +14,8 @@ extern "C" {
#define vertex_buffer_count (2048)
#define ui_padding 5
+#define DEBUG_CLEARS 0
+
static constexpr int font_w = 960;
static unsigned font_data[] = {
0x00000000, 0x00003000, 0x00000000, 0x00000000, 0x00000000,
@@ -78,58 +80,6 @@ static unsigned font_data[] = {
0x0003c01e, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};
-static Texture_Id create_atlas(Device* d) {
- int x, y;
- int w = font_w + 10;
- int size = 10 * w;
- Buffer_Id buf = d->create_buffer(
- "font atlas stage",
- size,
- Buffer_Flags::copy_src |
- Buffer_Flags::cpu_readwrite
- );
- Texture_Id tex;
- uint8_t* pixels = (uint8_t*)d->map_buffer(buf, 0, size);
- for (y = 0; y < 10; y++) {
- for (x = 0; x < font_w; x++) {
- int si = x + y * font_w;
- int di = x + y * w;
- unsigned bits = font_data[si >> 5];
- int bit = bits & 1 << (si & 0x1f);
- pixels[di] = bit? 0xff: 0x00;
- }
- }
- /* for solid colours, one white square at the end */
- for (y = 0; y < 10; y++) {
- for (x = font_w; x < w; x++) {
- pixels[x + y * w] = 0xff;
- }
- }
- d->unmap_buffer(buf);
- tex = d->create_texture(
- "font atlas",
- texture_format_r8i,
- Texture_Flags::sampleable | Texture_Flags::copy_dst,
- w,
- 10,
- 1,
- 1,
- 1,
- buf
- );
- d->destroy_bufferi(buf);
- return tex;
-}
-
-static Sampler_Id create_clamped_point(Device* dev) {
- Sampler_State s{};
- s.min = Filter_Mode::point;
- s.mag = Filter_Mode::point;
- s.address_u = Address_Mode::clamp;
- s.address_v = Address_Mode::clamp;
- return dev->create_sampler("clamped point", s);
-}
-
UI::Colour::Colour(unsigned rgb, uint8_t a):
r((rgb >> 16) & 0xff),
g((rgb >> 8) & 0xff),
@@ -157,6 +107,30 @@ void UI::Rect::clip(const Rect& other) {
if (h < 0) h = 0;
}
+void UI::Rect::clip_src(const Rect& other, Rect& src) {
+ int n;
+ if ((n = other.x - x) > 0) {
+ w -= n;
+ x += n;
+ src.w -= n;
+ src.x += n;
+ }
+ if ((n = other.y - y) > 0) {
+ h -= n;
+ y += n;
+ src.h -= n;
+ src.y += n;
+ }
+ if ((n = x + w - (other.x + other.w)) > 0) {
+ w -= n;
+ src.w -= n;
+ }
+ if ((n = y + h - (other.y + other.h)) > 0) {
+ h -= n;
+ src.h -= n;
+ }
+}
+
void UI::Rect::shrink(int a) {
x += a;
y += a;
@@ -170,236 +144,248 @@ bool UI::Rect::contains(int px, int py) {
return px >= x && py >= y && px < x + w && py < y + h;
}
-void UI::Vertex_Buffer::init(Device* dev) {
- buf.init(
- dev,
- "UI mesh",
- vertex_buffer_count * sizeof(Vertex) * 4,
- Buffer_Flags::vertex_buffer
- );
- init_indices(dev);
- usage = 0;
- start = 0;
- next = 0;
-}
-
-void UI::Vertex_Buffer::init_indices(Device* dev) {
- auto create_ind = [](uint16_t* target){
- int i, i2, e = vertex_buffer_count * 6;
- for (i = 0, i2 = 0; i < e; i += 6, i2 += 4) {
- target[i ] = (uint16_t)(i2 );
- target[i + 1] = (uint16_t)(i2 + 1);
- target[i + 2] = (uint16_t)(i2 + 2);
- target[i + 3] = (uint16_t)(i2 + 1);
- target[i + 4] = (uint16_t)(i2 + 3);
- target[i + 5] = (uint16_t)(i2 + 2);
- }
- };
- int s = vertex_buffer_count * 6 * sizeof(uint16_t);
- Buffer_Id stage = dev->create_buffer(
- "UI mesh indices stage",
- s,
- Buffer_Flags::copy_src |
- Buffer_Flags::cpu_readwrite
- );
- void* mem = dev->map_buffer(stage, 0, s);
- create_ind((uint16_t*)mem);
- indices = dev->create_buffer(
- "UI indices",
- s,
- Buffer_Flags::copy_dst |
- Buffer_Flags::index_buffer
- );
- Context& ctx = dev->acquire();
- ctx.copy(indices, stage);
- dev->submit(ctx);
- dev->unmap_buffer(stage);
- dev->destroy_bufferi(stage);
-}
-
-void UI::Vertex_Buffer::destroy(UI* ui) {
- Device* dev = ui->device;
- if (next) {
- next->destroy(ui);
- heap_free(ui->heap, next);
- }
- dev->destroy_buffer(indices);
- buf.destroy(dev);
+static inline UI::Colour blend(UI::Colour dst, UI::Colour src) {
+ int ia;
+ ia = 0xff - src.a;
+ dst.r = (uint8_t)(((src.r * src.a) + (dst.r * ia)) >> 8);
+ dst.g = (uint8_t)(((src.g * src.a) + (dst.g * ia)) >> 8);
+ dst.b = (uint8_t)(((src.b * src.a) + (dst.b * ia)) >> 8);
+ dst.a = (uint8_t)(((src.a * src.a) + (dst.a * ia)) >> 8);
+ return dst;
}
-void UI::Vertex_Buffer::add_quad(
- UI* ui,
+
+void UI::Renderer::blit_rect(
int x,
int y,
int w,
int h,
- float u0,
- float v0,
- float u1,
- float v1,
Colour col
) {
- Vertex* verts;
- int index = usage * 4;
- int* scissor = ui->pipeline->scissor;
- float r, g, b, a;
- if (usage >= vertex_buffer_count) {
- if (!next) {
- next = (Vertex_Buffer*)heap_alloc(ui->heap, sizeof *next);
- next->init(ui->device);
+ int i, j, ex, ey, s;
+ Rect r = { x, y, w, h };
+ r.clip(clip);
+ Colour* dst = pixels + r.x + r.y * bound.w;
+ ex = r.x + r.w;
+ ey = r.y + r.h;
+ s = bound.w - r.w;
+ for (j = r.y; j < ey; j++) {
+ for (i = r.x; i < ex; i++) {
+ *dst = blend(*dst, col);
+ dst++;
}
- next->add_quad(ui, x, y, w, h, u0, v0, u1, v1, col);
- return;
+ dst += s;
}
- if (
- clip.x < scissor[0] ||
- clip.y < scissor[1] ||
- clip.x + clip.w > scissor[0] + scissor[2] ||
- clip.y + clip.h > scissor[1] + scissor[3] ||
- ((
- clip.x != scissor[0] ||
- clip.y != scissor[1] ||
- clip.w != scissor[2] ||
- clip.h != scissor[3]
- ) && (
- x < clip.x ||
- y < clip.y ||
- x + w > clip.x + clip.w ||
- y + h > clip.y + clip.h
- ))
- ) {
- ui->mesh.draw(
- ui,
- ui->device->get_ctx(),
- *ui->pipeline,
- *ui->render_pass
- );
- scissor[0] = clip.x;
- scissor[1] = clip.y;
- scissor[2] = clip.w;
- scissor[3] = clip.h;
- ui->pipeline->hash();
+}
+
+void UI::Renderer::blit_char(char ch, int x, int y, Colour col) {
+ Rect re, su;
+ int i, j, sx, sy, ex, ey, s;
+ Colour* dst;
+ re.x = x;
+ re.y = y;
+ re.w = 10;
+ re.h = 10;
+ su.x = (ch - ' ') * 10;
+ su.y = 0;
+ su.w = 10;
+ su.h = 10;
+ re.clip_src(clip, su);
+ ex = re.x + re.w;
+ ey = re.y + re.h;
+ dst = pixels + re.x + re.y * bound.w;
+ s = bound.w - re.w;
+ for (j = re.y, sy = su.y; j < ey; j++, sy++) {
+ for (i = re.x, sx = su.x; i < ex; i++, sx++) {
+ int si = (sx + sy * font_w);
+ int bit = (1 << (si & 0x1f));
+ bit &= font_data[si >> 5];
+ if (bit)
+ *dst = blend(*dst, col);
+ dst++;
+ }
+ dst += s;
}
- r = col.r_f();
- g = col.g_f();
- b = col.b_f();
- a = col.a_f();
- verts = &((Vertex*)buf.map(ui->device))[index];
- verts[0] = Vertex { (float)x, (float)y, u0, v0, r, g, b, a };
- verts[1] = Vertex { (float)x + w, (float)y, u1, v0, r, g, b, a };
- verts[2] = Vertex { (float)x, (float)y + h, u0, v1, r, g, b, a };
- verts[3] = Vertex { (float)x + w, (float)y + h, u1, v1, r, g, b, a };
- buf.unmap(ui->device);
- usage++;
-}
-
-void UI::Vertex_Buffer::add_rect(
- UI* ui,
+}
+
+UI::Renderer::Cmd* UI::Renderer::add_cmd(int size) {
+ Cmd* r;
+ size = align_size(size, 8);
+ assert(cmd_buf_ptr + size <= cmd_buf_size);
+ r = (Cmd*)&cmd_buf[cmd_buf_ptr];
+ r->size = size;
+ cmd_buf_ptr += size;
+ return r;
+}
+
+void UI::Renderer::commit_cmd(Cmd* c) {
+ int x1 = std::min(c->r.x / grid_cell_size[0], grid_size);
+ int y1 = std::min(c->r.y / grid_cell_size[1], grid_size);
+ int x2 = std::min((c->r.x + c->r.w + grid_cell_size[0]) / grid_cell_size[0], grid_size);
+ int y2 = std::min((c->r.y + c->r.h + grid_cell_size[1]) / grid_cell_size[1], grid_size);
+ int s = grid_size - (x2 - x1);
+ uint64_t* h = grid + x1 + y1 * grid_size;
+ int i, j;
+ for (j = y1; j < y2; j++) {
+ for (i = x1; i < x2; i++) {
+ *h = fnv1a64_2(*h, (uint8_t*)c, c->size);
+ h++;
+ }
+ h += s;
+ }
+}
+
+void UI::Renderer::add_rect(
int x,
int y,
int w,
int h,
Colour col
) {
- constexpr float white_uv_x = (float)font_w / (float)(font_w + 10);
- add_quad(ui, x, y, w, h, white_uv_x, 0.0f, 1.0f, 1.0f, col);
+ Cmd* c = add_cmd(sizeof *c);
+ c->type = Cmd::RECT;
+ c->col = col;
+ c->r.x = x;
+ c->r.y = y;
+ c->r.w = w;
+ c->r.h = h;
+ commit_cmd(c);
}
-void UI::Vertex_Buffer::add_char(
- UI* ui,
+void UI::Renderer::add_text(
int x,
int y,
- char ch,
+ const char* txt,
Colour col
) {
- int off = (ch - ' ') * 10;
- float w = (float)(font_w + 10);
- float u0 = (float)off / w;
- float u1 = u0 + (10.0f / w);
- add_quad(ui, x, y, 10, 10, u0, 0.0f, u1, 1.0f, col);
+ int len = string_len(txt);
+ Cmd* c = add_cmd(sizeof *c + len + 1);
+ c->type = Cmd::TEXT;
+ c->col = col;
+ c->r.x = x;
+ c->r.y = y;
+ c->r.w = 10 * len;
+ c->r.h = 10;
+ string_copy((char*)(c + 1), txt);
+ commit_cmd(c);
+}
+
+void UI::Renderer::reset(const Rect& cl) {
+ int i, e;
+ uint64_t* dst = grid;
+ clip = cl;
+ e = grid_size * grid_size;
+ for (i = 0; i < e; i++, dst++)
+ *dst = fnv1a64(0, 0);
+ grid_cell_size[0] = cl.w / grid_size;
+ grid_cell_size[1] = cl.h / grid_size;
+ cmd_buf_ptr = 0;
+}
+
+void UI::Renderer::set_clip(const Rect& r) {
+ Cmd* c = add_cmd(sizeof *c);
+ c->type = Cmd::CLIP;
+ c->col = Colour(0, 0);
+ c->r = r;
+ clip = r;
}
-void UI::Vertex_Buffer::add_text(
- UI* ui,
- int x,
- int y,
- const char* txt,
- Colour col
-) {
- for (; *txt; txt++, x += 10)
- add_char(ui, x, y, *txt, col);
+void UI::Renderer::clear(const Rect& r) {
+ int x, y;
+ int ex = r.x + r.w;
+ int ey = r.y + r.h;
+ int s = bound.w - r.w;
+ Colour* dst = pixels + r.x + r.y * bound.w;
+#if DEBUG_CLEARS
+ Colour col(rand(), 0x30);
+#else
+ Colour col(0x000000, 0x00);
+#endif
+ for (y = r.y; y < ey; y++) {
+ for (x = r.x; x < ex; x++) {
+ *dst = col;
+ dst++;
+ }
+ dst += s;
+ }
}
-void UI::Vertex_Buffer::update_buffer(Context& ctx) {
- buf.update(ctx);
+const App* g_app;
+void UI::Renderer::flush(int x, int y) {
+ Cmd* cmd = (Cmd*)cmd_buf;
+ Cmd* last = (Cmd*)(cmd_buf + cmd_buf_ptr);
+ Rect cell = Rect(
+ x * grid_cell_size[0],
+ y * grid_cell_size[1],
+ grid_cell_size[0],
+ grid_cell_size[1]
+ );
+ clip = cell;
+ clear(cell);
+ while (cmd != last) {
+ switch (cmd->type) {
+ case Cmd::RECT: {
+ Rect& r = cmd->r;
+ blit_rect(r.x, r.y, r.w, r.h, cmd->col);
+ } break;
+ case Cmd::TEXT: {
+ int x = cmd->r.x;
+ char* txt = (char*)(cmd + 1);
+ for (; *txt; txt++, x += 10)
+ blit_char(*txt, x, cmd->r.y, cmd->col);
+ } break;
+ case Cmd::CLIP: {
+ clip = cmd->r;
+ clip.clip(cell);
+ break;
+ }
+ }
+ cmd = (Cmd*)((uint8_t*)cmd + cmd->size);
+ }
}
-void UI::Vertex_Buffer::reset(const Rect& c) {
- start = 0;
- usage = 0;
- dirty = true;
- clip = c;
- if (next)
- next->reset(c);
+void UI::Renderer::flush() {
+ uint64_t* next = grid == grid_a? grid_b: grid_a;
+ uint64_t* h = grid;
+ uint64_t* p = next;
+ int i, j;
+ for (j = 0; j < grid_size; j++) {
+ for (i = 0; i < grid_size; i++) {
+ if (*p != *h) {
+ flush(i, j);
+ }
+ h++;
+ p++;
+ }
+ }
+ grid = next;
}
-void UI::Vertex_Buffer::set_clip(const Rect& r) {
- clip = r;
- assert(r.x >= 0 && r.y >= 0);
- assert(r.w >= 0 && r.h >= 0);
- if (next)
- next->set_clip(r);
+void UI::Renderer::resize(int w, int h) {
+ heap_free(arena, pixels);
+ pixels = (Colour*)heap_alloc(arena, w * h * sizeof *pixels);
+ assert(pixels != 0);
+ bound = Rect(0, 0, w, h);
}
-void UI::Vertex_Buffer::draw(
- UI* ui,
- Context& ctx,
- Pipeline& pip,
- Render_Pass& rp
-) {
- if (usage == start) {
- if (next)
- next->draw(ui, ctx, pip, rp);
- return;
- }
- if (dirty) {
- update_buffer(ctx);
- dirty = false;
- }
- Vertex_Buffer_Binding binding[] = {{
- .id = buf.gpuonly,
- .offset = 0,
- .target = ui->shader_info.vert_binding
- }, {}};
- Index_Buffer_Binding indb = {
- .id = indices,
- .offset = 0
- };
- Draw d{};
- d.verts = binding;
- d.inds = indb;
- d.vertex_count = (usage - start) * 6;
- d.instance_count = 1;
- d.first_vertex = start * 6;
- ctx.submit(d, pip, rp);
- if (next)
- next->draw(ui, ctx, pip, rp);
- start = usage;
+void UI::Renderer::init(Heap* heap, int w, int h) {
+ arena = heap;
+ pixels = (Colour*)heap_alloc(heap, w * h * sizeof *pixels);
+ assert(pixels != 0);
+ bound = Rect(0, 0, w, h);
+ grid = grid_a;
}
UI* UI::create(
- Device* dev,
const App* app,
- Arena* a,
- Shader_Id sh
+ Arena* a
) {
int hs;
- Texture_Id atlas = create_atlas(dev);
UI* u = (UI*)arena_alloc(a, sizeof *u);
Heap* h = (Heap*)arena_alloc(a, sizeof *h);
hs = a->size - a->ptr - allocation_default_alignment - 1;
init_heap(h, arena_alloc(a, hs), hs);
- u->init(dev, app, h, atlas, sh);
+ u->init(app, h);
return u;
}
@@ -415,44 +401,21 @@ int UI::text_height(const char* t) {
}
void UI::init(
- Device* dev,
const App* a,
- Heap* h,
- Texture_Id at,
- Shader_Id sh
+ Heap* h
) {
- Shader* sp;
heap = h;
- device = dev;
app = a;
- atlas = at;
- shader = sh;
hot = 0;
hovered = 0;
active = 0;
- mesh.init(device);
- cbuffer.init(
- device,
- "UI CBuffer",
- sizeof(UI_CBuffer),
- Buffer_Flags::constant_buffer
- );
- sp = &dev->get_shader(sh);
- vertex_format = sp->vf;
- shader_info.vert_binding = sp->binding_index("verts");
- shader_info.atlas_binding = sp->descriptor_binding("atlas");
- shader_info.config_binding = sp->descriptor_binding("config_buffer");
- sampler = create_clamped_point(device);
+ ren.init(heap, a->w, a->h);
root = create_element<Container>(0);
((Container*)root)->padding = 0;
}
void UI::destroy() {
root->destroy();
- device->destroy_texture(atlas);
- device->destroy_sampler(sampler);
- mesh.destroy(this);
- cbuffer.destroy(device);
}
void UI::layout(int w, int h) {
@@ -516,93 +479,60 @@ void UI::update(Arena* s) {
layout(area.w, area.h);
}
-void UI::render(Arena* s, Texture_Id target) {
- Context& ctx = device->get_ctx();
- Texture& t = device->get_texture(target);
- UI_CBuffer* config = (UI_CBuffer*)cbuffer.map(device);
- config->projection = m4f::orth(
- 0.0f, (float)t.w,
- 0.0f, (float)t.h,
- -1.0f,
- 1.0f
- );
- cbuffer.unmap(device);
- cbuffer.update(ctx);
-
- Pipeline_Builder pb(s, device);
- pb.begin_rp();
- pb.rp_target(device->get_backbuffer(), Clear_Mode::restore);
- render_pass = &pb.build_rp();
-
- pb.begin();
- pb.shader(shader);
- pb.vertex_format(vertex_format);
- pb.blend(
- Blend_Mode::add,
- Blend_Factor::src_alpha,
- Blend_Factor::inv_src_alpha
- );
- pb.cbuffer(shader_info.config_binding, cbuffer.gpuonly);
- pb.texture(shader_info.atlas_binding, atlas, sampler);
- pipeline = &pb.build();
-
+void UI::render(Arena* s) {
+ if (area.w != ren.bound.w || area.h != ren.bound.h)
+ ren.resize(area.w, area.h);
+ ren.reset(ren.bound);
root->render();
- mesh.draw(this, ctx, *pipeline, *render_pass);
- mesh.reset(Rect(0, 0, t.w, t.h));
+ g_app = app;
+ ren.flush();
}
void UI::draw_container(const Rect& bound, Colour c) {
/* todo line function lmao */
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x,
bound.y,
bound.w,
bound.h,
c
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x,
bound.y,
bound.w,
1,
0x000000
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x + 1,
bound.y + 1,
bound.w - 1,
1,
0xa7a7a7
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x,
bound.y,
1,
bound.h,
0x000000
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x + 1,
bound.y + 1,
1,
bound.h - 1,
0xa7a7a7
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x + bound.w - 1,
bound.y + 1,
1,
bound.h - 2,
0x000000
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x + 1,
bound.y + bound.h - 1,
bound.w - 1,
@@ -612,56 +542,49 @@ void UI::draw_container(const Rect& bound, Colour c) {
}
void UI::draw_containeri(const Rect& bound, Colour c) {
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x,
bound.y,
bound.w,
bound.h,
c
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x,
bound.y,
bound.w,
1,
0x000000
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x + 1,
bound.y + bound.h - 2,
bound.w - 2,
1,
0xa7a7a7
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x,
bound.y,
1,
bound.h,
0x000000
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x + bound.w - 2,
bound.y + 1,
1,
bound.h - 2,
0xa7a7a7
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x + bound.w - 1,
bound.y + 1,
1,
bound.h - 2,
0x000000
);
- mesh.add_rect(
- this,
+ ren.add_rect(
bound.x + 1,
bound.y + bound.h - 1,
bound.w - 1,
@@ -728,12 +651,12 @@ void UI::Element::on_update() {
void UI::Element::render() {
Element* child;
- Rect old_clip = ui->mesh.clip;
+ Rect old_clip = ui->ren.clip;
on_render();
for (child = children; child; child = child->next) {
child->render();
}
- ui->mesh.clip = old_clip;
+ ui->ren.set_clip(old_clip);
}
void UI::Element::on_message(const Message& msg) {
@@ -838,7 +761,7 @@ UI::Rect UI::Container::layout(const Rect& avail) {
}
void UI::Container::on_render() {
- ui->mesh.set_clip(clip);
+ ui->ren.set_clip(clip);
}
UI::Table::Table(UI* ui, Element* parent, const int* rs):
@@ -921,7 +844,7 @@ UI::Rect UI::Toolbar::layout(const Rect& avail) {
}
void UI::Toolbar::on_render() {
- ui->mesh.set_clip(clip);
+ ui->ren.set_clip(clip);
ui->draw_container(
bound,
0xa7a7a7
@@ -958,9 +881,8 @@ void UI::Button::on_render() {
ui->draw_containeri(bound, 0xffffff);
} else
ui->draw_container(bound, 0xffffff);
- ui->mesh.set_clip(clip);
- ui->mesh.add_text(
- ui,
+ ui->ren.set_clip(clip);
+ ui->ren.add_text(
bound.x + ui_padding + toff[0],
bound.y + ui_padding + toff[1],
text,
@@ -1014,8 +936,7 @@ void UI::Input::on_render() {
if ((n = c.x - (clip.x + clip.w)) > 0)
tx -= n;
c.x = tx + w;
- ui->mesh.add_rect(
- ui,
+ ui->ren.add_rect(
c.x,
c.y,
c.w,
@@ -1024,9 +945,8 @@ void UI::Input::on_render() {
);
}
if (buf) {
- ui->mesh.set_clip(clip);
- ui->mesh.add_text(
- ui,
+ ui->ren.set_clip(clip);
+ ui->ren.add_text(
tx,
bound.y + ui_padding,
buf,
@@ -1155,16 +1075,14 @@ void UI::Slider::on_render() {
hc = 0x4f4f4f;
Rect sr = track_rect();
Rect ha = handle_rect();
- ui->mesh.add_rect(
- ui,
+ ui->ren.add_rect(
sr.x,
sr.y,
sr.w,
sr.h,
0xa7a7a7
);
- ui->mesh.add_rect(
- ui,
+ ui->ren.add_rect(
ha.x,
ha.y,
ha.w,
@@ -1271,9 +1189,8 @@ UI::Rect UI::Label::layout(const Rect& avail) {
}
void UI::Label::on_render() {
- ui->mesh.set_clip(clip);
- ui->mesh.add_text(
- ui,
+ ui->ren.set_clip(clip);
+ ui->ren.add_text(
bound.x + ui_padding,
bound.y + ui_padding,
text,
@@ -1363,7 +1280,7 @@ UI::Rect UI::Modal::layout(const Rect& avail) {
}
void UI::Modal::on_render() {
- ui->mesh.set_clip(clip);
+ ui->ren.set_clip(clip);
ui->draw_container(
contents->bound,
Colour(0xffffff, 0x80)
diff --git a/ui.hpp b/ui.hpp
index ea51717..37726cb 100644
--- a/ui.hpp
+++ b/ui.hpp
@@ -3,16 +3,12 @@
#include "app.hpp"
#include "maths.hpp"
-#include "video.hpp"
#include <new>
struct Arena;
+struct Heap;
struct UI {
- struct Vertex {
- float x, y, u, v, r, g, b, a;
- };
-
struct Colour {
uint8_t r, g, b, a;
Colour(unsigned rgb, uint8_t a = 0xff);
@@ -29,109 +25,77 @@ struct UI {
Rect(int x, int y, int w, int h);
void clip(const Rect& other);
+ void clip_src(const Rect& other, Rect& src);
void shrink(int a);
bool contains(int px, int py);
};
- struct Vertex_Buffer {
+ struct Renderer {
+ static constexpr int grid_size = 16;
+ static constexpr int cmd_buf_size = 1024 * 8;
+ Rect bound;
Rect clip;
- bool dirty;
- Staged_Buffer buf;
- Buffer_Id indices;
- int start, usage;
-
- void init(Device* dev);
- void init_indices(Device* dev);
- void destroy(UI* ui);
- void update_buffer(Context& ctx);
- void reset(const Rect& clip);
- void set_clip(const Rect& clip);
-
- void add_quad(
- UI* ui,
- int x,
- int y,
- int w,
- int h,
- float u0,
- float v0,
- float u1,
- float v1,
- Colour col
- );
- void add_rect(
- UI* ui,
- int x,
- int y,
- int w,
- int h,
- Colour col
- );
- void add_char(UI* ui, int x, int y, char ch, Colour col);
- void add_text(
- UI* ui,
- int x,
- int y,
- const char* txt,
- Colour col
- );
- void draw(
- UI* ui,
- Context& ctx,
- Pipeline& pip,
- Render_Pass& rp
- );
- Vertex_Buffer* next;
- };
+ Colour* pixels;
+ Heap* arena;
+ uint8_t cmd_buf[cmd_buf_size];
+ int cmd_buf_ptr;
+ int grid_cell_size[2];
+ uint64_t grid_a[grid_size * grid_size];
+ uint64_t grid_b[grid_size * grid_size];
+ uint64_t* grid;
+
+ struct Cmd {
+ enum {
+ RECT,
+ TEXT,
+ CLIP
+ };
+ int type, size;
+ Colour col;
+ Rect r;
+ };
+
+ void blit_rect(int x, int y, int w, int h, Colour col);
+ void blit_char(char ch, int x, int y, Colour col);
+
+ Cmd* add_cmd(int size);
+ void commit_cmd(Cmd* c);
+ void add_rect(int x, int y, int w, int h, Colour col);
+ void add_text(int x, int y, const char* txt, Colour col);
+ void reset(const Rect& cl);
+ void set_clip(const Rect& r);
+ void clear(const Rect& r);
+ void flush(int x, int y);
+ void flush();
+ void resize(int w, int h);
+ void init(Heap* heap, int w, int h);
+ } ren;
struct Element;
Heap* heap;
- Device* device;
const App* app;
- Texture_Id atlas;
- Shader_Id shader;
- Vertex_Format_Id vertex_format;
- Sampler_Id sampler;
- Staged_Buffer cbuffer;
- Vertex_Buffer mesh;
- Pipeline* pipeline;
- Render_Pass* render_pass;
Element* root, * hot, * hovered, * active;
Rect area;
bool layout_dirty;
- struct UI_CBuffer {
- m4f projection;
- };
- struct {
- int vert_binding;
- int atlas_binding;
- int config_binding;
- } shader_info;
-
static int text_width(const char* t);
static int text_height(const char* t);
static UI* create(
- Device* dev,
const App* app,
- Arena* a,
- Shader_Id sh
+ Arena* a
);
void init(
- Device* dev,
const App* app,
- Heap* h,
- Texture_Id atlas,
- Shader_Id sh
+ Heap* h
);
void destroy();
void layout(int w, int h);
void text_input(const char* buf);
void update(Arena* s);
- void render(Arena* s, Texture_Id target);
+ void render(Arena* s);
void draw_container(const Rect& r, Colour c);
void draw_containeri(const Rect& r, Colour c);
diff --git a/video.cpp b/video.cpp
index 6d52a57..82dd0f7 100644
--- a/video.cpp
+++ b/video.cpp
@@ -2455,6 +2455,14 @@ void Context::transition(Texture_Id id, Resource_State state) {
src_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
dst_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} else if (
+ src_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL &&
+ dst_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
+ ) {
+ b.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ b.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ src_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ dst_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ } else if (
src_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
dst_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
) {