WIP: lunasvg implementation, things stopped working

This commit is contained in:
2026-03-03 14:01:22 -05:00
parent 19bf78d635
commit 2703bbd901
80 changed files with 38694 additions and 12 deletions

View File

@@ -1,5 +1,6 @@
#include "renderer/renderer.h"
#include "ui/ui_core.h"
#include "ui/ui_icons.h"
#include <d3d12.h>
#include <dxgi1_5.h>
@@ -201,6 +202,10 @@ struct Renderer {
F32 font_atlas_size; // font size the atlas was built at
F32 font_line_height;
// Icon atlas
ID3D12Resource *icon_texture;
ID3D12DescriptorHeap *icon_srv_heap;
// GDI text measurement
HDC measure_dc;
HFONT measure_font;
@@ -976,7 +981,7 @@ static void emit_text_glyphs(DrawBatch *batch, Renderer *r,
////////////////////////////////
// Flush helper: issues a draw call for accumulated vertices, then resets batch
static void flush_batch(Renderer *r, DrawBatch *batch, UINT buf_idx) {
static void flush_batch(Renderer *r, DrawBatch *batch, UINT buf_idx, ID3D12DescriptorHeap *tex_heap = nullptr) {
if (batch->index_count == 0) return;
r->command_list->SetPipelineState(r->pipeline_state);
@@ -985,10 +990,11 @@ static void flush_batch(Renderer *r, DrawBatch *batch, UINT buf_idx) {
float constants[4] = { (float)r->width, (float)r->height, 0, 0 };
r->command_list->SetGraphicsRoot32BitConstants(0, 4, constants, 0);
// Bind font texture
r->command_list->SetDescriptorHeaps(1, &r->srv_heap);
// Bind texture (font or icon)
ID3D12DescriptorHeap *heap = tex_heap ? tex_heap : r->srv_heap;
r->command_list->SetDescriptorHeaps(1, &heap);
r->command_list->SetGraphicsRootDescriptorTable(1,
r->srv_heap->GetGPUDescriptorHandleForHeapStart());
heap->GetGPUDescriptorHandleForHeapStart());
r->command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
@@ -1053,6 +1059,8 @@ void renderer_destroy(Renderer *r) {
if (r->index_buffers[i]) r->index_buffers[i]->Release();
}
if (r->font_texture) r->font_texture->Release();
if (r->icon_texture) r->icon_texture->Release();
if (r->icon_srv_heap) r->icon_srv_heap->Release();
if (r->pipeline_state) r->pipeline_state->Release();
if (r->root_signature) r->root_signature->Release();
@@ -1133,6 +1141,23 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
batch.vertex_count = 0;
batch.index_count = 0;
// Track which texture is currently bound (0 = font, 1 = icon)
int bound_texture = 0;
auto bind_font = [&]() {
if (bound_texture != 0) {
flush_batch(r, &batch, buf_idx, r->srv_heap);
bound_texture = 0;
}
};
auto bind_icon = [&]() {
if (bound_texture != 1 && r->icon_srv_heap) {
flush_batch(r, &batch, buf_idx);
bound_texture = 1;
}
};
for (int32_t i = 0; i < render_commands.length; i++) {
Clay_RenderCommand *cmd = Clay_RenderCommandArray_Get(&render_commands, i);
Clay_BoundingBox bb = cmd->boundingBox;
@@ -1177,6 +1202,7 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
} break;
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
bind_font();
Clay_TextRenderData *text = &cmd->renderData.text;
emit_text_glyphs(&batch, r, bb, text->textColor,
text->stringContents.chars, text->stringContents.length,
@@ -1185,7 +1211,8 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: {
// Flush before changing scissor
flush_batch(r, &batch, buf_idx);
ID3D12DescriptorHeap *heap = bound_texture == 1 ? r->icon_srv_heap : r->srv_heap;
flush_batch(r, &batch, buf_idx, heap);
D3D12_RECT clip = {};
clip.left = (LONG)Max(bb.x, 0.f);
clip.top = (LONG)Max(bb.y, 0.f);
@@ -1197,7 +1224,8 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
} break;
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
flush_batch(r, &batch, buf_idx);
ID3D12DescriptorHeap *heap = bound_texture == 1 ? r->icon_srv_heap : r->srv_heap;
flush_batch(r, &batch, buf_idx, heap);
D3D12_RECT full_scissor = { 0, 0, (LONG)r->width, (LONG)r->height };
r->command_list->RSSetScissorRects(1, &full_scissor);
} break;
@@ -1207,6 +1235,7 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
if (custom->customData) {
CustomRenderType type = *(CustomRenderType *)custom->customData;
if (type == CUSTOM_RENDER_VGRADIENT) {
bind_font();
CustomGradientData *grad = (CustomGradientData *)custom->customData;
Clay_Color tc = grad->top_color;
Clay_Color bc = grad->bottom_color;
@@ -1217,6 +1246,20 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
custom->cornerRadius.topLeft, custom->cornerRadius.topRight,
custom->cornerRadius.bottomRight, custom->cornerRadius.bottomLeft,
1.0f);
} else if (type == CUSTOM_RENDER_ICON) {
bind_icon();
CustomIconData *icon = (CustomIconData *)custom->customData;
Clay_Color c = icon->color;
float cr = c.r / 255.f, cg = c.g / 255.f;
float cb = c.b / 255.f, ca = c.a / 255.f;
UI_IconInfo *info = &g_icons[icon->icon_id];
emit_quad(&batch,
bb.x, bb.y, bb.x + bb.width, bb.y + bb.height,
info->u0, info->v0, info->u1, info->v1,
cr, cg, cb, ca,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 1.0f);
}
}
} break;
@@ -1228,7 +1271,8 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
}
// Flush remaining
flush_batch(r, &batch, buf_idx);
ID3D12DescriptorHeap *heap = bound_texture == 1 ? r->icon_srv_heap : r->srv_heap;
flush_batch(r, &batch, buf_idx, heap);
}
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
@@ -1245,6 +1289,101 @@ void renderer_end_frame(Renderer *r, Clay_RenderCommandArray render_commands) {
r->frame_index++;
}
void renderer_create_icon_atlas(Renderer *r, const uint8_t *data, int32_t w, int32_t h) {
// Create texture resource
D3D12_HEAP_PROPERTIES heap_props = {};
heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
D3D12_RESOURCE_DESC tex_desc = {};
tex_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
tex_desc.Width = w;
tex_desc.Height = h;
tex_desc.DepthOrArraySize = 1;
tex_desc.MipLevels = 1;
tex_desc.Format = DXGI_FORMAT_R8_UNORM;
tex_desc.SampleDesc.Count = 1;
tex_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
r->device->CreateCommittedResource(&heap_props, D3D12_HEAP_FLAG_NONE,
&tex_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
IID_PPV_ARGS(&r->icon_texture));
// Upload via staging buffer
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = {};
UINT64 total_bytes = 0;
r->device->GetCopyableFootprints(&tex_desc, 0, 1, 0, &footprint, nullptr, nullptr, &total_bytes);
D3D12_HEAP_PROPERTIES upload_heap = {};
upload_heap.Type = D3D12_HEAP_TYPE_UPLOAD;
D3D12_RESOURCE_DESC upload_desc = {};
upload_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
upload_desc.Width = total_bytes;
upload_desc.Height = 1;
upload_desc.DepthOrArraySize = 1;
upload_desc.MipLevels = 1;
upload_desc.SampleDesc.Count = 1;
upload_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
ID3D12Resource *upload_buf = nullptr;
r->device->CreateCommittedResource(&upload_heap, D3D12_HEAP_FLAG_NONE,
&upload_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
IID_PPV_ARGS(&upload_buf));
void *mapped = nullptr;
D3D12_RANGE read_range = {0, 0};
upload_buf->Map(0, &read_range, &mapped);
U8 *dst = (U8 *)mapped;
for (int y = 0; y < h; y++) {
memcpy(dst + y * footprint.Footprint.RowPitch, data + y * w, w);
}
upload_buf->Unmap(0, nullptr);
r->frames[0].command_allocator->Reset();
r->command_list->Reset(r->frames[0].command_allocator, nullptr);
D3D12_TEXTURE_COPY_LOCATION src_loc = {};
src_loc.pResource = upload_buf;
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
src_loc.PlacedFootprint = footprint;
D3D12_TEXTURE_COPY_LOCATION dst_loc = {};
dst_loc.pResource = r->icon_texture;
dst_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst_loc.SubresourceIndex = 0;
r->command_list->CopyTextureRegion(&dst_loc, 0, 0, 0, &src_loc, nullptr);
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Transition.pResource = r->icon_texture;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
r->command_list->ResourceBarrier(1, &barrier);
r->command_list->Close();
r->command_queue->ExecuteCommandLists(1, (ID3D12CommandList *const *)&r->command_list);
wait_for_pending(r);
upload_buf->Release();
// Create separate SRV heap for icon texture
D3D12_DESCRIPTOR_HEAP_DESC srv_desc = {};
srv_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srv_desc.NumDescriptors = 1;
srv_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
r->device->CreateDescriptorHeap(&srv_desc, IID_PPV_ARGS(&r->icon_srv_heap));
D3D12_SHADER_RESOURCE_VIEW_DESC srv_view = {};
srv_view.Format = DXGI_FORMAT_R8_UNORM;
srv_view.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srv_view.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srv_view.Texture2D.MipLevels = 1;
r->device->CreateShaderResourceView(r->icon_texture,
&srv_view, r->icon_srv_heap->GetCPUDescriptorHandleForHeapStart());
}
void renderer_resize(Renderer *r, int32_t width, int32_t height) {
if (width <= 0 || height <= 0) return;