begin reworking format utils to take argument arrays instead of only va_list

This commit is contained in:
jacob 2025-12-10 21:19:23 -06:00
parent bc76a511e6
commit 4fe18195d1
5 changed files with 200 additions and 123 deletions

View File

@ -531,13 +531,14 @@ String TrimWhitespace(String s)
*
* FmtEnd (internal): Denote the end of the va_list
*/
String FormatStringV(Arena *arena, String fmt, va_list args)
String FormatString(Arena *arena, String fmt, FmtArgArray args)
{
u64 final_len = 0;
u8 *final_text = ArenaNext(arena, u8);
String result = ZI;
result.text = ArenaNext(arena, u8);
u8 *end = fmt.text + fmt.len;
b32 no_more_args = 0;
u64 arg_idx = 0;
for (u8 *c = fmt.text; c < end; ++c)
{
u8 *next = ((c + 1) < end) ? (c + 1) : (u8 *)"\0";
@ -546,80 +547,92 @@ String FormatStringV(Arena *arena, String fmt, va_list args)
b32 escape = !no_more_args && *c == '%' && *next == '%';
if (escape)
{
/* Skip the escape '%' char from parsing */
/* Skip the escaped '%' char from parsing */
++c;
}
if (!no_more_args && !escape && *c == '%' && *next == 'F')
{
String parsed_str = ZI;
/* Detect arg type and parse to string */
FmtArg arg = va_arg(args, FmtArg);
String parsed_arg = ZI;
FmtArg arg = ZI;
if (arg_idx < args.count)
{
arg = args.args[arg_idx];
++arg_idx;
}
else
{
no_more_args = 1;
}
switch (arg.kind)
{
default:
{
/* Unknown format type */
Assert(0);
parsed_str = PushString(arena, Lit("<?>"));
parsed_arg = PushString(arena, Lit("<?>"));
no_more_args = 1;
} break;
case FmtArgKind_Char:
{
parsed_str = StringFromChar(arena, arg.value.c);
parsed_arg = StringFromChar(arena, arg.value.c);
} break;
case FmtArgKind_String:
{
parsed_str = PushString(arena, arg.value.string);
parsed_arg = PushString(arena, arg.value.string);
} break;
case FmtArgKind_Uint:
{
parsed_str = StringFromU64(arena, arg.value.uint, 10, arg.z);
parsed_arg = StringFromU64(arena, arg.value.uint, 10, arg.z);
} break;
case FmtArgKind_Sint:
{
parsed_str = StringFromI64(arena, arg.value.sint, 10, arg.z);
parsed_arg = StringFromI64(arena, arg.value.sint, 10, arg.z);
} break;
case FmtArgKind_Hex:
{
parsed_str = StringFromU64(arena, arg.value.sint, 16, arg.z);
parsed_arg = StringFromU64(arena, arg.value.sint, 16, arg.z);
} break;
case FmtArgKind_Ptr:
{
parsed_str = StringFromPtr(arena, arg.value.ptr);
parsed_arg = StringFromPtr(arena, arg.value.ptr);
} break;
case FmtArgKind_Float:
{
parsed_str = StringFromF64(arena, arg.value.f, arg.p);
parsed_arg = StringFromF64(arena, arg.value.f, arg.p);
} break;
case FmtArgKind_Handle:
{
parsed_str = StringFromhandle(arena, arg.value.handle.h64[0], arg.value.handle.h64[1]);
parsed_arg = StringFromhandle(arena, arg.value.handle.h64[0], arg.value.handle.h64[1]);
} break;
case FmtArgKind_Uid:
{
parsed_str = StringFromUid(arena, arg.value.uid);
parsed_arg = StringFromUid(arena, arg.value.uid);
} break;
case FmtArgKind_End:
{
/* Unexpected end. Not enough FMT args passed to function. */
Assert(0);
parsed_str = PushString(arena, Lit("<?>"));
parsed_arg = PushString(arena, Lit("<?>"));
no_more_args = 1;
} break;
}
/* Update final string len / start */
final_len += parsed_str.len;
final_len += parsed_arg.len;
/* Skip 'F' from parsing */
++c;
}
@ -634,26 +647,63 @@ String FormatStringV(Arena *arena, String fmt, va_list args)
#if IsRtcEnabled
if (!no_more_args)
{
FmtArg last_arg = va_arg(args, FmtArg);
/* End arg not reached. Too many FMT values passed to function. */
FmtArg last_arg = ZI;
if (arg_idx < args.count)
{
last_arg = args.args[arg_idx];
}
/* End arg not reached. Too many args supplied. */
Assert(last_arg.kind == FmtArgKind_End);
}
#endif
return (String)
{
.len = final_len,
.text = final_text
};
return result;
}
String FormatString_(Arena *arena, String fmt, ...)
String FormatStringV_(Arena *arena, String fmt, ...)
{
va_list args;
va_start(args, fmt);
String new_str = FormatStringV(arena, fmt, args);
String result = FormatStringVL(arena, fmt, args);
va_end(args);
return new_str;
return result;
}
FmtArgArray FmtArgsFromVaList(Arena *arena, va_list args)
{
FmtArgArray result = ZI;
result.args = ArenaNext(arena, FmtArg);
{
b32 done = 0;
while (!done)
{
FmtArg arg = va_arg(args, FmtArg);
*PushStructNoZero(arena, FmtArg) = arg;
++result.count;
switch (arg.kind)
{
default:
{
/* Last arg reached */
done = 1;
} break;
case FmtArgKind_Char:
case FmtArgKind_String:
case FmtArgKind_Uint:
case FmtArgKind_Sint:
case FmtArgKind_Hex:
case FmtArgKind_Ptr:
case FmtArgKind_Float:
case FmtArgKind_Uid:
case FmtArgKind_Handle:
{
/* Continue */
} break;
}
}
}
return result;
}
////////////////////////////////////////////////////////////

View File

@ -43,6 +43,12 @@ Struct(FmtArg)
} value;
};
Struct(FmtArgArray)
{
u64 count;
FmtArg *args;
};
////////////////////////////////////////////////////////////
//~ Unicode types
@ -111,10 +117,23 @@ String StringFromList(Arena *arena, StringList l, String separator);
#define FmtUid(v, ...) FMTARG(FmtArgKind_Uid, .value.uid = (v), __VA_ARGS__)
#define FmtEnd FMTARG(FmtArgKind_End) /* Denotes end of VA list */
#define StringF(arena, lit, ...) FormatString_((arena), Lit(lit), __VA_ARGS__, FmtEnd)
#define FormatString(arena, fmt, ...) FormatString_((arena), (fmt), __VA_ARGS__, FmtEnd)
String FormatString_(Arena *arena, String fmt, ...);
String FormatStringV(Arena *arena, String fmt, va_list args);
// #define StringF(arena, lit, ...) FormatString_((arena), Lit(lit), __VA_ARGS__, FmtEnd)
// #define FormatString(arena, fmt, ...) FormatString_((arena), (fmt), __VA_ARGS__, FmtEnd)
// String FormatString_(Arena *arena, String fmt, ...);
// String FormatStringV(Arena *arena, String fmt, va_list args);
String FormatString(Arena *arena, String fmt, FmtArgArray args);
String StringF_(Arena *arena, String fmt, ...);
#define StringF(arena, lit, ...) StringF_((arena), Lit(lit), __VA_ARGS__, FmtEnd)
FmtArgArray FmtArgsFromVaList(Arena *arena, va_list vl);
////////////////////////////////////////////////////////////
//~ Unicode

View File

@ -724,11 +724,11 @@ void G_Compute(G_CommandListHandle cl, ComputeShader cs, Vec3I32 groups);
//- Rasterize
void G_Rasterize(G_CommandListHandle cl,
VertexShader vs, PixelShader ps,
u32 instances_count, G_IndexBufferDesc index_buffer,
u32 render_targets_count, G_ResourceHandle *render_targets,
Rng3 viewport, Rng2 scissor,
G_RasterMode mode);
VertexShader vs, PixelShader ps,
u32 instances_count, G_IndexBufferDesc index_buffer,
u32 render_targets_count, G_ResourceHandle *render_targets,
Rng3 viewport, Rng2 scissor,
G_RasterMode mode);
//- Clear

View File

@ -137,7 +137,7 @@ void G_Bootstrap(void)
hr = DXGIGetDebugInterface1(0, &IID_IDXGIInfoQueue, (void **)&dxgi_info);
if (FAILED(hr))
{
Panic(Lit("Failed to get DXGI debug interface"));
Panic(Lit("Failed to retrieve DXGI debug interface"));
}
IDXGIInfoQueue_SetBreakOnSeverity(dxgi_info, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, 1);
IDXGIInfoQueue_SetBreakOnSeverity(dxgi_info, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, 1);
@ -487,68 +487,75 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
if (ok && (!IsResourceNil(desc.vs.resource) || !IsResourceNil(desc.ps.resource)))
{
D3D12_RASTERIZER_DESC raster_desc = ZI;
if (desc.is_wireframe)
{
raster_desc.FillMode = D3D12_FILL_MODE_WIREFRAME;
}
else
{
raster_desc.FillMode = D3D12_FILL_MODE_SOLID;
}
raster_desc.CullMode = D3D12_CULL_MODE_NONE;
raster_desc.FrontCounterClockwise = 0;
raster_desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
raster_desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
raster_desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
raster_desc.DepthClipEnable = 1;
raster_desc.MultisampleEnable = 0;
raster_desc.AntialiasedLineEnable = 0;
raster_desc.ForcedSampleCount = 0;
raster_desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
D3D12_BLEND_DESC blend_desc = ZI;
blend_desc.AlphaToCoverageEnable = 0;
blend_desc.IndependentBlendEnable = 0;
blend_desc.RenderTarget[0].BlendEnable = 1;
blend_desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
blend_desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
blend_desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
blend_desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
blend_desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
D3D12_DEPTH_STENCIL_DESC ds_desc = ZI;
ds_desc.DepthEnable = 0;
ds_desc.StencilEnable = 0;
String vs = DataFromResource(desc.vs.resource);
String ps = DataFromResource(desc.ps.resource);
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = ZI;
pso_desc.pRootSignature = g->bindless_rootsig;
pso_desc.VS.pShaderBytecode = vs.text;
pso_desc.VS.BytecodeLength = vs.len;
pso_desc.PS.pShaderBytecode = ps.text;
pso_desc.PS.BytecodeLength = ps.len;
pso_desc.RasterizerState = raster_desc;
pso_desc.BlendState = blend_desc;
pso_desc.DepthStencilState = ds_desc;
pso_desc.PrimitiveTopologyType = desc.topology_type;
pso_desc.SampleMask = UINT_MAX;
pso_desc.SampleDesc.Count = 1;
pso_desc.SampleDesc.Quality = 0;
for (i32 i = 0; i < (i32)countof(desc.render_target_formats); ++i)
{
StaticAssert(countof(pso_desc.RTVFormats) <= countof(desc.render_target_formats));
DXGI_FORMAT format = G_D12_DxgiFormatFromGpuFormat(desc.render_target_formats[i]);
if (format != DXGI_FORMAT_UNKNOWN)
if (desc.is_wireframe)
{
pso_desc.RTVFormats[pso_desc.NumRenderTargets++] = format;
raster_desc.FillMode = D3D12_FILL_MODE_WIREFRAME;
}
else
{
break;
raster_desc.FillMode = D3D12_FILL_MODE_SOLID;
}
raster_desc.CullMode = D3D12_CULL_MODE_NONE;
raster_desc.FrontCounterClockwise = 0;
raster_desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
raster_desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
raster_desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
raster_desc.DepthClipEnable = 1;
raster_desc.MultisampleEnable = 0;
raster_desc.AntialiasedLineEnable = 0;
raster_desc.ForcedSampleCount = 0;
raster_desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
}
D3D12_BLEND_DESC blend_desc = ZI;
{
blend_desc.AlphaToCoverageEnable = 0;
blend_desc.IndependentBlendEnable = 0;
blend_desc.RenderTarget[0].BlendEnable = 1;
blend_desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
blend_desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
blend_desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
blend_desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
blend_desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
}
D3D12_DEPTH_STENCIL_DESC ds_desc = ZI;
{
ds_desc.DepthEnable = 0;
ds_desc.StencilEnable = 0;
}
String vs = DataFromResource(desc.vs.resource);
String ps = DataFromResource(desc.ps.resource);
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = ZI;
{
pso_desc.pRootSignature = g->bindless_rootsig;
pso_desc.VS.pShaderBytecode = vs.text;
pso_desc.VS.BytecodeLength = vs.len;
pso_desc.PS.pShaderBytecode = ps.text;
pso_desc.PS.BytecodeLength = ps.len;
pso_desc.RasterizerState = raster_desc;
pso_desc.BlendState = blend_desc;
pso_desc.DepthStencilState = ds_desc;
pso_desc.PrimitiveTopologyType = desc.topology_type;
pso_desc.SampleMask = UINT_MAX;
pso_desc.SampleDesc.Count = 1;
pso_desc.SampleDesc.Quality = 0;
for (i32 i = 0; i < (i32)countof(desc.render_target_formats); ++i)
{
StaticAssert(countof(pso_desc.RTVFormats) <= countof(desc.render_target_formats));
DXGI_FORMAT format = G_D12_DxgiFormatFromGpuFormat(desc.render_target_formats[i]);
if (format != DXGI_FORMAT_UNKNOWN)
{
pso_desc.RTVFormats[pso_desc.NumRenderTargets++] = format;
}
else
{
break;
}
}
}
hr = ID3D12Device_CreateGraphicsPipelineState(g->device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
@ -561,11 +568,12 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
else if (ok)
{
String cs = DataFromResource(desc.cs.resource);
D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc = ZI;
pso_desc.pRootSignature = g->bindless_rootsig;
pso_desc.CS.pShaderBytecode = cs.text;
pso_desc.CS.BytecodeLength = cs.len;
{
pso_desc.pRootSignature = g->bindless_rootsig;
pso_desc.CS.pShaderBytecode = cs.text;
pso_desc.CS.BytecodeLength = cs.len;
}
hr = ID3D12Device_CreateComputePipelineState(g->device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
if (FAILED(hr))
{
@ -2748,7 +2756,7 @@ G_ResourceHandle G_PrepareBackbuffer(G_SwapchainHandle swapchain_handle, G_Forma
if (FAILED(hr))
{
/* TODO: Don't panic */
Panic(Lit("Failed to get swapchain buffer"));
Panic(Lit("Failed to retrieve swapchain buffer"));
}
ZeroStruct(backbuffer);
backbuffer->d3d_resource = d3d_resource;
@ -2825,6 +2833,8 @@ void G_CommitBackbuffer(G_ResourceHandle backbuffer_handle, i32 vsync)
////////////////////////////////////////////////////////////
//~ Collection worker
/* TODO: Move this to common */
void G_D12_CollectionWorkerEntry(WaveLaneCtx *lane)
{
G_QueueKind queue_kind = G_QueueKind_Direct;
@ -2852,8 +2862,8 @@ void G_D12_CollectionWorkerEntry(WaveLaneCtx *lane)
G_CopyBufferToBuffer(cl, readback_buff, 0, queue->print_buffer, RNGU64(0, queue->print_buffer_size));
/* Reset counters to 0 */
G_MemorySync(cl, queue->print_buffer,
G_Stage_Copy, G_Access_CopyRead,
G_Stage_Copy, G_Access_CopyWrite
G_Stage_Copy, G_Access_CopyRead,
G_Stage_Copy, G_Access_CopyWrite
);
u8 zero[12] = ZI;
G_CopyCpuToBuffer(cl, queue->print_buffer, 0, zero, RNGU64(0, sizeof(zero)));
@ -2861,6 +2871,7 @@ void G_D12_CollectionWorkerEntry(WaveLaneCtx *lane)
G_CommitCommandList(cl);
G_SyncCpu(G_MaskFromQueue(queue_kind));
u32 attempted_print_bytes_count = *(G_StructFromResource(readback_buff, u32) + 0);
u32 prints_count = *(G_StructFromResource(readback_buff, u32) + 1);
u32 overflows_count = *(G_StructFromResource(readback_buff, u32) + 2);
@ -2891,49 +2902,44 @@ void G_D12_CollectionWorkerEntry(WaveLaneCtx *lane)
at += chars_count;
}
FmtArg *args = 0;
FmtArgArray args = ZI;
args.count = args_count;
{
if (args_count > 0)
{
args = PushStructs(scratch.arena, FmtArg, args_count);
args.args = PushStructs(scratch.arena, FmtArg, args_count);
for (u32 arg_idx = 0; arg_idx <= args_count; ++arg_idx)
{
G_FmtArgKind gpu_kind = (G_FmtArgKind)(*at);
at += 1;
u32 gpu_data = *(u32 *)at;
u32 gpu_value = *(u32 *)at;
at += 4;
FmtArg *dst = &args[arg_idx];
FmtArg *dst = &args.args[arg_idx];
switch (gpu_kind)
{
case G_FmtArgKind_U32:
{
dst->kind = FmtArgKind_Uint;
dst->value.uint = gpu_data;
dst->value.uint = gpu_value;
} break;
case G_FmtArgKind_I32:
{
dst->kind = FmtArgKind_Sint;
dst->value.sint = (i32)gpu_data;
dst->value.sint = (i32)gpu_value;
} break;
case G_FmtArgKind_F32:
{
dst->kind = FmtArgKind_Float;
dst->value.f = *(f32 *)&gpu_data;
dst->value.f = *(f32 *)&gpu_value;
} break;
}
}
}
}
// String final_str = ZI;
// if (args_count > 0)
// {
// }
// else
// {
// final_str = PushString(scratch.arena, fmt);
// }
String final_str = FormatString(scratch.arena, fmt, args);
at = (u8 *)AlignU64((u64)at, 4);
}

View File

@ -160,11 +160,12 @@ Struct(G_FmtArg)
u32 chunks_count = (buff.char_pos + 3) / 4;
u32 alloc_size = 0;
alloc_size += 4; /* Header */
alloc_size += chunks_count * 4; /* Chunks */
alloc_size += 4; /* Header */
alloc_size += chunks_count * 4; /* Chunks */
/* Atomic fetch + add to base counter */
u32 base;
rw.InterlockedAdd(0, alloc_size, base); /* Write to base counter */
rw.InterlockedAdd(0, alloc_size, base);
u32 pos = base;
pos += 4; /* Offset for base counter */
@ -176,7 +177,7 @@ Struct(G_FmtArg)
/* Increment success counter */
rw.InterlockedAdd(4, 1);
/* Store header */
/* Write header */
{
u32 header = 0;
header |= (buff.fmt_size << 0) & 0x0000FFFF;
@ -184,7 +185,8 @@ Struct(G_FmtArg)
rw.Store(base + pos, header);
pos += 4;
}
/* Store chunks */
/* Write chunks */
for (u32 chunk_idx = 0; chunk_idx < chunks_count; ++chunk_idx)
{
u32 chunk = buff.char_chunks[chunk_idx];