gpu utils

This commit is contained in:
jacob 2025-10-21 16:02:35 -05:00
parent fca8ba5a8d
commit 69a8f2e1a3
18 changed files with 620 additions and 383 deletions

View File

@ -398,7 +398,11 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
#define AlignedBlock(n) struct alignas(n)
//- Enum
#define Enum(name) typedef enum name name; enum name
#if !LanguageIsGpu
# define Enum(name) typedef enum name name; enum name
#else
# define Enum(name) enum name
#endif
//- alignof
#if LanguageIsC && (CompilerIsMsvc || __STDC_VERSION__ < 202311L)

View File

@ -51,3 +51,14 @@ Vec4 LinearFromSrgbU32(u32 srgb32)
{
return LinearFromSrgbVec4(Vec4NormFromU32(srgb32));
}
////////////////////////////////
//~ Ndc helpers
Vec2 NdcFromViewport(Vec2 viewport_size, Vec2 viewport_coords)
{
Vec2 result;
result.x = ((viewport_coords.x + 0.5f) / viewport_size.x) * 2.0f - 1.0f;
result.y = 1.0f - ((viewport_coords.y + 0.5f) / viewport_size.y) * 2.0f;
return result;
}

View File

@ -384,6 +384,8 @@ Vec2I32 GPU_GetTextureSize2D(GPU_Resource *resource);
Vec3I32 GPU_GetTextureSize3D(GPU_Resource *resource);
u64 GPU_GetFootprintSize(GPU_Resource *resource);
u64 GPU_GetBufferCount(GPU_Resource *gpu_resource);
////////////////////////////////
//~ @hookdecl Resource index operations

View File

@ -5,9 +5,17 @@
//- Api
@IncludeC gpu.h
@IncludeC gpu_util.h
//- Impl
@IncludeC gpu_util.c
//- Dx12 impl
@DefaultWindowsImpl gpu_dx12
//- Embeds
@EmbedDir GPU_Resources gpu_res
//- Startup
@Startup GPU_Startup
@Startup GPU_StartupUtils

View File

@ -1231,9 +1231,9 @@ GPU_Resource *GPU_AcquireResource(GPU_ResourceDesc desc)
d3d_desc.MaxLOD = desc.sampler.max_lod;
/* Defaults */
if (d3d_desc.AddressU == 0) d3d_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;;
if (d3d_desc.AddressV == 0) d3d_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;;
if (d3d_desc.AddressW == 0) d3d_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;;
if (d3d_desc.AddressU == 0) d3d_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
if (d3d_desc.AddressV == 0) d3d_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
if (d3d_desc.AddressW == 0) d3d_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
if (d3d_desc.MaxLOD >= F32Infinity)
{
d3d_desc.MaxLOD = D3D12_FLOAT32_MAX;
@ -1351,6 +1351,12 @@ u64 GPU_GetFootprintSize(GPU_Resource *gpu_resource)
return footprint_size;
}
u64 GPU_GetBufferCount(GPU_Resource *gpu_resource)
{
GPU_D12_Resource *resource = (GPU_D12_Resource *)gpu_resource;
return resource->desc.buffer.count;
}
////////////////////////////////
//~ @hookdef Resource index hooks

236
src/gpu/gpu_util.c Normal file
View File

@ -0,0 +1,236 @@
GPU_SharedUtilState GPU_shared_util_state = ZI;
////////////////////////////////
//~ Startup
void GPU_StartupUtils(void)
{
GPU_SharedUtilState *g = &GPU_shared_util_state;
GPU_QueueKind queue_kind = GPU_QueueKind_Direct;
Fence *queue_fence = GPU_FenceFromQueue(queue_kind);
i64 queue_fence_target = FetchFence(queue_fence);
GPU_Resource *noise_upload = 0;
GPU_Resource *quad_upload = 0;
GPU_Resource *noise = 0;
GPU_Resource *quad = 0;
GPU_CommandList *cl = GPU_BeginCommandList(queue_kind);
{
/* Upload noise */
{
Vec3I32 noise_size = VEC3I32(128, 128, 64);
Resource noise_resource = ResourceFromStore(&GPU_Resources, Lit("noise_128x128x64_16.dat"));
String noise_res_data = DataFromResource(noise_resource);
if (noise_res_data.len != noise_size.x * noise_size.y * noise_size.z * 2)
{
Panic(Lit("Unexpected noise texture size"));
}
GPU_ResourceDesc desc = ZI;
desc.kind = GPU_ResourceKind_Texture3D;
desc.texture.format = GPU_Format_R16_Uint;
desc.texture.size = noise_size;
noise = GPU_AcquireResource(desc);
{
u64 footprint_size = GPU_GetFootprintSize(noise);
GPU_ResourceDesc upload_desc = ZI;
upload_desc.kind = GPU_ResourceKind_Buffer;
upload_desc.buffer.heap_kind = GPU_HeapKind_Upload;
upload_desc.buffer.count = footprint_size;
noise_upload = GPU_AcquireResource(upload_desc);
GPU_Mapped mapped = GPU_Map(noise_upload);
GPU_CopyBytesToFootprint(mapped.mem, noise_res_data.text, noise);
GPU_Unmap(mapped);
}
GPU_TransitionToCopyDst(cl, noise);
GPU_CopyResource(cl, noise, noise_upload);
GPU_TransitionToReadable(cl, noise);
}
/* Upload quad indices */
{
u16 quad_indices[6] = { 0, 1, 2, 0, 2, 3 };
GPU_ResourceDesc desc = ZI;
desc.kind = GPU_ResourceKind_Buffer;
desc.buffer.count = countof(quad_indices);
desc.buffer.stride = sizeof(quad_indices[0]);
quad = GPU_AcquireResource(desc);
{
GPU_ResourceDesc upload_desc = ZI;
upload_desc.kind = GPU_ResourceKind_Buffer;
upload_desc.buffer.heap_kind = GPU_HeapKind_Upload;
upload_desc.buffer.count = desc.buffer.count * desc.buffer.stride;
quad_upload = GPU_AcquireResource(upload_desc);
GPU_Mapped mapped = GPU_Map(quad_upload);
CopyBytes(mapped.mem, quad_indices, sizeof(quad_indices));
GPU_Unmap(mapped);
}
GPU_TransitionToCopyDst(cl, quad);
GPU_CopyResource(cl, quad, quad_upload);
GPU_TransitionToReadable(cl, quad);
}
}
queue_fence_target = GPU_EndCommandList(cl);
/* Init point sampler */
g->pt_sampler = GPU_AcquireResource((GPU_ResourceDesc) { .kind = GPU_ResourceKind_Sampler, .sampler.filter = GPU_Filter_MinMagMipPoint });
/* Wait & cleanup */
YieldOnFence(queue_fence, queue_fence_target);
GPU_ReleaseResource(noise_upload, GPU_ReleaseFlag_None);
GPU_ReleaseResource(quad_upload, GPU_ReleaseFlag_None);
g->noise = noise;
g->quad_indices = quad;
}
////////////////////////////////
//~ Common resource helpers
GPU_Resource *GPU_GetCommonPointSampler(void)
{
return GPU_shared_util_state.pt_sampler;
}
GPU_Resource *GPU_GetCommonQuadIndices(void)
{
return GPU_shared_util_state.quad_indices;
}
GPU_Resource *GPU_GetCommonNoise(void)
{
return GPU_shared_util_state.noise;
}
////////////////////////////////
//~ Transient buffer operations
GPU_TransientBuffer *GPU_AcquireTransientBuffer_(u64 reserve, GPU_QueueKind queue_kind, u32 max_in_flight, u32 element_size, u32 element_align)
{
element_size = MaxU32(element_size, 1);
element_align = MaxU32(element_align, 1);
max_in_flight = MaxU32(max_in_flight, 1);
GPU_TransientBuffer *tbuff = 0;
{
Arena *arena = AcquireArena(reserve);
tbuff = PushStruct(arena, GPU_TransientBuffer);
tbuff->arena = arena;
}
tbuff->queue_kind = queue_kind;
tbuff->submitted_resources = PushStructs(tbuff->arena, GPU_SubmittedTransientBufferResource, max_in_flight);
tbuff->max_in_flight = max_in_flight;
for (u32 i = 0; i < max_in_flight; ++i)
{
/* Init free list */
StackPush(tbuff->first_free, &tbuff->submitted_resources[i]);
}
PushAlign(tbuff->arena, element_align);
tbuff->elements_start_pos = tbuff->arena->pos;
tbuff->element_size = element_size;
tbuff->element_align = element_align;
return tbuff;
}
void GPU_ReleaseTransientBuffer(GPU_TransientBuffer *tbuff)
{
Fence *queue_fence = GPU_FenceFromQueue(tbuff->queue_kind);
i64 queue_fence_value = FetchFence(queue_fence);
YieldOnFence(queue_fence, queue_fence_value);
for (GPU_SubmittedTransientBufferResource *submitted = tbuff->first_submitted;
submitted;
submitted = submitted->next)
{
GPU_ReleaseResource(submitted->resource, GPU_ReleaseFlag_None);
}
ReleaseArena(tbuff->arena);
}
GPU_Resource *GPU_UploadTransientBuffer(GPU_TransientBuffer *tbuff)
{
GPU_Resource *resource = 0;
u32 element_count = (tbuff->arena->pos - tbuff->elements_start_pos) / tbuff->element_size;
Fence *queue_fence = GPU_FenceFromQueue(tbuff->queue_kind);
i64 queue_fence_value = FetchFence(queue_fence);
if (tbuff->uploaded != 0)
{
Panic(Lit("GPU transient buffer uploaded without a reset"));
}
/* Grab resource */
GPU_SubmittedTransientBufferResource *upload = 0;
{
GPU_SubmittedTransientBufferResource *submitted = tbuff->first_submitted;
if (submitted && submitted->fence_target <= queue_fence_value)
{
upload = submitted;
QueuePop(tbuff->first_submitted, tbuff->last_submitted);
}
else if (tbuff->first_free)
{
/* Resource in upload, create new */
upload = tbuff->first_free;
StackPop(tbuff->first_free);
}
else
{
/* Resource in use and max_in_flight reached, wait for availability */
Assert(submitted != 0);
YieldOnFence(queue_fence, submitted->fence_target);
queue_fence_value = FetchFence(queue_fence);
upload = submitted;
QueuePop(tbuff->first_submitted, tbuff->last_submitted);
}
}
if (upload->resource)
{
GPU_ReleaseResource(upload->resource, GPU_ReleaseFlag_Reuse);
upload->resource = 0;
}
GPU_ResourceDesc desc = ZI;
desc.kind = GPU_ResourceKind_Buffer;
desc.flags = GPU_ResourceFlag_None;
desc.buffer.heap_kind = GPU_HeapKind_Upload;
desc.buffer.count = element_count;
desc.buffer.stride = tbuff->element_size;
upload->resource = GPU_AcquireResource(desc);
{
__profn("Copy to transfer buffer");
GPU_Mapped m = GPU_Map(upload->resource);
CopyBytes(m.mem, ArenaBase(tbuff->arena) + tbuff->elements_start_pos, tbuff->element_size * element_count);
GPU_Unmap(m);
}
tbuff->uploaded = upload;
tbuff->uploaded_element_count = element_count;
return upload->resource;
}
void GPU_ResetTransientBuffer(GPU_TransientBuffer *tbuff, i64 queue_fence_target)
{
PopTo(tbuff->arena, tbuff->elements_start_pos);
GPU_SubmittedTransientBufferResource *use = tbuff->uploaded;
if (use)
{
use->fence_target = queue_fence_target;
QueuePush(tbuff->first_submitted, tbuff->last_submitted, use);
tbuff->uploaded = 0;
}
}
Arena *GPU_ArenaFromTransientBuffer(GPU_TransientBuffer *tbuff)
{
return tbuff->arena;
}

65
src/gpu/gpu_util.h Normal file
View File

@ -0,0 +1,65 @@
////////////////////////////////
//~ Transient buffer types
Struct(GPU_SubmittedTransientBufferResource)
{
GPU_SubmittedTransientBufferResource *next;
i64 fence_target; /* Once the buffer's queue reaches the target, the resource can be freed or reused */
GPU_Resource *resource;
};
Struct(GPU_TransientBuffer)
{
Arena *arena;
GPU_QueueKind queue_kind;
u64 elements_start_pos;
u32 element_size;
u32 element_align;
GPU_SubmittedTransientBufferResource *submitted_resources; /* Pool of submitted resource structs */
u32 uploaded_element_count;
GPU_SubmittedTransientBufferResource *uploaded;
GPU_SubmittedTransientBufferResource *first_submitted;
GPU_SubmittedTransientBufferResource *last_submitted;
GPU_SubmittedTransientBufferResource *first_free;
u32 max_in_flight;
};
////////////////////////////////
//~ State types
Struct(GPU_SharedUtilState)
{
/* Common shared resources */
GPU_Resource *pt_sampler;
GPU_Resource *quad_indices;
GPU_Resource *noise;
} extern GPU_shared_util_state;
////////////////////////////////
//~ Startup
void GPU_StartupUtils(void);
////////////////////////////////
//~ Common resource helpers
GPU_Resource *GPU_GetCommonPointSampler(void);
GPU_Resource *GPU_GetCommonQuadIndices(void);
GPU_Resource *GPU_GetCommonNoise(void);
////////////////////////////////
//~ Transient buffer operations
GPU_TransientBuffer *GPU_AcquireTransientBuffer_(u64 reserve, GPU_QueueKind queue_kind, u32 max_in_flight, u32 element_size, u32 element_align);
#define GPU_AcquireTransientBuffer(reserve, queue_kind, max_in_flight, type) GPU_AcquireTransientBuffer_((reserve), (queue_kind), (max_in_flight), sizeof(type), alignof(type))
void GPU_ReleaseTransientBuffer(GPU_TransientBuffer *tbuff);
GPU_Resource *GPU_UploadTransientBuffer(GPU_TransientBuffer *tbuff);
void GPU_ResetTransientBuffer(GPU_TransientBuffer *tbuff, i64 queue_fence_target);
Arena *GPU_ArenaFromTransientBuffer(GPU_TransientBuffer *tbuff);

View File

@ -26,16 +26,6 @@ void StartupUser(void)
g->user_blended_client = AcquireClient(g->user_client_store);
g->ss_blended = NilSnapshot();
/* Renderer sampler */
g->pt_sampler = GPU_AcquireResource((GPU_ResourceDesc) { .kind = GPU_ResourceKind_Sampler, .sampler.filter = GPU_Filter_MinMagMipPoint });
/* Renderer data arenas */
g->material_instances_arena = AcquireArena(Gibi(64));
g->ui_rect_instances_arena = AcquireArena(Gibi(64));
g->ui_shape_verts_arena = AcquireArena(Gibi(64));
g->ui_shape_indices_arena = AcquireArena(Gibi(64));
g->grids_arena = AcquireArena(Gibi(64));
/* Local to user client */
g->local_to_user_client_store = AcquireClientStore();
g->local_to_user_client = AcquireClient(g->local_to_user_client_store);
@ -403,42 +393,6 @@ GPU_Resource *AcquireGbuffer(GPU_Format format, Vec2I32 size)
return GPU_AcquireResource(desc);
}
//- Upload buffer
GPU_Resource *AcquireUploadBuffer_(void *src, u32 element_size, u32 element_count)
{
__prof;
GPU_ResourceDesc desc = ZI;
desc.kind = GPU_ResourceKind_Buffer;
desc.flags = GPU_ResourceFlag_None;
desc.buffer.heap_kind = GPU_HeapKind_Upload;
desc.buffer.count = element_count;
desc.buffer.stride = element_size;
GPU_Resource *r = GPU_AcquireResource(desc);
{
__profn("Copy to transfer buffer");
GPU_Mapped m = GPU_Map(r);
CopyBytes(m.mem, src, element_size * element_count);
GPU_Unmap(m);
}
return r;
}
GPU_Resource *AcquireUploadBufferFromArena_(Arena *arena, u32 element_size)
{
__prof;
u64 element_count = arena->pos / element_size;
GPU_Resource *r = AcquireUploadBuffer_(ArenaBase(arena), element_size, element_count);
return r;
}
JobDef(DelayReleaseGpuResources, sig, id)
{
YieldOnFence(sig->begin_fence, sig->begin_fence_target);
GPU_Resource *resource = sig->resources[id];
GPU_ReleaseResource(resource, sig->flags);
}
////////////////////////////////
//~ Sort entities
@ -500,6 +454,21 @@ void UpdateUser(P_Window *window)
UI_Box *pp_root_box = UI_BuildBox(UI_Flag_DrawImage, UI_NilKey);
UI_PushParent(pp_root_box);
//- Init render data buffers
if (!g->material_instances_tbuff)
{
g->material_instances_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, MaterialInstance);
g->ui_rect_instances_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, UiRectInstance);
g->ui_shape_verts_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, UiShapeVert);
g->ui_shape_indices_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, u32);
g->grids_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, MaterialGrid);
}
Arena *material_instances_arena = GPU_ArenaFromTransientBuffer(g->material_instances_tbuff);
Arena *ui_rect_instances_arena = GPU_ArenaFromTransientBuffer(g->ui_rect_instances_tbuff);
Arena *ui_shape_verts_arena = GPU_ArenaFromTransientBuffer(g->ui_shape_verts_tbuff);
Arena *ui_shape_indices_arena = GPU_ArenaFromTransientBuffer(g->ui_shape_indices_tbuff);
Arena *grids_arena = GPU_ArenaFromTransientBuffer(g->grids_tbuff);
//- Pull latest local sim snapshot
{
@ -1007,7 +976,6 @@ void UpdateUser(P_Window *window)
//- Draw grid
/* FIXME: Enable this */
{
f32 thickness = 2;
@ -1019,7 +987,7 @@ void UpdateUser(P_Window *window)
u32 color0 = Rgba32F(0.17f, 0.17f, 0.17f, 1.f);
u32 color1 = Rgba32F(0.15f, 0.15f, 0.15f, 1.f);
MaterialGrid *grid = PushStruct(g->grids_arena, MaterialGrid);
MaterialGrid *grid = PushStruct(grids_arena, MaterialGrid);
*grid = DefaultMaterialGrid;
grid->line_thickness = thickness;
grid->line_spacing = spacing;
@ -1030,9 +998,12 @@ void UpdateUser(P_Window *window)
grid->x_srgb = ColorRed;
grid->y_srgb = ColorGreen;
MaterialInstance *mat = PushStruct(g->material_instances_arena, MaterialInstance);
MaterialInstance *mat = PushStruct(material_instances_arena, MaterialInstance);
*mat = DefaultMaterialInstance;
mat->grid_id = grid - (MaterialGrid *)ArenaBase(g->grids_arena);
// TODO
// BROKE
// FIXME
mat->grid_id = grid - (MaterialGrid *)ArenaBase(grids_arena);
mat->xf = XformFromRect(RectFromVec2(pos, size));
}
@ -1251,7 +1222,7 @@ void UpdateUser(P_Window *window)
Vec3 emittance = ent->sprite_emittance;
u32 tint = ent->sprite_tint;
S_Frame frame = S_FrameFromIndex(sheet, ent->animation_frame);
MaterialInstance *mat = PushStruct(g->material_instances_arena, MaterialInstance);
MaterialInstance *mat = PushStruct(material_instances_arena, MaterialInstance);
*mat = DefaultMaterialInstance;
mat->xf = sprite_xform;
mat->tex = GPU_Texture2DRidFromResource(texture->gpu_texture);
@ -1286,7 +1257,7 @@ void UpdateUser(P_Window *window)
Vec2I32 world_tile_index = WorldTileIndexFromLocalTileIndex(chunk_index, local_tile_index);
Vec2 pos = PosFromWorldTileIndex(world_tile_index);
Xform tile_xf = XformFromRect(RectFromVec2(pos, VEC2(tile_size, tile_size)));
MaterialInstance *mat = PushStruct(g->material_instances_arena, MaterialInstance);
MaterialInstance *mat = PushStruct(material_instances_arena, MaterialInstance);
*mat = DefaultMaterialInstance;
mat->xf = tile_xf;
mat->tex = GPU_Texture2DRidFromResource(tile_texture->gpu_texture);
@ -2029,6 +2000,7 @@ void UpdateUser(P_Window *window)
GPU_MemoryInfo vram = GPU_QueryMemoryInfo();
////////////////////////////////
//~ Draw global debug info
/* FIXME: Enable this */
#if 1
@ -2264,14 +2236,15 @@ void UpdateUser(P_Window *window)
#endif
}
////////////////////////////////
//~ Render
{
__profn("Render");
GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct;
Rect ui_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->ui_size.x, g->ui_size.y));
Rect render_viewport = RectFromVec2(VEC2(0, 0), VEC2(g->render_size.x, g->render_size.y));
GPU_QueueKind gpu_render_queue = GPU_QueueKind_Direct;
Fence *render_fence = GPU_FenceFromQueue(gpu_render_queue);
{
__profn("Render");
/* Acquire gbuffers */
if (g->shade_target && !EqVec2I32(g->render_size, GPU_GetTextureSize2D(g->shade_target)))
@ -2309,84 +2282,17 @@ void UpdateUser(P_Window *window)
g->ui_target = AcquireGbuffer(GPU_Format_R8G8B8A8_Unorm, g->ui_size);
}
/* Init renderer resources */
if (!g->gpu_noise || !g->gpu_quad)
{
GPU_Resource *noise_upload = 0;
GPU_Resource *quad_upload = 0;
GPU_Resource *noise = 0;
GPU_Resource *quad = 0;
GPU_CommandList *cl = GPU_BeginCommandList(gpu_render_queue);
/* Upload noise */
{
Vec3I32 noise_size = VEC3I32(128, 128, 64);
Resource noise_resource = ResourceFromStore(&GameResources, Lit("noise_128x128x64_16.dat"));
String noise_res_data = DataFromResource(noise_resource);
if (noise_res_data.len != noise_size.x * noise_size.y * noise_size.z * 2)
{
Panic(Lit("Unexpected noise texture size"));
}
GPU_ResourceDesc desc = ZI;
desc.kind = GPU_ResourceKind_Texture3D;
desc.texture.format = GPU_Format_R16_Uint;
desc.texture.size = noise_size;
noise = GPU_AcquireResource(desc);
{
u64 footprint_size = GPU_GetFootprintSize(noise);
GPU_ResourceDesc upload_desc = ZI;
upload_desc.kind = GPU_ResourceKind_Buffer;
upload_desc.buffer.heap_kind = GPU_HeapKind_Upload;
upload_desc.buffer.count = footprint_size;
noise_upload = GPU_AcquireResource(upload_desc);
GPU_Mapped mapped = GPU_Map(noise_upload);
GPU_CopyBytesToFootprint(mapped.mem, noise_res_data.text, noise);
GPU_Unmap(mapped);
}
GPU_TransitionToCopyDst(cl, noise);
GPU_CopyResource(cl, noise, noise_upload);
GPU_TransitionToReadable(cl, noise);
}
/* Upload quad indices */
{
u16 quad_indices[6] = { 0, 1, 2, 0, 2, 3 };
GPU_ResourceDesc desc = ZI;
desc.kind = GPU_ResourceKind_Buffer;
desc.buffer.count = countof(quad_indices);
desc.buffer.stride = sizeof(quad_indices[0]);
quad = GPU_AcquireResource(desc);
{
GPU_ResourceDesc upload_desc = ZI;
upload_desc.kind = GPU_ResourceKind_Buffer;
upload_desc.buffer.heap_kind = GPU_HeapKind_Upload;
upload_desc.buffer.count = desc.buffer.count * desc.buffer.stride;
quad_upload = GPU_AcquireResource(upload_desc);
GPU_Mapped mapped = GPU_Map(quad_upload);
CopyBytes(mapped.mem, quad_indices, sizeof(quad_indices));
GPU_Unmap(mapped);
}
GPU_TransitionToCopyDst(cl, quad);
GPU_CopyResource(cl, quad, quad_upload);
GPU_TransitionToReadable(cl, quad);
}
g->gpu_render_fence_target = GPU_EndCommandList(cl);
YieldOnFence(render_fence, g->gpu_render_fence_target);
GPU_ReleaseResource(noise_upload, GPU_ReleaseFlag_None);
GPU_ReleaseResource(quad_upload, GPU_ReleaseFlag_None);
g->gpu_noise = noise;
g->gpu_quad = quad;
}
/* Acquire transfer buffers */
GPU_Resource *material_instance_buffer = AcquireUploadBufferFromArena(g->material_instances_arena, MaterialInstance);
GPU_Resource *ui_rect_instance_buffer = AcquireUploadBufferFromArena(g->ui_rect_instances_arena, UiRectInstance);
GPU_Resource *ui_shape_verts_buffer = AcquireUploadBufferFromArena(g->ui_shape_verts_arena, UiShapeVert);
GPU_Resource *ui_shape_indices_buffer = AcquireUploadBufferFromArena(g->ui_shape_indices_arena, u32);
GPU_Resource *grids_buffer = AcquireUploadBufferFromArena(g->grids_arena, MaterialGrid);
u64 material_instances_count = ArenaCount(g->material_instances_arena, MaterialInstance);
u64 ui_rect_instances_count = ArenaCount(g->ui_rect_instances_arena, UiRectInstance);
u64 ui_shape_verts_count = ArenaCount(g->ui_shape_verts_arena, UiShapeVert);
u64 ui_shape_indices_count = ArenaCount(g->ui_shape_indices_arena, u32);
u64 grids_count = ArenaCount(g->grids_arena, MaterialGrid);
/* Upload transient buffers */
GPU_Resource *material_instances_buffer = GPU_UploadTransientBuffer(g->material_instances_tbuff);
GPU_Resource *ui_rect_instances_buffer = GPU_UploadTransientBuffer(g->ui_rect_instances_tbuff);
GPU_Resource *ui_shape_verts_buffer = GPU_UploadTransientBuffer(g->ui_shape_verts_tbuff);
GPU_Resource *ui_shape_indices_buffer = GPU_UploadTransientBuffer(g->ui_shape_indices_tbuff);
GPU_Resource *grids_buffer = GPU_UploadTransientBuffer(g->grids_tbuff);
u64 material_instances_count = GPU_GetBufferCount(material_instances_buffer);
u64 ui_rect_instances_count = GPU_GetBufferCount(ui_rect_instances_buffer);
u64 ui_shape_verts_count = GPU_GetBufferCount(ui_shape_verts_buffer);
u64 ui_shape_indices_count = GPU_GetBufferCount(ui_shape_indices_buffer);
u64 grids_count = GPU_GetBufferCount(grids_buffer);
GPU_CommandList *cl = GPU_BeginCommandList(gpu_render_queue);
{
@ -2423,8 +2329,8 @@ void UpdateUser(P_Window *window)
MaterialSig sig = ZI;
sig.projection = world_to_render_vp_matrix;
sig.sampler = GPU_SamplerStateRidFromResource(g->pt_sampler);
sig.instances = GPU_StructuredBufferRidFromResource(material_instance_buffer);
sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler());
sig.instances = GPU_StructuredBufferRidFromResource(material_instances_buffer);
sig.grids = GPU_StructuredBufferRidFromResource(grids_buffer);
GPU_Rasterize(cl,
&sig,
@ -2433,7 +2339,7 @@ void UpdateUser(P_Window *window)
viewport,
scissor,
material_instances_count,
g->gpu_quad,
GPU_GetCommonQuadIndices(),
GPU_RasterizeMode_TriangleList);
}
@ -2504,7 +2410,7 @@ void UpdateUser(P_Window *window)
{
__profn("Shade pass");
GPU_ProfN(cl, Lit("Shade pass"));
Vec3I32 noise_size = GPU_GetTextureSize3D(g->gpu_noise);
Vec3I32 noise_size = GPU_GetTextureSize3D(GPU_GetCommonNoise());
u32 shade_flags = ShadeFlag_None;
if (effects_disabled)
@ -2522,7 +2428,7 @@ void UpdateUser(P_Window *window)
(u32)(RandU64FromState(&g->frame_rand) & 0xFFFFFFFF));
sig.frame_index = g->frame_index;
sig.camera_offset = g->world_to_render_xf.og;
sig.noise = GPU_Texture3DRidFromResource(g->gpu_noise);
sig.noise = GPU_Texture3DRidFromResource(GPU_GetCommonNoise());
sig.albedo = GPU_Texture2DRidFromResource(g->albedo);
sig.emittance = GPU_Texture2DRidFromResource(g->emittance);
sig.emittance_flood = GPU_Texture2DRidFromResource(g->emittance_flood_read);
@ -2557,7 +2463,7 @@ void UpdateUser(P_Window *window)
GPU_Scissor scissor = GPU_ScissorFromRect(ui_viewport);
UiBlitSig sig = ZI;
sig.sampler = GPU_SamplerStateRidFromResource(g->pt_sampler);
sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler());
sig.src = GPU_Texture2DRidFromResource(g->shade_read);
sig.projection = blit_vp_matrix;
sig.flags = UiBlitFlag_ToneMap | UiBlitFlag_GammaCorrect;
@ -2570,7 +2476,7 @@ void UpdateUser(P_Window *window)
viewport,
scissor,
1,
g->gpu_quad,
GPU_GetCommonQuadIndices(),
GPU_RasterizeMode_TriangleList);
}
@ -2584,8 +2490,8 @@ void UpdateUser(P_Window *window)
UiRectSig sig = ZI;
sig.projection = ui_vp_matrix;
sig.sampler = GPU_SamplerStateRidFromResource(g->pt_sampler);
sig.instances = GPU_StructuredBufferRidFromResource(ui_rect_instance_buffer);
sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler());
sig.instances = GPU_StructuredBufferRidFromResource(ui_rect_instances_buffer);
GPU_Rasterize(cl,
&sig,
UiRectVS, UiRectPS,
@ -2593,7 +2499,7 @@ void UpdateUser(P_Window *window)
viewport,
scissor,
ui_rect_instances_count,
g->gpu_quad,
GPU_GetCommonQuadIndices(),
GPU_RasterizeMode_TriangleList);
}
@ -2618,44 +2524,25 @@ void UpdateUser(P_Window *window)
ui_shape_indices_buffer,
GPU_RasterizeMode_TriangleList);
}
//- Transition target to readable before UI pass
GPU_TransitionToReadable(cl, g->ui_target);
}
g->gpu_render_fence_target = GPU_EndCommandList(cl);
/* Reset transfer buffers & queue their release */
{
{
GPU_Resource *release_resources[] = {
material_instance_buffer,
ui_rect_instance_buffer,
ui_shape_verts_buffer,
ui_shape_indices_buffer,
grids_buffer,
};
Job *job = OpenJob(DelayReleaseGpuResources, JobPool_Inherit);
{
DelayReleaseGpuResources_Sig *sig = PushStruct(job->arena, DelayReleaseGpuResources_Sig);
job->count = countof(release_resources);
job->sig = sig;
sig->begin_fence = render_fence;
sig->begin_fence_target = g->gpu_render_fence_target;
sig->resources = PushStructsNoZero(job->arena, GPU_Resource *, job->count);
sig->flags = GPU_ReleaseFlag_Reuse;
CopyBytes(sig->resources, release_resources, sizeof(release_resources));
}
CloseJob(job);
}
ResetArena(g->material_instances_arena);
ResetArena(g->ui_rect_instances_arena);
ResetArena(g->ui_shape_verts_arena);
ResetArena(g->ui_shape_indices_arena);
ResetArena(g->grids_arena);
}
/* Reset transients */
GPU_ResetTransientBuffer(g->material_instances_tbuff, g->gpu_render_fence_target);
GPU_ResetTransientBuffer(g->ui_rect_instances_tbuff, g->gpu_render_fence_target);
GPU_ResetTransientBuffer(g->ui_shape_verts_tbuff, g->gpu_render_fence_target);
GPU_ResetTransientBuffer(g->ui_shape_indices_tbuff, g->gpu_render_fence_target);
GPU_ResetTransientBuffer(g->grids_tbuff, g->gpu_render_fence_target);
}
/* Render UI */
UI_PopParent();
UI_SetDisplayImage(pp_root_box, g->ui_target);
GPU_Resource *ui_render = UI_EndBuild();
GPU_Resource *ui_render = UI_EndBuild(ui_viewport);
////////////////////////////////
//~ Present

View File

@ -172,11 +172,7 @@ Struct(SharedUserState)
SecondsStat net_bytes_read;
SecondsStat net_bytes_sent;
//- Gpu resources
GPU_Resource *pt_sampler;
GPU_Resource *gpu_noise;
GPU_Resource *gpu_quad;
//- Renderer gbuffers
GPU_Resource *albedo;
GPU_Resource *emittance;
GPU_Resource *emittance_flood_read;
@ -185,15 +181,16 @@ Struct(SharedUserState)
GPU_Resource *shade_target;
GPU_Resource *ui_target;
//- Render transient buffers
GPU_TransientBuffer *material_instances_tbuff;
GPU_TransientBuffer *ui_rect_instances_tbuff;
GPU_TransientBuffer *ui_shape_verts_tbuff;
GPU_TransientBuffer *ui_shape_indices_tbuff;
GPU_TransientBuffer *grids_tbuff;
//- Renderer state
RandState frame_rand;
u64 frame_index;
Arena *material_instances_arena;
Arena *ui_rect_instances_arena;
Arena *ui_shape_verts_arena;
Arena *ui_shape_indices_arena;
Arena *grids_arena;
i64 gpu_render_fence_target;
//- Bind state
@ -295,13 +292,7 @@ void DrawDebugConsole(i32 level, b32 minimized);
////////////////////////////////
//~ Gpu buffer helpers
#define AcquireUploadBuffer(src, type, count) AcquireUploadBuffer_((src), sizeof(type), (count))
#define AcquireUploadBufferFromArena(arena, type) AcquireUploadBufferFromArena_((arena), sizeof(type))
GPU_Resource *AcquireGbuffer(GPU_Format format, Vec2I32 size);
GPU_Resource *AcquireUploadBuffer_(void *src, u32 element_size, u32 element_count);
GPU_Resource *AcquireUploadBufferFromArena_(Arena *arena, u32 element_size);
JobDecl(DelayReleaseGpuResources, { Fence *begin_fence; u64 begin_fence_target; GPU_Resource **resources; GPU_ReleaseFlag flags; });
////////////////////////////////
//~ Entity sorting

View File

@ -28,9 +28,9 @@ void UI_PushTagFromHash(u64 hash)
{
hash = RandU64FromSeeds(hash, g->top_tag->hash);
}
UI_Tag *tag = PushStruct(g->build_arena, UI_Tag);
StackPush(g->top_tag, tag);
tag->hash = hash;
UI_TagNode *n = PushStruct(g->build_arena, UI_TagNode);
StackPush(g->top_tag, n);
n->hash = hash;
}
void UI_PushTagFromString(String str)
@ -42,9 +42,9 @@ void UI_PushTagFromString(String str)
hash = g->top_tag->hash;
}
hash = HashFnv64(hash, str);
UI_Tag *tag = PushStruct(g->build_arena, UI_Tag);
StackPush(g->top_tag, tag);
tag->hash = hash;
UI_TagNode *n = PushStruct(g->build_arena, UI_TagNode);
n->hash = hash;
StackPush(g->top_tag, n);
}
void UI_PushTagF_(char *fmt_cstr, ...)
@ -63,8 +63,7 @@ void UI_PushTagF_(char *fmt_cstr, ...)
void UI_PopTag(void)
{
UI_SharedState *g = &UI_shared_state;
StackPop(g->top_tag);
StackPop(UI_shared_state.top_tag);
}
//- Parent
@ -72,15 +71,46 @@ void UI_PopTag(void)
void UI_PushParent(UI_Box *box)
{
UI_SharedState *g = &UI_shared_state;
UI_Parent *parent = PushStruct(g->build_arena, UI_Parent);
parent->box = box;
StackPush(g->top_parent, parent);
UI_ParentNode *n = PushStruct(g->build_arena, UI_ParentNode);
n->box = box;
StackPush(g->top_parent, n);
}
void UI_PopParent(void)
{
StackPop(UI_shared_state.top_parent);
}
//- Size
void UI_PushSize(Axis axis, UI_SizeKind kind, f32 v, f32 strictness)
{
UI_SharedState *g = &UI_shared_state;
StackPop(g->top_parent);
UI_SizeNode *n = PushStruct(g->build_arena, UI_SizeNode);
n->size.kind = kind;
n->size.v = v;
n->size.strictness = strictness;
StackPush(g->top_size[axis], n);
}
void UI_PopSize(Axis axis)
{
StackPop(UI_shared_state.top_size[axis]);
}
//- Layout dir
void UI_PushLayoutDir(Axis dir)
{
UI_SharedState *g = &UI_shared_state;
UI_AxisNode *n = PushStruct(g->build_arena, UI_AxisNode);
n->axis = dir;
StackPush(g->top_layout_dir, n);
}
void UI_PopLayoutDir(void)
{
StackPop(UI_shared_state.top_layout_dir);
}
////////////////////////////////
@ -131,16 +161,21 @@ UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key)
box->key = key;
box->flags = flags;
box->tint = 0xFFFFFFFF;
/* Pull from stack */
box->parent = g->top_parent->box;
box->pref_size[Axis_X] = g->top_size[Axis_X]->size;
box->pref_size[Axis_Y] = g->top_size[Axis_Y]->size;
box->layout_dir = g->top_layout_dir->axis;
DllPushBack(g->top_parent->box->first, g->top_parent->box->last, box);
++box->parent->count;
return box;
}
////////////////////////////////
//~ Text
void UI_SetDisplayText(UI_Box *box, String str)
{
UI_SharedState *g = &UI_shared_state;
@ -148,9 +183,6 @@ void UI_SetDisplayText(UI_Box *box, String str)
box->display_text = text;
}
////////////////////////////////
//~ Image
void UI_SetDisplayImage(UI_Box *box, GPU_Resource *img)
{
box->display_image = img;
@ -187,8 +219,6 @@ void UI_BeginBuild(void)
/* Init root box */
g->root_box = PushStruct(g->build_arena, UI_Box);
g->root_box->key = UI_RootKey;
g->root_box->pref_size[Axis_X].kind = UI_SizeKind_Absolute;
g->root_box->pref_size[Axis_Y].kind = UI_SizeKind_Absolute;
UI_BoxBin *bin = &g->box_bins[g->root_box->key.hash % UI_NumBoxLookupBins];
DllPushBackNP(bin->first, bin->last, g->root_box, next_in_bin, prev_in_bin);
++g->boxes_count;
@ -196,6 +226,9 @@ void UI_BeginBuild(void)
/* Init stacks */
UI_PushTagF("root");
UI_PushParent(g->root_box);
UI_PushSize(Axis_X, UI_SizeKind_Percent, 1, 0);
UI_PushSize(Axis_Y, UI_SizeKind_Percent, 1, 0);
UI_PushLayoutDir(Axis_X);
if (!g->back_build_arena)
{
@ -207,7 +240,7 @@ void UI_BeginBuild(void)
////////////////////////////////
//~ End build
GPU_Resource *UI_EndBuild(void)
GPU_Resource *UI_EndBuild(Rect render_viewport)
{
TempArena scratch = BeginScratchNoConflict();
UI_SharedState *g = &UI_shared_state;
@ -218,9 +251,10 @@ GPU_Resource *UI_EndBuild(void)
//- Layout
/* Init root size */
Vec2I32 root_size = VEC2I32(500, 500);
g->root_box->p0 = VEC2(0, 0);
g->root_box->p1 = VEC2(root_size.x, root_size.y);
g->root_box->pref_size[Axis_X].kind = UI_SizeKind_Pixel;
g->root_box->pref_size[Axis_X].v = render_viewport.size.x;
g->root_box->pref_size[Axis_Y].kind = UI_SizeKind_Pixel;
g->root_box->pref_size[Axis_Y].v = render_viewport.size.y;
/* Build pre-order & post-order box arrays */
u64 boxes_count = g->boxes_count;
@ -263,21 +297,21 @@ GPU_Resource *UI_EndBuild(void)
}
/* Calculate independent sizes */
for (u64 box_index = 1; box_index < boxes_count; ++box_index)
for (u64 box_index = 0; box_index < boxes_count; ++box_index)
{
UI_Box *box = boxes_pre[box_index];
for (Axis axis = 0; axis < Axis_CountXY; ++axis)
{
UI_Size pref_size = box->pref_size[axis];
if (pref_size.kind == UI_SizeKind_Absolute)
if (pref_size.kind == UI_SizeKind_Pixel)
{
box->solved_size[axis].v = pref_size.v;
box->solved_dims[axis] = pref_size.v;
}
else if (pref_size.kind == UI_SizeKind_Text)
{
/* FIXME: Calculate actual text size here */
f32 text_size = 10;
box->solved_size[axis].v = text_size;
box->solved_dims[axis] = text_size;
}
}
}
@ -292,21 +326,39 @@ GPU_Resource *UI_EndBuild(void)
if (pref_size.kind == UI_SizeKind_Percent)
{
UI_Box *ancestor = box->parent;
UI_Size ancestor_size = ZI;
f32 ancestor_size = 0;
for (; ancestor; ancestor = ancestor->parent)
{
UI_Size tmp = ancestor->solved_size[axis];
if (tmp.kind == UI_SizeKind_Absolute || tmp.kind == UI_SizeKind_Text)
UI_Size tmp = ancestor->pref_size[axis];
if (tmp.kind == UI_SizeKind_Pixel || tmp.kind == UI_SizeKind_Text)
{
ancestor_size = tmp;
ancestor_size = ancestor->solved_dims[axis];
break;
}
}
// box->solved_size =
box->solved_dims[axis] = pref_size.v * ancestor_size;
}
}
}
/* Calculate final positions */
for (u64 box_index = 0; box_index < boxes_count; ++box_index)
{
UI_Box *box = boxes_pre[box_index];
UI_Box *parent = box->parent;
Vec2 final_size = VEC2(box->solved_dims[0], box->solved_dims[1]);
if (parent)
{
b32 is_layout_x = parent->layout_dir == Axis_X;
f32 layout_cursor = parent->layout_cursor;
Vec2 offset = VEC2(layout_cursor * is_layout_x, layout_cursor * !is_layout_x);
parent->layout_cursor += final_size.x * is_layout_x + final_size.y * is_layout_x;
box->p0 = AddVec2(parent->p0, offset);
}
box->p1 = AddVec2(box->p0, final_size);
}
/* TODO: Remove this */
#if 0
{
@ -351,33 +403,46 @@ GPU_Resource *UI_EndBuild(void)
#endif
////////////////////////////////
//- Build instances
//- Build render data
/* Init transient buffers */
if (!g->draw_rects_tbuff)
{
g->draw_rects_tbuff = GPU_AcquireTransientBuffer(Gibi(64), GPU_QueueKind_Direct, 8, UI_RectInstance);
}
Arena *draw_rects_arena = GPU_ArenaFromTransientBuffer(g->draw_rects_tbuff);
GPU_QueueKind render_queue = GPU_QueueKind_Direct;
Fence *render_fence = GPU_FenceFromQueue(render_queue);
/* Init render state */
if (!g->draw_rects_arena)
if (!draw_rects_arena)
{
g->draw_rects_arena = AcquireArena(Gibi(64));
draw_rects_arena = AcquireArena(Gibi(64));
}
/* Build rect instance data */
for (u64 box_index = 0; box_index < boxes_count; ++box_index)
{
UI_Box *box = boxes_pre[box_index];
UI_RectInstance *rect = PushStruct(g->draw_rects_arena, UI_RectInstance);
UI_RectInstance *rect = PushStruct(draw_rects_arena, UI_RectInstance);
rect->flags = box->flags;
rect->p0 = box->p0;
rect->p1 = box->p1;
rect->tint_srgb = 0xFFFFFFFF;
rect->tint_srgb = box->tint;
if (box->flags & UI_Flag_DrawImage, box->display_image)
{
rect->image_tex = GPU_Texture2DRidFromResource(box->display_image);
}
}
////////////////////////////////
//- Render
/* Acquire render target */
if (g->render_target && !EqVec2I32(root_size, GPU_GetTextureSize2D(g->render_target)))
/* Init render target */
if (g->render_target && !EqVec2I32(VEC2I32(render_viewport.size.x, render_viewport.size.y), GPU_GetTextureSize2D(g->render_target)))
{
YieldOnFence(render_fence, g->render_fence_target);
GPU_ReleaseResource(g->render_target, GPU_ReleaseFlag_None);
@ -389,18 +454,53 @@ GPU_Resource *UI_EndBuild(void)
desc.kind = GPU_ResourceKind_Texture2D;
desc.flags = GPU_ResourceFlag_Renderable;
desc.texture.format = GPU_Format_R8G8B8A8_Unorm;
desc.texture.size = VEC3I32(root_size.x, root_size.y, 1);
desc.texture.size = VEC3I32(render_viewport.size.x, render_viewport.size.y, 1);
g->render_target = GPU_AcquireResource(desc);
}
/* Upload transient buffers */
GPU_Resource *draw_rects_buffer = GPU_UploadTransientBuffer(g->draw_rects_tbuff);
u32 draw_rects_count = GPU_GetBufferCount(draw_rects_buffer);
/* Build command list */
GPU_CommandList *cl = GPU_BeginCommandList(render_queue);
{
//- Prep rect pass
{
__profn("Clear target");
GPU_ProfN(cl, Lit("Clear target"));
GPU_TransitionToRenderable(cl, g->render_target, 0);
GPU_ClearRenderable(cl, g->render_target);
}
//- Rect pass
if (draw_rects_count > 0)
{
__profn("Rect pass");
GPU_ProfN(cl, Lit("Rect pass"));
GPU_Viewport viewport = GPU_ViewportFromRect(render_viewport);
GPU_Scissor scissor = GPU_ScissorFromRect(render_viewport);
UI_RectSig sig = ZI;
sig.viewport_size = RoundVec2ToVec2I32(render_viewport.size);
sig.sampler = GPU_SamplerStateRidFromResource(GPU_GetCommonPointSampler());
sig.instances = GPU_StructuredBufferRidFromResource(draw_rects_buffer);
GPU_Rasterize(cl,
&sig,
UI_RectVS, UI_RectPS,
1,
viewport,
scissor,
draw_rects_count,
GPU_GetCommonQuadIndices(),
GPU_RasterizeMode_TriangleList);
}
}
g->render_fence_target = GPU_EndCommandList(cl);
/* Reset render state */
ResetArena(g->draw_rects_arena);
/* Reset transient buffers */
GPU_ResetTransientBuffer(g->draw_rects_tbuff, g->render_fence_target);
EndScratch(scratch);
return g->render_target;

View File

@ -16,7 +16,7 @@ Enum(UI_SizeKind)
{
UI_SizeKind_Children,
UI_SizeKind_Percent,
UI_SizeKind_Absolute,
UI_SizeKind_Pixel,
UI_SizeKind_Text,
};
@ -24,18 +24,12 @@ Struct(UI_Size)
{
UI_SizeKind kind;
f32 v;
f32 strictness;
};
////////////////////////////////
//~ Box types
Enum(UI_Flag)
{
UI_Flag_None = 0,
UI_Flag_DrawText = (1 << 0),
UI_Flag_DrawImage = (1 << 1),
};
Struct(UI_Box)
{
//- Hash list
@ -58,9 +52,12 @@ Struct(UI_Box)
String display_text;
GPU_Resource *display_image;
UI_Size pref_size[Axis_CountXY];
Axis layout_dir;
u32 tint;
//- Solver data
UI_Size solved_size[Axis_CountXY];
//- Layout data
f32 solved_dims[Axis_CountXY];
f32 layout_cursor;
//- Post-solve data
Vec2 p0;
@ -76,8 +73,10 @@ Struct(UI_BoxBin)
////////////////////////////////
//~ Stack types
Struct(UI_Tag) { UI_Tag *next; u64 hash; };
Struct(UI_Parent) { UI_Parent *next; UI_Box *box; };
Struct(UI_TagNode) { UI_TagNode *next; u64 hash; };
Struct(UI_ParentNode) { UI_ParentNode *next; UI_Box *box; };
Struct(UI_SizeNode) { UI_SizeNode *next; UI_Size size; };
Struct(UI_AxisNode) { UI_AxisNode *next; Axis axis; };
////////////////////////////////
//~ State types
@ -100,13 +99,15 @@ Struct(UI_SharedState)
u64 back_boxes_count;
//- Stack state
UI_Tag *top_tag;
UI_Parent *top_parent;
UI_TagNode *top_tag;
UI_ParentNode *top_parent;
UI_SizeNode *top_size[Axis_CountXY];
UI_AxisNode *top_layout_dir;
//- Render state
GPU_Resource *render_target;
i64 render_fence_target;
Arena *draw_rects_arena;
GPU_TransientBuffer *draw_rects_tbuff;
} extern UI_shared_state;
////////////////////////////////
@ -128,12 +129,21 @@ void UI_PopTag(void);
void UI_PushParent(UI_Box *box);
void UI_PopParent(void);
//- Size
void UI_PushSize(Axis axis, UI_SizeKind kind, f32 v, f32 strictness);
void UI_PopSize(Axis axis);
//- Layout dir
void UI_PushLayoutDir(Axis dir);
void UI_PopLayoutDir(void);
////////////////////////////////
//~ Box
UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key);
void UI_SetDisplayText(UI_Box *box, String str);
void UI_SetDisplayImage(UI_Box *box, GPU_Resource *img);
////////////////////////////////
//~ Image
@ -148,114 +158,4 @@ void UI_BeginBuild(void);
////////////////////////////////
//~ End build
GPU_Resource *UI_EndBuild(void);
/* TODO: Remove this */
#if 0
////////////////////////////////
//~ Rect
Struct(UI_RectParams)
{
Xform xf;
GPU_Resource *texture;
ClipRect clip;
u32 tint;
};
#define UI_RECTPARAMS(...) ((UI_RectParams) { \
.tint = ColorWhite, \
.clip = AllClipped, \
__VA_ARGS__ \
})
////////////////////////////////
//~ Text types
/* How is text aligned within its area */
Enum(UI_TextAlignment)
{
UI_TextAlignment_Left, /* Default */
UI_TextAlignment_Center,
UI_TextAlignment_Right
};
/* How does the specified text position relate to the text area.
* E.g. Bottom & Right means the bottom-right of the text area will snap to
* the specified position. */
Enum(UI_TextOffsetX)
{
UI_TextOffsetX_Left, /* Default */
UI_TextOffsetX_Center,
UI_TextOffsetX_Right
};
Enum(UI_TextOffsetY)
{
UI_TextOffsetY_Top, /* Default */
UI_TextOffsetY_Center,
UI_TextOffsetY_Bottom
};
Struct(UI_TextGlyph)
{
f32 off_x;
f32 off_y;
f32 width;
f32 height;
f32 advance;
ClipRect clip;
};
Struct(UI_TextLine)
{
f32 line_width;
u32 num_glyphs;
UI_TextGlyph *glyphs;
UI_TextLine *next;
};
Struct(UI_TextParams)
{
F_Font *font;
Vec2 pos;
f32 scale;
u32 color;
UI_TextAlignment alignment;
UI_TextOffsetX offset_x;
UI_TextOffsetY offset_y;
String str;
};
#define UI_TEXTPARAMS(...) ((UI_TextParams) { \
.scale = 1.0, \
.alignment = UI_TextAlignment_Left, \
.offset_x = UI_TextOffsetX_Left, \
.offset_y = UI_TextOffsetY_Top, \
.color = ColorWhite, \
__VA_ARGS__ \
})s
////////////////////////////////
//~ State types
Struct(UI_SharedState)
{
i32 _;
} extern UI_shared_state;
#endif
GPU_Resource *UI_EndBuild(Rect render_viewport);

View File

@ -4,14 +4,16 @@
@Dep gpu
//- Api
@IncludeC ui_flags.h
@IncludeC ui.h
@IncludeC ui_widgets.h
@IncludeC ui_util.h
@IncludeC ui_draw.h
@IncludeGpu ui_flags.h
@IncludeGpu ui_draw.h
//- Impl
@IncludeC ui.c
@IncludeC ui_widgets.c
@IncludeC ui_util.c
@IncludeGpu ui_draw.gpu
//- Shaders

View File

@ -5,7 +5,11 @@ ConstantBuffer<UI_RectSig> UI_rect_sig : register (b0);
Struct(UI_RectPS_Input)
{
Semantic(Vec4, sv_position);
Semantic(Vec4, tint_lin);
Semantic(Vec2, uv);
Semantic(nointerpolation u32, instance_idx);
};
Struct(UI_RectPS_Output)
@ -18,21 +22,25 @@ Struct(UI_RectPS_Output)
UI_RectPS_Input VSDef(UI_RectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid))
{
ConstantBuffer<UI_RectSig> sig = UI_rect_sig;
static const Vec2 unit_quad_verts[4] = {
Vec2(-0.5f, -0.5f),
Vec2(0.5f, -0.5f),
Vec2(0.5f, 0.5f),
Vec2(-0.5f, 0.5f)
static const Vec2 uvs[4] = {
Vec2(0, 0),
Vec2(1, 0),
Vec2(1, 1),
Vec2(0, 1),
};
StructuredBuffer<UI_RectInstance> instances = UniformResourceFromRid(sig.instances);
UI_RectInstance instance = instances[sv_instanceid];
Vec2 vert = unit_quad_verts[sv_vertexid];
// Vec2 world_pos = mul(instance.xf, Vec3(vert, 1)).xy;
Vec2 world_pos = 0;
Vec2 uv = uvs[sv_vertexid];
Vec2 vert = instance.p0 + (uv * instance.p1);
Vec2 ndc = NdcFromViewport(sig.viewport_size, vert);
UI_RectPS_Input result;
result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
result.sv_position = Vec4(ndc.xy, 0, 1);
result.tint_lin = LinearFromSrgbU32(instance.tint_srgb);
result.instance_idx = sv_instanceid;
result.uv = uv;
return result;
}
@ -41,7 +49,17 @@ UI_RectPS_Input VSDef(UI_RectVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_
UI_RectPS_Output PSDef(UI_RectPS, UI_RectPS_Input input)
{
ConstantBuffer<UI_RectSig> sig = UI_rect_sig;
f32 color = 0;
StructuredBuffer<UI_RectInstance> instances = UniformResourceFromRid(sig.instances);
UI_RectInstance instance = instances[input.instance_idx];
Vec4 color = input.tint_lin;
if (instance.flags & UI_Flag_DrawImage)
{
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
Texture2D<Vec4> tex = NonUniformResourceFromRid(instance.image_tex);
color *= tex.Sample(sampler, input.uv);
}
UI_RectPS_Output result;
result.sv_target0 = color;

View File

@ -4,21 +4,20 @@
Struct(UI_RectSig)
{
/* ----------------------------------------------------- */
Mat4x4 projection; /* 16 consts */
/* ----------------------------------------------------- */
Vec2I32 viewport_size; /* 02 consts */
StructuredBufferRid instances; /* 01 consts */
u32 _pad0; /* 01 consts (padding) */
u32 _pad1; /* 01 consts (padding) */
u32 _pad2; /* 01 consts (padding) */
SamplerStateRid sampler; /* 01 consts */
/* ----------------------------------------------------- */
};
AssertRootConst(UI_RectSig, 20);
AssertRootConst(UI_RectSig, 4);
Struct(UI_RectInstance)
{
u32 flags;
Vec2 p0;
Vec2 p1;
u32 tint_srgb;
Texture2DRid image_tex;
};
#define UI_DefaultRectInstance (UI_RectInstance) { \
0 \

8
src/ui/ui_flags.h Normal file
View File

@ -0,0 +1,8 @@
/* NOTE: UI flags are located here since they are shared between application & shader code */
Enum(UI_Flag)
{
UI_Flag_None = 0,
UI_Flag_DrawText = (1 << 0),
UI_Flag_DrawImage = (1 << 1),
};