use premultiplied alpha for ui composition

This commit is contained in:
jacob 2026-01-02 18:15:30 -06:00
parent 8aa44b5deb
commit ba8b1667db
14 changed files with 256 additions and 140 deletions

View File

@ -260,25 +260,30 @@ Vec4 SrgbFromLinear(Vec4 lin)
return result; return result;
} }
u32 LinearU32FromSrgb(Vec4 srgb) Vec4 PremulFromLinear(Vec4 lin)
{
Vec4 result = Zi;
result.x = lin.x * lin.w;
result.y = lin.y * lin.w;
result.z = lin.z * lin.w;
result.w = lin.w;
return result;
}
Vec4 PremulFromSrgb(Vec4 srgb)
{ {
Vec4 lin = LinearFromSrgb(srgb); Vec4 lin = LinearFromSrgb(srgb);
u32 result = U32FromVec4(lin); Vec4 premul = PremulFromLinear(lin);
return result; return premul;
} }
Vec4 LerpSrgb(Vec4 v0, Vec4 v1, f32 t) Vec4 LerpSrgb(Vec4 v0, Vec4 v1, f32 t)
{ {
Vec4 v0_l = LinearFromSrgb(v0); Vec4 result = Zi;
Vec4 v1_l = LinearFromSrgb(v1); Vec4 v0_lin = LinearFromSrgb(v0);
Vec4 blend_l = Zi; Vec4 v1_lin = LinearFromSrgb(v1);
{ Vec4 lerp_lin = LerpVec4(v0_lin, v1_lin, t);
blend_l.x = LerpF32(v0_l.x, v1_l.x, t); result = SrgbFromLinear(lerp_lin);
blend_l.y = LerpF32(v0_l.y, v1_l.y, t);
blend_l.z = LerpF32(v0_l.z, v1_l.z, t);
blend_l.w = LerpF32(v0_l.w, v1_l.w, t);
}
Vec4 result = SrgbFromLinear(blend_l);
return result; return result;
} }
@ -494,21 +499,21 @@ Vec2 ClosestPointFromRay(Vec2 ray_pos, Vec2 ray_dir_norm, Vec2 p)
//- Lerp //- Lerp
// Interpolate position vectors // Interpolate position vectors
Vec2 LerpVec2(Vec2 val0, Vec2 val1, f32 t) Vec2 LerpVec2(Vec2 v0, Vec2 v1, f32 t)
{ {
return VEC2(LerpF32(val0.x, val1.x, t), LerpF32(val0.y, val1.y, t)); return VEC2(LerpF32(v0.x, v1.x, t), LerpF32(v0.y, v1.y, t));
} }
Vec2 LerpVec2Vec2(Vec2 val0, Vec2 val1, Vec2 t) Vec2 LerpVec2Vec2(Vec2 v0, Vec2 v1, Vec2 t)
{ {
return VEC2(LerpF32(val0.x, val1.x, t.x), LerpF32(val0.y, val1.y, t.y)); return VEC2(LerpF32(v0.x, v1.x, t.x), LerpF32(v0.y, v1.y, t.y));
} }
// Interpolate direction vectors (spherical lerp) // Interpolate direction vectors (spherical lerp)
Vec2 SlerpVec2(Vec2 val0, Vec2 val1, f32 t) Vec2 SlerpVec2(Vec2 v0, Vec2 v1, f32 t)
{ {
f32 rot = LerpAngleF32(AngleFromVec2(val0), AngleFromVec2(val1), t); f32 rot = LerpAngleF32(AngleFromVec2(v0), AngleFromVec2(v1), t);
f32 len = LerpF32(Vec2Len(val0), Vec2Len(val1), t); f32 len = LerpF32(Vec2Len(v0), Vec2Len(v1), t);
return MulVec2(Vec2FromAngle(rot), len); return MulVec2(Vec2FromAngle(rot), len);
} }
@ -560,6 +565,18 @@ Vec4 MulVec4Vec4(Vec4 a, Vec4 b)
return VEC4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); return VEC4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
} }
//- Lerp
Vec4 LerpVec4(Vec4 v0, Vec4 v1, f32 t)
{
Vec4 result = Zi;
result.x = LerpF32(v0.x, v1.x, t);
result.y = LerpF32(v0.y, v1.y, t);
result.z = LerpF32(v0.z, v1.z, t);
result.w = LerpF32(v0.w, v1.w, t);
return result;
}
//- Conversion //- Conversion
Vec4 Vec4FromU32(u32 v) Vec4 Vec4FromU32(u32 v)

View File

@ -297,9 +297,14 @@ i64 LerpU64(u64 val0, u64 val1, f64 t);
f32 SrgbFromLinearF32(f32 lin); f32 SrgbFromLinearF32(f32 lin);
f32 LinearFromSrgbF32(f32 srgb); f32 LinearFromSrgbF32(f32 srgb);
Vec4 LinearFromSrgb(Vec4 srgb); Vec4 LinearFromSrgb(Vec4 srgb);
Vec4 SrgbFromLinear(Vec4 lin); Vec4 SrgbFromLinear(Vec4 lin);
u32 LinearU32FromSrgb(Vec4 srgb);
Vec4 PremulFromLinear(Vec4 lin);
Vec4 PremulFromSrgb(Vec4 srgb);
// Vec4 LerpLinear(Vec4 v0, Vec4 v1, f32 t);
Vec4 LerpSrgb(Vec4 v0, Vec4 v1, f32 t); Vec4 LerpSrgb(Vec4 v0, Vec4 v1, f32 t);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -356,9 +361,9 @@ f32 AngleFromVec2Points(Vec2 pt1, Vec2 pt2);
Vec2 ClosestPointFromRay(Vec2 ray_pos, Vec2 ray_dir_norm, Vec2 p); Vec2 ClosestPointFromRay(Vec2 ray_pos, Vec2 ray_dir_norm, Vec2 p);
//- Lerp //- Lerp
Vec2 LerpVec2(Vec2 val0, Vec2 val1, f32 t); Vec2 LerpVec2(Vec2 v0, Vec2 v1, f32 t);
Vec2 LerpVec2Vec2(Vec2 val0, Vec2 val1, Vec2 t); Vec2 LerpVec2Vec2(Vec2 v0, Vec2 v1, Vec2 t);
Vec2 SlerpVec2(Vec2 val0, Vec2 val1, f32 t); Vec2 SlerpVec2(Vec2 v0, Vec2 v1, f32 t);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Vec2I32 //~ Vec2I32
@ -375,6 +380,10 @@ Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b);
Vec4 MulVec4(Vec4 v, f32 s); Vec4 MulVec4(Vec4 v, f32 s);
Vec4 MulVec4Vec4(Vec4 a, Vec4 b); Vec4 MulVec4Vec4(Vec4 a, Vec4 b);
//- Lerp
Vec4 LerpVec4(Vec4 v0, Vec4 v1, f32 t);
//- Conversion //- Conversion
Vec4 Vec4FromU32(u32 v); Vec4 Vec4FromU32(u32 v);
u32 U32FromVec4(Vec4 v); u32 U32FromVec4(Vec4 v);

View File

@ -86,7 +86,7 @@ u32 countof(T arr[N])
Vec4 Vec4FromU32(u32 v) Vec4 Vec4FromU32(u32 v)
{ {
Vec4 result; Vec4 result = 0;
result.x = ((v >> 0) & 0xFF) / 255.0; result.x = ((v >> 0) & 0xFF) / 255.0;
result.y = ((v >> 8) & 0xFF) / 255.0; result.y = ((v >> 8) & 0xFF) / 255.0;
result.z = ((v >> 16) & 0xFF) / 255.0; result.z = ((v >> 16) & 0xFF) / 255.0;
@ -96,7 +96,7 @@ Vec4 Vec4FromU32(u32 v)
u32 U32FromVec4(Vec4 v) u32 U32FromVec4(Vec4 v)
{ {
u32 result; u32 result = 0;
result |= (((u32)(v.x * 255.0)) & 0xFF) << 0; result |= (((u32)(v.x * 255.0)) & 0xFF) << 0;
result |= (((u32)(v.y * 255.0)) & 0xFF) << 8; result |= (((u32)(v.y * 255.0)) & 0xFF) << 8;
result |= (((u32)(v.z * 255.0)) & 0xFF) << 16; result |= (((u32)(v.z * 255.0)) & 0xFF) << 16;
@ -128,6 +128,14 @@ Vec4 LinearFromSrgb(Vec4 srgb)
return result; return result;
} }
Vec4 Premul(Vec4 v)
{
Vec4 result;
result.rgb = v.rgb * v.a;
result.a = v.a;
return result;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Vertex ID helpers //~ Vertex ID helpers

View File

@ -107,6 +107,6 @@ f64 TweakFloat_(String name, f64 initial, TweakFloatDesc desc);
.category = Lit("Debug"), \ .category = Lit("Debug"), \
.min = (_min), \ .min = (_min), \
.max = (_max), \ .max = (_max), \
.precision = 2, \ .precision = 3, \
__VA_ARGS__ \ __VA_ARGS__ \
}) })

View File

@ -479,6 +479,13 @@ Enum(G_RasterMode)
G_RasterMode_WireTriangleStrip, G_RasterMode_WireTriangleStrip,
}; };
Enum(G_BlendMode)
{
G_BlendMode_Opaque,
G_BlendMode_CompositeStraightAlpha,
G_BlendMode_CompositePremultipliedAlpha,
};
Struct(G_IndexBufferDesc) Struct(G_IndexBufferDesc)
{ {
G_ResourceHandle resource; G_ResourceHandle resource;
@ -486,6 +493,12 @@ Struct(G_IndexBufferDesc)
u32 index_count; u32 index_count;
}; };
Struct(G_RenderTargetDesc)
{
G_ResourceHandle resource;
G_BlendMode blend;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Statistic types //~ Statistic types
@ -585,6 +598,10 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena, G_CommandListHandle cl, G_R
#define G_IdxBuff16(_res) ((G_IndexBufferDesc) { .resource = (_res), .index_size = 2, .index_count = (G_CountBuffer((_res), i16)) }) #define G_IdxBuff16(_res) ((G_IndexBufferDesc) { .resource = (_res), .index_size = 2, .index_count = (G_CountBuffer((_res), i16)) })
#define G_IdxBuff32(_res) ((G_IndexBufferDesc) { .resource = (_res), .index_size = 4, .index_count = (G_CountBuffer((_res), i32)) }) #define G_IdxBuff32(_res) ((G_IndexBufferDesc) { .resource = (_res), .index_size = 4, .index_count = (G_CountBuffer((_res), i32)) })
//- Render target helpers
#define G_Rt(_res, _blend_mode) ((G_RenderTargetDesc) { .resource = (_res), .blend = (_blend_mode) })
//- Count //- Count
u64 G_CountBufferBytes(G_ResourceHandle buffer); u64 G_CountBufferBytes(G_ResourceHandle buffer);
@ -765,9 +782,9 @@ void G_Rasterize(
G_CommandListHandle cl, G_CommandListHandle cl,
VertexShader vs, PixelShader ps, VertexShader vs, PixelShader ps,
u32 instances_count, G_IndexBufferDesc index_buffer, u32 instances_count, G_IndexBufferDesc index_buffer,
u32 render_targets_count, G_ResourceHandle *render_targets, u32 render_targets_count, G_RenderTargetDesc *render_targets,
Rng3 viewport, Rng2 scissor, Rng3 viewport, Rng2 scissor,
G_RasterMode mode G_RasterMode raster_mode
); );
//- Clear //- Clear

View File

@ -496,6 +496,30 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
ID3D12PipelineState *pso = 0; ID3D12PipelineState *pso = 0;
if (ok && (!IsResourceNil(desc.vs.resource) || !IsResourceNil(desc.ps.resource))) if (ok && (!IsResourceNil(desc.vs.resource) || !IsResourceNil(desc.ps.resource)))
{ {
i32 rts_count = 0;
b32 has_multiple_blend_modes = 0;
{
G_BlendMode last_blend_mode = 0;
for (i32 rt_idx = 0; rt_idx < countof(desc.render_target_formats); ++rt_idx)
{
G_BlendMode blend_mode = desc.render_target_blend_modes[rt_idx];
DXGI_FORMAT format = G_D12_DxgiFormatFromGpuFormat(desc.render_target_formats[rt_idx]);
if (format == DXGI_FORMAT_UNKNOWN)
{
break;
}
else
{
if (rt_idx > 0 && blend_mode != last_blend_mode)
{
has_multiple_blend_modes = 1;
}
last_blend_mode = blend_mode;
rts_count += 1;
}
}
}
D3D12_RASTERIZER_DESC raster_desc = Zi; D3D12_RASTERIZER_DESC raster_desc = Zi;
{ {
if (desc.is_wireframe) if (desc.is_wireframe)
@ -520,16 +544,51 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
D3D12_BLEND_DESC blend_desc = Zi; D3D12_BLEND_DESC blend_desc = Zi;
{ {
blend_desc.IndependentBlendEnable = has_multiple_blend_modes;
blend_desc.AlphaToCoverageEnable = 0; blend_desc.AlphaToCoverageEnable = 0;
blend_desc.IndependentBlendEnable = 0; for (i32 rt_idx = 0; rt_idx < rts_count; ++rt_idx)
blend_desc.RenderTarget[0].BlendEnable = 1; {
blend_desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; G_BlendMode blend_mode = desc.render_target_blend_modes[rt_idx];
blend_desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; D3D12_RENDER_TARGET_BLEND_DESC *rt = &blend_desc.RenderTarget[rt_idx];
blend_desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; switch (blend_mode)
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; {
blend_desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; default:
blend_desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; {
blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; rt->BlendEnable = 0;
rt->RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
} break;
case G_BlendMode_CompositeStraightAlpha:
{
rt->BlendEnable = 1;
rt->SrcBlend = D3D12_BLEND_SRC_ALPHA;
rt->BlendOp = D3D12_BLEND_OP_ADD;
rt->DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
rt->SrcBlendAlpha = D3D12_BLEND_ONE;
rt->BlendOpAlpha = D3D12_BLEND_OP_ADD;
rt->DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
rt->RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
} break;
case G_BlendMode_CompositePremultipliedAlpha:
{
rt->BlendEnable = 1;
rt->SrcBlend = D3D12_BLEND_ONE;
rt->BlendOp = D3D12_BLEND_OP_ADD;
rt->DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
rt->SrcBlendAlpha = D3D12_BLEND_ONE;
rt->BlendOpAlpha = D3D12_BLEND_OP_ADD;
rt->DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
rt->RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
} break;
}
}
} }
D3D12_DEPTH_STENCIL_DESC ds_desc = Zi; D3D12_DEPTH_STENCIL_DESC ds_desc = Zi;
@ -554,18 +613,11 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
pso_desc.SampleMask = UINT_MAX; pso_desc.SampleMask = UINT_MAX;
pso_desc.SampleDesc.Count = 1; pso_desc.SampleDesc.Count = 1;
pso_desc.SampleDesc.Quality = 0; pso_desc.SampleDesc.Quality = 0;
for (i32 i = 0; i < (i32)countof(desc.render_target_formats); ++i) pso_desc.NumRenderTargets = rts_count;
for (i32 rt_idx = 0; rt_idx < rts_count; ++rt_idx)
{ {
StaticAssert(countof(pso_desc.RTVFormats) <= countof(desc.render_target_formats)); DXGI_FORMAT format = G_D12_DxgiFormatFromGpuFormat(desc.render_target_formats[rt_idx]);
DXGI_FORMAT format = G_D12_DxgiFormatFromGpuFormat(desc.render_target_formats[i]); pso_desc.RTVFormats[rt_idx] = format;
if (format != DXGI_FORMAT_UNKNOWN)
{
pso_desc.RTVFormats[pso_desc.NumRenderTargets++] = format;
}
else
{
break;
}
} }
} }
hr = ID3D12Device_CreateGraphicsPipelineState(G_D12.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso); hr = ID3D12Device_CreateGraphicsPipelineState(G_D12.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
@ -1727,7 +1779,7 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
} }
{ {
b32 tweak_b32 = TweakBool("GPU tweak-bool", 1); b32 tweak_b32 = TweakBool("GPU tweak-bool", 1);
f32 tweak_f32 = TweakFloat("GPU tweak-float", 1, 0, 1, .precision = 3); f32 tweak_f32 = TweakFloat("GPU tweak-float", 1, 0, 1);
slotted_constants[G_ShaderConst_TweakB32] = tweak_b32; slotted_constants[G_ShaderConst_TweakB32] = tweak_b32;
slotted_constants[G_ShaderConst_TweakF32] = *(u32 *)&tweak_f32; slotted_constants[G_ShaderConst_TweakF32] = *(u32 *)&tweak_f32;
} }
@ -2029,6 +2081,7 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
case G_D12_CmdKind_Compute: case G_D12_CmdKind_Compute:
{ {
// Fetch pipeline
G_D12_Pipeline *pipeline = 0; G_D12_Pipeline *pipeline = 0;
{ {
G_D12_PipelineDesc pipeline_desc = Zi; G_D12_PipelineDesc pipeline_desc = Zi;
@ -2084,6 +2137,7 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
case G_D12_CmdKind_Rasterize: case G_D12_CmdKind_Rasterize:
{ {
// Fetch pipeline
G_D12_Pipeline *pipeline = 0; G_D12_Pipeline *pipeline = 0;
{ {
G_D12_PipelineDesc pipeline_desc = Zi; G_D12_PipelineDesc pipeline_desc = Zi;
@ -2091,7 +2145,7 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
pipeline_desc.ps = cmd->rasterize.ps; pipeline_desc.ps = cmd->rasterize.ps;
{ {
pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED; pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED;
switch (cmd->rasterize.mode) switch (cmd->rasterize.raster_mode)
{ {
default: Assert(0); break; default: Assert(0); break;
case G_RasterMode_PointList: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; break; case G_RasterMode_PointList: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; break;
@ -2103,16 +2157,18 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
case G_RasterMode_WireTriangleStrip: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; case G_RasterMode_WireTriangleStrip: pipeline_desc.topology_type = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break;
} }
} }
if (cmd->rasterize.mode == G_RasterMode_WireTriangleList || cmd->rasterize.mode == G_RasterMode_WireTriangleStrip) if (cmd->rasterize.raster_mode == G_RasterMode_WireTriangleList || cmd->rasterize.raster_mode == G_RasterMode_WireTriangleStrip)
{ {
pipeline_desc.is_wireframe = 1; pipeline_desc.is_wireframe = 1;
} }
for (u32 i = 0; i < countof(cmd->rasterize.render_targets); ++i) for (u32 i = 0; i < countof(cmd->rasterize.render_target_descs); ++i)
{ {
G_D12_Resource *rt = cmd->rasterize.render_targets[i]; G_RenderTargetDesc desc = cmd->rasterize.render_target_descs[i];
G_D12_Resource *rt = G_D12_ResourceFromHandle(desc.resource);
if (rt) if (rt)
{ {
pipeline_desc.render_target_formats[i] = rt->texture_format; pipeline_desc.render_target_formats[i] = rt->texture_format;
pipeline_desc.render_target_blend_modes[i] = desc.blend;
} }
else else
{ {
@ -2226,7 +2282,7 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
// Set topology // Set topology
{ {
D3D_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; D3D_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
switch (cmd->rasterize.mode) switch (cmd->rasterize.raster_mode)
{ {
default: Assert(0); break; default: Assert(0); break;
case G_RasterMode_PointList: topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; break; case G_RasterMode_PointList: topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; break;
@ -2254,9 +2310,10 @@ i64 G_CommitCommandList(G_CommandListHandle cl_handle)
{ {
b32 om_dirty = 0; b32 om_dirty = 0;
u32 rtvs_count = 0; u32 rtvs_count = 0;
for (u32 i = 0; i < countof(cmd->rasterize.render_targets); ++i) for (u32 i = 0; i < countof(cmd->rasterize.render_target_descs); ++i)
{ {
G_D12_Resource *rt = cmd->rasterize.render_targets[i]; G_RenderTargetDesc desc = cmd->rasterize.render_target_descs[i];
G_D12_Resource *rt = G_D12_ResourceFromHandle(desc.resource);
if (rt) if (rt)
{ {
if (bound_render_target_uids[i] != rt->uid) if (bound_render_target_uids[i] != rt->uid)
@ -2627,9 +2684,9 @@ void G_Rasterize(
G_CommandListHandle cl_handle, G_CommandListHandle cl_handle,
VertexShader vs, PixelShader ps, VertexShader vs, PixelShader ps,
u32 instances_count, G_IndexBufferDesc index_buffer, u32 instances_count, G_IndexBufferDesc index_buffer,
u32 render_targets_count, G_ResourceHandle *render_targets, u32 render_targets_count, G_RenderTargetDesc *render_targets,
Rng3 viewport, Rng2 scissor, Rng3 viewport, Rng2 scissor,
G_RasterMode mode G_RasterMode raster_mode
) )
{ {
G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle); G_D12_CmdList *cl = G_D12_CmdListFromHandle(cl_handle);
@ -2641,11 +2698,11 @@ void G_Rasterize(
cmd->rasterize.index_buffer_desc = index_buffer; cmd->rasterize.index_buffer_desc = index_buffer;
for (u32 i = 0; i < MinU32(render_targets_count, G_MaxRenderTargets); ++i) for (u32 i = 0; i < MinU32(render_targets_count, G_MaxRenderTargets); ++i)
{ {
cmd->rasterize.render_targets[i] = G_D12_ResourceFromHandle(render_targets[i]); cmd->rasterize.render_target_descs[i] = render_targets[i];
} }
cmd->rasterize.viewport = viewport; cmd->rasterize.viewport = viewport;
cmd->rasterize.scissor = scissor; cmd->rasterize.scissor = scissor;
cmd->rasterize.mode = mode; cmd->rasterize.raster_mode = raster_mode;
} }
//- Clear //- Clear

View File

@ -36,6 +36,7 @@ Struct(G_D12_PipelineDesc)
b32 is_wireframe; b32 is_wireframe;
D3D12_PRIMITIVE_TOPOLOGY_TYPE topology_type; D3D12_PRIMITIVE_TOPOLOGY_TYPE topology_type;
G_Format render_target_formats[G_MaxRenderTargets]; G_Format render_target_formats[G_MaxRenderTargets];
G_BlendMode render_target_blend_modes[G_MaxRenderTargets];
}; };
Struct(G_D12_Pipeline) Struct(G_D12_Pipeline)
@ -345,10 +346,10 @@ Struct(G_D12_Cmd)
PixelShader ps; PixelShader ps;
u32 instances_count; u32 instances_count;
G_IndexBufferDesc index_buffer_desc; G_IndexBufferDesc index_buffer_desc;
G_D12_Resource *render_targets[G_MaxRenderTargets]; G_RenderTargetDesc render_target_descs[G_MaxRenderTargets];
Rng3 viewport; Rng3 viewport;
Rng2 scissor; Rng2 scissor;
G_RasterMode mode; G_RasterMode raster_mode;
} rasterize; } rasterize;
struct struct

View File

@ -421,9 +421,15 @@ void BuildEntryPoint(WaveLaneCtx *lane)
//- Dxc //- Dxc
{ {
// PushStringToList(perm, &cp.flags_dxc, Lit("-Od"));
PushStringToList(perm, &cp.flags_dxc, Lit("-O3")); PushStringToList(perm, &cp.flags_dxc, Lit("-O3"));
PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug")); PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug"));
// Enable warnings
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wall"));
PushStringToList(perm, &cp.warnings_dxc, Lit("-WX"));
// Disable warnings
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-unused-variable"));
} }
} }
@ -868,13 +874,14 @@ void BuildEntryPoint(WaveLaneCtx *lane)
: Lit("vs_6_6"); : Lit("vs_6_6");
String compile_cmd = StringF( String compile_cmd = StringF(
perm, perm,
"dxc.exe -T %F -E %F -Fo %F %F %F %F", "dxc.exe -T %F -E %F -Fo %F %F %F %F %F",
FmtString(target), FmtString(target),
FmtString(e->name), FmtString(e->name),
FmtString(out_file), FmtString(out_file),
FmtString(gpu_out_file), FmtString(gpu_out_file),
FmtString(StringFromList(perm, cp.defs, Lit(" "))), FmtString(StringFromList(perm, cp.defs, Lit(" "))),
FmtString(StringFromList(perm, cp.flags_dxc, Lit(" "))) FmtString(StringFromList(perm, cp.flags_dxc, Lit(" "))),
FmtString(StringFromList(perm, cp.warnings_dxc, Lit(" ")))
); );
OS_CommandResult cmd_result = OS_RunCommand(perm, compile_cmd); OS_CommandResult cmd_result = OS_RunCommand(perm, compile_cmd);

View File

@ -98,9 +98,7 @@ V_WidgetTheme V_GetWidgetTheme(void)
theme.text_padding_x = 5; theme.text_padding_x = 5;
theme.text_padding_y = 5; theme.text_padding_y = 5;
theme.window_padding = 1;
theme.window_bd_sz = 1;
theme.window_padding = theme.window_bd_sz - 1;
//- Colors //- Colors
theme.col.window_bg = Rgb32(0xff1a1d1e); theme.col.window_bg = Rgb32(0xff1a1d1e);
@ -1321,7 +1319,7 @@ void V_TickForever(WaveLaneCtx *lane)
Vec2 drag_offset = SubVec2(ui_frame->drag_cursor_pos, palette_reps.drag.screen_anchor); Vec2 drag_offset = SubVec2(ui_frame->drag_cursor_pos, palette_reps.drag.screen_anchor);
palette->pos = SubVec2(frame->ui_cursor, drag_offset); palette->pos = SubVec2(frame->ui_cursor, drag_offset);
} }
window_border_color = LerpSrgb(window_border_color, Rgb32(0x0078a6), titlebar_reps.draw.hot); window_border_color = LerpSrgb(window_border_color, theme.col.button_active, titlebar_reps.draw.hot);
f32 scale = LerpF32(0.85, 1, palette->show); f32 scale = LerpF32(0.85, 1, palette->show);
UI_Push(Tint, VEC4(1, 1, 1, palette->show)); UI_Push(Tint, VEC4(1, 1, 1, palette->show));
@ -1329,7 +1327,8 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Push(BackgroundColor, window_background_color); UI_Push(BackgroundColor, window_background_color);
UI_Push(BorderColor, window_border_color); UI_Push(BorderColor, window_border_color);
UI_Push(BorderSize, theme.window_bd_sz); // UI_Push(BorderSize, theme.window_bd_sz);
UI_Push(BorderSize, 1);
UI_Push(Rounding, UI_RGROW(0.095 * theme.rounding)); UI_Push(Rounding, UI_RGROW(0.095 * theme.rounding));
UI_Push(Width, UI_FNT(40, 0)); UI_Push(Width, UI_FNT(40, 0));
UI_Push(Height, UI_SHRINK(0, 0)); UI_Push(Height, UI_SHRINK(0, 0));
@ -1358,7 +1357,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_BuildRow(); UI_BuildRow();
// Title box // Title box
UI_SetNext(FontSize, UI_Top(FontSize) * theme.h2); UI_SetNext(FontSize, UI_Top(FontSize) * theme.h3);
UI_SetNext(ChildAlignment, UI_Region_Center); UI_SetNext(ChildAlignment, UI_Region_Center);
UI_SetNext(Width, UI_SHRINK(0, 1)); UI_SetNext(Width, UI_SHRINK(0, 1));
UI_SetNext(Text, Lit("Debug Palette")); UI_SetNext(Text, Lit("Debug Palette"));
@ -1376,7 +1375,7 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Build palette items list //- Build palette items list
f32 window_padding = theme.window_bd_sz; f32 window_padding = theme.window_padding;
UI_SetNext(Tint, 0); UI_SetNext(Tint, 0);
UI_SetNext(Rounding, 0); UI_SetNext(Rounding, 0);
UI_PushCP(UI_BuildRow()); UI_PushCP(UI_BuildRow());
@ -1475,8 +1474,10 @@ void V_TickForever(WaveLaneCtx *lane)
} }
} }
Vec4 item_color = theme.col.window_bg; // Vec4 item_color = theme.col.window_bg;
Vec4 item_border_color = item_color; Vec4 item_color = Zi;
// Vec4 item_color = theme.col.hint;
Vec4 item_border_color = Zi;
if (item->flags & PaletteItemFlag_IsCmd) if (item->flags & PaletteItemFlag_IsCmd)
{ {
item_color = LerpSrgb(item_color, theme.col.button_hot, item_rep.hot); item_color = LerpSrgb(item_color, theme.col.button_hot, item_rep.hot);
@ -1491,12 +1492,12 @@ void V_TickForever(WaveLaneCtx *lane)
f32 item_size_px = UI_FNT(1.5, 1).v; f32 item_size_px = UI_FNT(1.5, 1).v;
f32 tweak_size_px = UI_FNT(1.25, 1).v; f32 tweak_size_px = UI_FNT(1.25, 1).v;
UI_SetNext(BorderColor, 0); UI_SetNext(Tint, 0);
UI_SetNext(Rounding, UI_RPIX(0));
UI_PushCP(UI_BuildRow()); UI_PushCP(UI_BuildRow());
{ {
UI_SetNext(BorderColor, item_border_color);
UI_SetNext(BackgroundColor, item_color); UI_SetNext(BackgroundColor, item_color);
UI_SetNext(BorderColor, item_border_color);
UI_SetNext(BorderSize, 1);
UI_SetNext(Rounding, UI_RPIX(5)); UI_SetNext(Rounding, UI_RPIX(5));
UI_SetNext(Width, UI_GROW(1, 0)); UI_SetNext(Width, UI_GROW(1, 0));
UI_SetNext(Height, UI_PIX(item_size_px, 1)); UI_SetNext(Height, UI_PIX(item_size_px, 1));
@ -1701,7 +1702,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetNext(BackgroundColor, slider_progress_color); UI_SetNext(BackgroundColor, slider_progress_color);
// UI_SetNext(Rounding, UI_RGROW(theme.rounding)); // UI_SetNext(Rounding, UI_RGROW(theme.rounding));
UI_SetNext(Rounding, 0); UI_SetNext(Rounding, 0);
UI_SetNext(BorderColor, slider_border_color); UI_SetNext(BorderColor, 0);
UI_SetNext(BorderSize, 1); UI_SetNext(BorderSize, 1);
UI_SetNext(Width, UI_PIX(marker_pos + half_marker_dims.x, 0)); UI_SetNext(Width, UI_PIX(marker_pos + half_marker_dims.x, 0));
UI_SetNext(Height, UI_PIX(tweak_size_px * 0.75, 1)); UI_SetNext(Height, UI_PIX(tweak_size_px * 0.75, 1));
@ -2309,7 +2310,7 @@ void V_TickForever(WaveLaneCtx *lane)
frame->cl, frame->cl,
V_DVertVS, V_DVertPS, V_DVertVS, V_DVertPS,
1, dvert_idxs_ib, 1, dvert_idxs_ib,
1, &draw_target, 1, &G_Rt(draw_target, G_BlendMode_CompositeStraightAlpha),
viewport, scissor, viewport, scissor,
G_RasterMode_TriangleList G_RasterMode_TriangleList
); );
@ -2323,7 +2324,7 @@ void V_TickForever(WaveLaneCtx *lane)
frame->cl, frame->cl,
V_OverlayVS, V_OverlayPS, V_OverlayVS, V_OverlayPS,
1, G_QuadIndices(), 1, G_QuadIndices(),
1, &draw_target, 1, &G_Rt(draw_target, G_BlendMode_CompositeStraightAlpha),
viewport, scissor, viewport, scissor,
G_RasterMode_TriangleList G_RasterMode_TriangleList
); );

View File

@ -33,9 +33,7 @@ Struct(V_WidgetTheme)
f32 rounding; f32 rounding;
f32 window_bd_sz;
f32 window_padding; f32 window_padding;
f32 text_padding_x; f32 text_padding_x;
f32 text_padding_y; f32 text_padding_y;

View File

@ -1499,6 +1499,7 @@ void UI_EndFrame(UI_Frame *frame)
} break; } break;
} }
// Clamp rounding based on parent rounding
if (parent && !AllBits(box->desc.flags, UI_BoxFlag_Floating | UI_BoxFlag_NoFloatingClamp)) if (parent && !AllBits(box->desc.flags, UI_BoxFlag_Floating | UI_BoxFlag_NoFloatingClamp))
{ {
Vec2 vtl = SubVec2(VEC2(parent->screen_rect.p0.x, parent->screen_rect.p0.y), VEC2(box->screen_rect.p0.x, box->screen_rect.p0.y)); Vec2 vtl = SubVec2(VEC2(parent->screen_rect.p0.x, parent->screen_rect.p0.y), VEC2(box->screen_rect.p0.x, box->screen_rect.p0.y));
@ -1711,6 +1712,7 @@ void UI_EndFrame(UI_Frame *frame)
params.rects = rects_ro; params.rects = rects_ro;
params.sampler = G_BasicSampler(); params.sampler = G_BasicSampler();
params.cursor_pos = frame->cursor_pos; params.cursor_pos = frame->cursor_pos;
params.aa = TweakFloat("UI anti-aliasing", 1, 0, 1);
} }
G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(&params)); G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(&params));
G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, UI_DParams); G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, UI_DParams);
@ -1742,7 +1744,7 @@ void UI_EndFrame(UI_Frame *frame)
frame->cl, frame->cl,
UI_DRectVS, UI_DRectPS, UI_DRectVS, UI_DRectPS,
rects_count, G_QuadIndices(), rects_count, G_QuadIndices(),
1, &draw_target, 1, &G_Rt(draw_target, G_BlendMode_CompositePremultipliedAlpha),
draw_viewport, draw_scissor, draw_viewport, draw_scissor,
G_RasterMode_TriangleList G_RasterMode_TriangleList
); );
@ -1755,7 +1757,7 @@ void UI_EndFrame(UI_Frame *frame)
frame->cl, frame->cl,
UI_DRectVS, UI_DRectPS, UI_DRectVS, UI_DRectPS,
rects_count, G_QuadIndices(), rects_count, G_QuadIndices(),
1, &draw_target, 1, &G_Rt(draw_target, G_BlendMode_CompositePremultipliedAlpha),
draw_viewport, draw_scissor, draw_viewport, draw_scissor,
G_RasterMode_WireTriangleList G_RasterMode_WireTriangleList
); );
@ -1772,7 +1774,7 @@ void UI_EndFrame(UI_Frame *frame)
frame->cl, frame->cl,
UI_BlitVS, UI_BlitPS, UI_BlitVS, UI_BlitPS,
1, G_QuadIndices(), 1, G_QuadIndices(),
1, &backbuffer, 1, &G_Rt(backbuffer, G_BlendMode_Opaque),
monitor_viewport, monitor_scissor, monitor_viewport, monitor_scissor,
G_RasterMode_TriangleList G_RasterMode_TriangleList
); );

View File

@ -6,6 +6,8 @@ G_DeclConstant(b32, UI_ShaderConst_DebugDraw, 1);
Struct(UI_DParams) Struct(UI_DParams)
{ {
f32 aa;
Vec2I32 target_size; Vec2I32 target_size;
G_Texture2DRef target_ro; G_Texture2DRef target_ro;

View File

@ -15,14 +15,18 @@ VertexShader(UI_DRectVS, UI_DRectPSInput)
Vec2 target_pos = lerp(rect.bounds.p0, rect.bounds.p1, rect_uv); Vec2 target_pos = lerp(rect.bounds.p0, rect.bounds.p1, rect_uv);
UI_DRectPSInput result; UI_DRectPSInput result;
result.sv_position = Vec4(NdcFromPos(target_pos, Vec2(params.target_size).xy), 0, 1); {
result.background_lin = rect.background_lin; result.sv_position = Vec4(NdcFromPos(target_pos, Vec2(params.target_size).xy), 0, 1);
result.border_lin = rect.border_lin; result.rect_idx = SV_InstanceID;
result.tint_lin = rect.tint_lin;
result.rect_idx = SV_InstanceID;
result.rect_uv = rect_uv;
result.tex_uv = tex_uv;
result.base_background_premul = Premul(rect.background_lin);
result.base_border_premul = Premul(rect.border_lin);
result.tint_premul = Premul(rect.tint_lin);
result.debug_premul = Premul(rect.debug_lin);
result.rect_uv = rect_uv;
result.tex_uv = tex_uv;
}
return result; return result;
} }
@ -42,7 +46,7 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
Vec2 p0 = rect.bounds.p0; Vec2 p0 = rect.bounds.p0;
Vec2 p1 = rect.bounds.p1; Vec2 p1 = rect.bounds.p1;
// Compute rect sdf (negative means pixel is inside of rect) //- Compute rect dist (negative means pixel is inside of rect)
f32 rect_dist = min(min(p.x - p0.x, p1.x - p.x), min(p.y - p0.y, p1.y - p.y)); f32 rect_dist = min(min(p.x - p0.x, p1.x - p.x), min(p.y - p0.y, p1.y - p.y));
{ {
f32 tl_radius = rect.tl_rounding; f32 tl_radius = rect.tl_rounding;
@ -59,62 +63,54 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
if (p.x < bl.x && p.y > bl.y) { rect_dist = min(rect_dist, bl_radius - length(bl - p)); } if (p.x < bl.x && p.y > bl.y) { rect_dist = min(rect_dist, bl_radius - length(bl - p)); }
} }
rect_dist = -rect_dist; rect_dist = -rect_dist;
f32 rect_dist_fwidth = fwidth(rect_dist);
// Compute border sdf (negative means pixel is inside of border) bool is_inside = rect_dist < 0;
f32 border_size = 0;
f32 border_dist = 0;
Vec4 border_color = 0;
{
if (rect.border_size > 0)
{
border_size = rect.border_size;
border_color = input.border_lin;
}
else
{
border_size = 0;
border_color = input.background_lin;
}
border_dist = abs(rect_dist);
if (rect_dist <= 0)
{
border_dist -= border_size;
}
}
Vec4 final_color = 0; //- Compute background color
Vec4 background_premul = 0;
if (is_inside)
{ {
// Background color
if (G_IsRefNil(rect.tex)) if (G_IsRefNil(rect.tex))
{ {
final_color = input.background_lin; background_premul = input.base_background_premul;
} }
else else
{ {
Texture2D<Vec4> tex = G_Dereference<Vec4>(rect.tex); Texture2D<Vec4> tex = G_Dereference<Vec4>(rect.tex);
final_color = tex.Sample(sampler, input.tex_uv); background_premul = tex.Sample(sampler, input.tex_uv);
} background_premul.rgb *= background_premul.a;
final_color *= rect_dist <= 0;
// Border color
{
f32 half_border_dist_fwidth = fwidth(border_dist) * 0.5;
f32 border_alpha = smoothstep(half_border_dist_fwidth, -half_border_dist_fwidth, border_dist);
final_color = lerp(final_color, border_color, border_alpha);
}
// Tint
final_color *= input.tint_lin;
// Debug color
if (UI_ShaderConst_DebugDraw)
{
final_color = rect.debug_lin;
} }
} }
//- Compute borer color
Vec4 border_premul = input.base_border_premul;
//- Compute border dist
f32 border_dist = 0;
border_dist = abs(rect_dist);
if (is_inside)
{
border_dist -= rect.border_size;
}
//- Compute anti-aliased border-over-background color
Vec4 composite_premul = 0;
{
f32 smoothness = rect_dist_fwidth * params.aa * 0.5;
f32 border_coverage = smoothstep(smoothness, -smoothness, border_dist);
composite_premul = lerp(background_premul, border_premul, border_coverage);
}
//- Finalize
Vec4 result = composite_premul * input.tint_premul;
if (UI_ShaderConst_DebugDraw)
{
result = input.debug_premul;
}
UI_DRectPSOutput output; UI_DRectPSOutput output;
output.sv_target0 = final_color; output.sv_target0 = result;
return output; return output;
} }

View File

@ -5,9 +5,10 @@ Struct(UI_DRectPSInput)
{ {
Semantic(Vec4, sv_position); Semantic(Vec4, sv_position);
Semantic(nointerpolation u32, rect_idx); Semantic(nointerpolation u32, rect_idx);
Semantic(Vec4, background_lin); Semantic(Vec4, base_background_premul);
Semantic(Vec4, border_lin); Semantic(Vec4, base_border_premul);
Semantic(Vec4, tint_lin); Semantic(Vec4, tint_premul);
Semantic(Vec4, debug_premul);
Semantic(Vec2, rect_uv); Semantic(Vec2, rect_uv);
Semantic(Vec2, tex_uv); Semantic(Vec2, tex_uv);
}; };