268 lines
7.4 KiB
C
268 lines
7.4 KiB
C
SPR_Ctx SPR = Zi;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Bootstrap
|
|
|
|
void SPR_Bootstrap(void)
|
|
{
|
|
OnAsyncTick(SPR_TickAsync);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Key helpers
|
|
|
|
SPR_SheetKey SPR_SheetKeyFromResource(ResourceKey resource)
|
|
{
|
|
SPR_SheetKey result = Zi;
|
|
result.r = resource;
|
|
return result;
|
|
}
|
|
|
|
SPR_SpanKey SPR_SpanKeyFromName(String name)
|
|
{
|
|
SPR_SpanKey result = Zi;
|
|
// TODO
|
|
return result;
|
|
}
|
|
|
|
SPR_LayerKey SPR_LayerKeyFromName(String name)
|
|
{
|
|
SPR_LayerKey result = Zi;
|
|
// TODO
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Lookup
|
|
|
|
SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, SPR_SpanKey span, i64 frame_seq)
|
|
{
|
|
SPR_Slice result = Zi;
|
|
|
|
// TODO
|
|
|
|
return result;
|
|
}
|
|
|
|
// SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, SPR_SpanKey span, i64 frame_seq)
|
|
// {
|
|
// // TODO: Ability to specify desired alpha modes (Straight, Premultiplied, Opaque)
|
|
// SPR_Slice result = Zi;
|
|
|
|
// // FIXME
|
|
// u64 hash = sheet.r.v;
|
|
// hash = HashStringEx(hash, slice_name);
|
|
|
|
// i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy);
|
|
|
|
// // Search for existing entry
|
|
// b32 found = 0;
|
|
// SPR_SliceBin *bin = &SPR.slice_bins[hash % countof(SPR.slice_bins)];
|
|
// {
|
|
// Lock bin_lock = LockS(&bin->mutex);
|
|
// {
|
|
// SPR_SliceEntry *entry = bin->first;
|
|
// for (; entry; entry = entry->next)
|
|
// {
|
|
// if (entry->hash == hash)
|
|
// {
|
|
// break;
|
|
// }
|
|
// }
|
|
// if (entry)
|
|
// {
|
|
// if (completion >= Atomic64Fetch(&entry->async_copy_completion_target))
|
|
// {
|
|
// result = entry->slice;
|
|
// }
|
|
// found = 1;
|
|
// }
|
|
// }
|
|
// Unlock(&bin_lock);
|
|
// }
|
|
|
|
// // Push new entry
|
|
// if (!found)
|
|
// {
|
|
// Lock submit_lock = LockE(&SPR.submit.mutex);
|
|
// Lock bin_lock = LockE(&bin->mutex);
|
|
// {
|
|
// SPR_SliceEntry *entry = bin->first;
|
|
// for (; entry; entry = entry->next)
|
|
// {
|
|
// if (entry->hash == hash)
|
|
// {
|
|
// break;
|
|
// }
|
|
// }
|
|
// if (entry)
|
|
// {
|
|
// if (completion >= Atomic64Fetch(&entry->async_copy_completion_target))
|
|
// {
|
|
// result = entry->slice;
|
|
// }
|
|
// found = 1;
|
|
// }
|
|
// else
|
|
// {
|
|
// Arena *perm = PermArena();
|
|
|
|
// entry = PushStruct(perm, SPR_SliceEntry);
|
|
// entry->hash = hash;
|
|
// Atomic64FetchSet(&entry->async_copy_completion_target, I64Max);
|
|
// entry->sheet = sheet;
|
|
// entry->slice_name = PushString(perm, slice_name);
|
|
// SllStackPush(bin->first, entry);
|
|
|
|
// SPR_CmdNode *n = SPR.submit.first_free;
|
|
// if (n)
|
|
// {
|
|
// SllStackPop(SPR.submit.first_free);
|
|
// ZeroStruct(n);
|
|
// }
|
|
// else
|
|
// {
|
|
// n = PushStruct(perm, SPR_CmdNode);
|
|
// }
|
|
// n->cmd.entry = entry;
|
|
// SllQueuePush(SPR.submit.first, SPR.submit.last, n);
|
|
// ++SPR.submit.count;
|
|
// Atomic32FetchSet(&SPR.new_cmds_present, 1);
|
|
// SignalAsyncTick();
|
|
// }
|
|
// }
|
|
// Unlock(&bin_lock);
|
|
// Unlock(&submit_lock);
|
|
// }
|
|
|
|
// if (G_IsRefNil(result.tex))
|
|
// {
|
|
// result.tex = G_BlankTexture2D();
|
|
// result.uv_rect.p0 = VEC2(0, 0);
|
|
// result.uv_rect.p1 = VEC2(1, 1);
|
|
// }
|
|
|
|
// return result;
|
|
// }
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Async
|
|
|
|
void SPR_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame)
|
|
{
|
|
Arena *perm = PermArena();
|
|
SPR_AsyncCtx *async = &SPR.async;
|
|
Arena *frame_arena = base_async_lane_frame->arena;
|
|
|
|
// TODO: Go wide
|
|
if (lane->idx == 0)
|
|
{
|
|
if (Atomic32Fetch(&SPR.new_cmds_present))
|
|
{
|
|
Atomic32Set(&SPR.new_cmds_present, 0);
|
|
SPR_CmdNode *first_cmd_node = 0;
|
|
SPR_CmdNode *last_cmd_node = 0;
|
|
u64 cmds_count = 0;
|
|
{
|
|
Lock lock = LockE(&SPR.submit.mutex);
|
|
{
|
|
first_cmd_node = SPR.submit.first;
|
|
last_cmd_node = SPR.submit.last;
|
|
cmds_count = SPR.submit.count;
|
|
SPR.submit.first = 0;
|
|
SPR.submit.last = 0;
|
|
SPR.submit.count = 0;
|
|
}
|
|
Unlock(&lock);
|
|
}
|
|
if (cmds_count > 0)
|
|
{
|
|
for (SPR_CmdNode *n = first_cmd_node; n; n = n->next)
|
|
{
|
|
SPR_Cmd cmd = n->cmd;
|
|
SPR_SliceEntry *slice_entry = cmd.entry;
|
|
|
|
SPR_SheetBin *sheet_bin = &async->sheet_bins[slice_entry->sheet.r.v % countof(async->sheet_bins)];
|
|
SPR_SheetEntry *sheet = sheet_bin->first;
|
|
for (; sheet; sheet = sheet->next)
|
|
{
|
|
if (sheet->key.r.v == slice_entry->sheet.r.v)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Decode sheet
|
|
// TODO: Distribute chunk decoding accross wave
|
|
// TODO: Use atlas allocator and separate slices into unique textures
|
|
// TODO: Reuse command list for all uploads
|
|
if (!sheet)
|
|
{
|
|
sheet = PushStruct(perm, SPR_SheetEntry);
|
|
sheet->key = slice_entry->sheet;
|
|
SllStackPush(sheet_bin->first, sheet);
|
|
|
|
String encoded = DataFromResource(sheet->key.r);
|
|
String name = NameFromResource(sheet->key.r);
|
|
LogInfoF("Decoding sprite sheet \"%F\" (%F bytes)", FmtString(name), FmtUint(encoded.len));
|
|
|
|
ASE_DecodedImage decoded_image = ASE_DecodeImage(frame_arena, encoded);
|
|
ASE_DecodedSheet decoded_sheet = ASE_DecodeSheet(frame_arena, encoded);
|
|
|
|
if (decoded_image.ok)
|
|
{
|
|
G_ResourceHandle gpu_resource = Zi;
|
|
G_ArenaHandle gpu_perm = G_PermArena();
|
|
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy);
|
|
{
|
|
Vec3I32 dims = Zi;
|
|
dims.x = decoded_image.width;
|
|
dims.y = decoded_image.height;
|
|
dims.z = 1;
|
|
gpu_resource = G_PushTexture2D(
|
|
gpu_perm, cl,
|
|
G_Format_R8G8B8A8_Unorm_Srgb,
|
|
dims,
|
|
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present
|
|
);
|
|
G_CopyCpuToTexture(
|
|
cl,
|
|
gpu_resource, VEC3I32(0, 0, 0),
|
|
decoded_image.pixels, dims,
|
|
RNG3I32(
|
|
VEC3I32(0, 0, 0),
|
|
dims
|
|
)
|
|
);
|
|
}
|
|
i64 completion_target = G_CommitCommandList(cl);
|
|
sheet->async_copy_completion_target = completion_target;
|
|
sheet->tex = G_PushTexture2DRef(gpu_perm, gpu_resource);
|
|
// LogDebugF("Decoded with ref: %F", FmtUint(slice_entry->slice.tex.v));
|
|
}
|
|
else
|
|
{
|
|
// TODO: Use 'missing' texture
|
|
sheet->tex = G_BlankTexture2D();
|
|
sheet->async_copy_completion_target = 0;
|
|
}
|
|
}
|
|
slice_entry->slice.tex = sheet->tex;
|
|
// FIXME: Real uv
|
|
slice_entry->slice.uv_rect.p0 = VEC2(0, 0);
|
|
slice_entry->slice.uv_rect.p1= VEC2(1, 1);
|
|
Atomic64Set(&slice_entry->async_copy_completion_target, sheet->async_copy_completion_target);
|
|
}
|
|
|
|
// Free cmds
|
|
Lock lock = LockE(&SPR.submit.mutex);
|
|
{
|
|
last_cmd_node->next = SPR.submit.first_free;
|
|
SPR.submit.first_free = first_cmd_node;
|
|
}
|
|
Unlock(&lock);
|
|
}
|
|
}
|
|
}
|
|
}
|