fix oob resource access during composition pass

This commit is contained in:
jacob 2026-02-02 22:29:14 -06:00
parent e3ae1a789f
commit 201d0c2bf0
18 changed files with 669 additions and 705 deletions

View File

@ -81,7 +81,6 @@ void AsyncWorkerEntryPoint(WaveLaneCtx *lane)
}
}
WaveSync(lane);
//////////////////////////////

View File

@ -439,7 +439,6 @@ CR_Item *CR_ItemFromString(Arena *arena, String str)
}
}
EndScratch(scratch);
return result;
}

View File

@ -29,7 +29,6 @@ u64 ClampU64(u64 v, u64 min, u64 max) { return v < min ? min : v > max ? max : v
i64 ClampI64(i64 v, i64 min, i64 max) { return v < min ? min : v > max ? max : v; }
f64 ClampF64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ? max : v; }
//- Saturate
u32 SaturateU32(u32 v) { return v < 0 ? 0 : v > 1 ? 1 : v; }
i32 SaturateI32(i32 v) { return v < 0 ? 0 : v > 1 ? 1 : v; }

View File

@ -39,7 +39,6 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings)
}
}
////////////////////////////////////////////////////////////
//~ Resource ops

View File

@ -49,66 +49,65 @@ u32 countof(T arr[N])
//~ C -> HLSL interoperability stubs
//- Min
#define MinU8 min
#define MinI8 min
#define MinU32 min
#define MinI32 min
#define MinF32 min
#define MinU64 min
#define MinI64 min
#define MinF64 min
#define MinU8 (u8)min
#define MinI8 (i8)min
#define MinU32 (u32)min
#define MinI32 (i32)min
#define MinF32 (f32)min
#define MinU64 (u64)min
#define MinI64 (i64)min
#define MinF64 (f64)min
//- Max
#define MaxU8 max
#define MaxI8 max
#define MaxU32 max
#define MaxI32 max
#define MaxF32 max
#define MaxU64 max
#define MaxI64 max
#define MaxF64 max
#define MaxU8 (u8)max
#define MaxI8 (i8)max
#define MaxU32 (u32)max
#define MaxI32 (i32)max
#define MaxF32 (f32)max
#define MaxU64 (u64)max
#define MaxI64 (i64)max
#define MaxF64 (f64)max
//- Clamp
#define ClampU32 clamp
#define ClampI32 clamp
#define ClampF32 clamp
#define ClampU64 clamp
#define ClampI64 clamp
#define ClampF64 clamp
#define ClampU32 (u32)clamp
#define ClampI32 (i32)clamp
#define ClampF32 (f32)clamp
#define ClampU64 (u64)clamp
#define ClampI64 (i64)clamp
#define ClampF64 (f64)clamp
//- Round
#define RoundF32 round
#define RoundF64 round
#define RoundF32 (f32)round
#define RoundF64 (f64)round
//- Floor
#define FloorF32 floor
#define FloorF64 floor
#define FloorF32 (f32)floor
#define FloorF64 (f64)floor
//- Ceil
#define CeilF32 ceil
#define CeilF64 ceil
#define CeilF32 (f32)ceil
#define CeilF64 (f64)ceil
//- Trunc
#define TruncF32 trunc
#define TruncF64 trunc
#define TruncF32 (f32)trunc
#define TruncF64 (f64)trunc
//- Mod
#define ModF32 fmod
#define ModF64 fmod
#define ModF32 (f32)fmod
#define ModF64 (f64)fmod
//- Abs
#define AbsF32 abs
#define AbsF64 abs
#define AbsF32 (f32)abs
#define AbsF64 (f64)abs
//- Sign
#define SignF32 sign
#define SignF64 sign
#define SignF32 (f32)sign
#define SignF64 (f64)sign
//- Smoothstep
#define SmoothstepF32 smoothstep
#define SmoothstepF64 smoothstep
#define SmoothstepF32 (f32)smoothstep
#define SmoothstepF64 (f64)smoothstep
//- Matchfloor
#define MatchFloor(a, b) all(floor(a) == floor(b))
////////////////////////////////////////////////////////////
@ -166,12 +165,12 @@ Inline Vec4 LinearFromSrgb(Vec4 srgb)
Inline f32 LuminanceFromColor(Vec4 v)
{
return 0.2126 * v.r + 0.7152 * v.g + 0.0722 * v.b;
};
}
Inline Vec4 InvertColor(Vec4 v)
{
return Vec4(Vec3(1, 1, 1) - v.rgb, v.a);
};
}
Inline Vec4 Premul(Vec4 v)
{

View File

@ -132,7 +132,6 @@ String StringFromList(Arena *arena, StringList l, String separator);
#define FmtChar(v, ...) FMTARG(FmtArgKind_Char, .value.c = (v), __VA_ARGS__)
#define FmtString(v, ...) FMTARG(FmtArgKind_String, .value.string = (v), __VA_ARGS__)
#define FmtUint(v, ...) FMTARG(FmtArgKind_Uint, .value.uints = VEC4U64((v), 0, 0, 0), __VA_ARGS__)
#define FmtUint2(v, ...) FMTARG(FmtArgKind_Uint2, .value.uints = VEC4U64((v).x, (v).y, 0, 0), __VA_ARGS__)
#define FmtUint3(v, ...) FMTARG(FmtArgKind_Uint3, .value.uints = VEC4U64((v).x, (v).y, (v).z, 0), __VA_ARGS__)

View File

@ -317,6 +317,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame)
G_Format_R8G8B8A8_Unorm_Srgb,
atlas->dims,
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
.debug = Lit("Glyph atlas")
);
atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex);
}

View File

@ -415,12 +415,14 @@ Enum(G_ResourceFlag)
G_ResourceFlag_ZeroMemory = (1 << 3),
G_ResourceFlag_HostMemory = (1 << 4), // Resource will be mapped into the cpu's address space
G_ResourceFlag_Uncached = (1 << 5), // Cpu writes will be combined & reads will be uncached
G_ResourceFlag_ForceNoReuse = (1 << 6),
};
Struct(G_BufferDesc)
{
G_ResourceFlag flags;
u64 size;
String debug;
};
Struct(G_TextureDesc)
@ -431,6 +433,7 @@ Struct(G_TextureDesc)
G_Layout initial_layout;
i32 mip_levels; // Will be clamped to range [1, inf)
Vec4 clear_color;
String debug;
};
Struct(G_SamplerDesc)
@ -446,6 +449,7 @@ Struct(G_SamplerDesc)
Vec4 border_color;
f32 min_lod;
f32 max_lod;
String debug;
};
Struct(G_ResourceDesc)

View File

@ -450,6 +450,34 @@ D3D12_BARRIER_LAYOUT G_D12_BarrierLayoutFromLayout(G_Layout layout)
return result;
};
void G_D12_SetObjectName(ID3D12Object *object, String name)
{
TempArena scratch = BeginScratchNoConflict();
{
wchar_t *name_wstr = WstrFromString(scratch.arena, name);
ID3D12Resource_SetName(object, name_wstr);
}
EndScratch(scratch);
}
String G_D12_NameFromObject(Arena *arena, ID3D12Object *object)
{
String result = Zi;
{
wchar_t dbg_text[G_D12_MaxDebugTextLen] = Zi;
u32 dbg_text_sz = sizeof(dbg_text);
ID3D12Object_GetPrivateData(object, &WKPDID_D3DDebugObjectNameW, &dbg_text_sz, dbg_text);
if (dbg_text_sz > 2)
{
String16 str16 = Zi;
str16.len = (dbg_text_sz / 2) - 1;
str16.text = dbg_text;
result = StringFromString16(arena, str16);
}
}
return result;
}
////////////////////////////////////////////////////////////
//~ Pipeline
@ -497,163 +525,197 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
// Create pipeline
if (is_pipeline_new)
{
TempArena scratch = BeginScratchNoConflict();
HRESULT hr = 0;
b32 ok = 1;
String error_str = Zi;
b32 is_compute = IsResourceNil(desc.vs.resource) || IsResourceNil(desc.ps.resource);
String pipeline_name = Zi;
if (is_compute)
{
pipeline_name = StringF(
scratch.arena,
"%F%F",
FmtHandle(desc.cs.resource.v),
FmtString(NameFromResource(desc.cs.resource))
);
}
else
{
pipeline_name = StringF(
scratch.arena,
"%F%F-%F%F",
FmtHandle(desc.vs.resource.v),
FmtString(NameFromResource(desc.vs.resource)),
FmtHandle(desc.ps.resource.v),
FmtString(NameFromResource(desc.ps.resource))
);
}
// Create PSO
ID3D12PipelineState *pso = 0;
if (ok && (!IsResourceNil(desc.vs.resource) || !IsResourceNil(desc.ps.resource)))
if (ok)
{
i32 rts_count = 0;
b32 has_multiple_blend_modes = 0;
if (!is_compute)
{
G_BlendMode last_blend_mode = 0;
for (i32 rt_idx = 0; rt_idx < countof(desc.render_target_formats); ++rt_idx)
i32 rts_count = 0;
b32 has_multiple_blend_modes = 0;
{
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)
G_BlendMode last_blend_mode = 0;
for (i32 rt_idx = 0; rt_idx < countof(desc.render_target_formats); ++rt_idx)
{
break;
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;
{
if (desc.is_wireframe)
{
raster_desc.FillMode = D3D12_FILL_MODE_WIREFRAME;
}
else
{
if (rt_idx > 0 && blend_mode != last_blend_mode)
{
has_multiple_blend_modes = 1;
}
last_blend_mode = blend_mode;
rts_count += 1;
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_RASTERIZER_DESC raster_desc = Zi;
{
if (desc.is_wireframe)
D3D12_BLEND_DESC blend_desc = Zi;
{
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.IndependentBlendEnable = has_multiple_blend_modes;
blend_desc.AlphaToCoverageEnable = 0;
for (i32 rt_idx = 0; rt_idx < rts_count; ++rt_idx)
{
G_BlendMode blend_mode = desc.render_target_blend_modes[rt_idx];
D3D12_RENDER_TARGET_BLEND_DESC *rt = &blend_desc.RenderTarget[rt_idx];
switch (blend_mode)
blend_desc.IndependentBlendEnable = has_multiple_blend_modes;
blend_desc.AlphaToCoverageEnable = 0;
for (i32 rt_idx = 0; rt_idx < rts_count; ++rt_idx)
{
default:
G_BlendMode blend_mode = desc.render_target_blend_modes[rt_idx];
D3D12_RENDER_TARGET_BLEND_DESC *rt = &blend_desc.RenderTarget[rt_idx];
switch (blend_mode)
{
rt->BlendEnable = 0;
rt->RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
} break;
default:
{
rt->BlendEnable = 0;
rt->RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
} break;
case G_BlendMode_CompositeStraightAlpha:
{
rt->BlendEnable = 1;
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->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->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;
rt->RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
} break;
case G_BlendMode_CompositePremultipliedAlpha:
{
rt->BlendEnable = 1;
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->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->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;
rt->RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
} break;
}
}
}
}
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_D12.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;
pso_desc.NumRenderTargets = rts_count;
for (i32 rt_idx = 0; rt_idx < rts_count; ++rt_idx)
D3D12_DEPTH_STENCIL_DESC ds_desc = Zi;
{
DXGI_FORMAT format = G_D12_DxgiFormatFromGpuFormat(desc.render_target_formats[rt_idx]);
pso_desc.RTVFormats[rt_idx] = format;
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_D12.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;
pso_desc.NumRenderTargets = rts_count;
for (i32 rt_idx = 0; rt_idx < rts_count; ++rt_idx)
{
DXGI_FORMAT format = G_D12_DxgiFormatFromGpuFormat(desc.render_target_formats[rt_idx]);
pso_desc.RTVFormats[rt_idx] = format;
}
}
hr = ID3D12Device_CreateGraphicsPipelineState(G_D12.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
if (FAILED(hr))
{
error_str = StringF(scratch.arena, "Failed to create graphics pipeline \"%F\"", FmtString(pipeline_name));
ok = 0;
}
}
hr = ID3D12Device_CreateGraphicsPipelineState(G_D12.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
if (FAILED(hr))
else
{
error_str = Lit("Failed to create graphics pipeline");
ok = 0;
}
}
else if (ok)
{
String cs = DataFromResource(desc.cs.resource);
D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc = Zi;
{
pso_desc.pRootSignature = G_D12.bindless_rootsig;
pso_desc.CS.pShaderBytecode = cs.text;
pso_desc.CS.BytecodeLength = cs.len;
}
hr = ID3D12Device_CreateComputePipelineState(G_D12.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
if (FAILED(hr))
{
error_str = Lit("Failed to create compute pipeline");
ok = 0;
String cs = DataFromResource(desc.cs.resource);
D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc = Zi;
{
pso_desc.pRootSignature = G_D12.bindless_rootsig;
pso_desc.CS.pShaderBytecode = cs.text;
pso_desc.CS.BytecodeLength = cs.len;
}
hr = ID3D12Device_CreateComputePipelineState(G_D12.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
if (FAILED(hr))
{
error_str = StringF(scratch.arena, "Failed to create compute pipeline \"%F\"", FmtString(pipeline_name));
ok = 0;
}
}
}
if (!ok)
if (ok)
{
if (GPU_DEBUG)
{
G_D12_SetObjectName((ID3D12Object *)pso, pipeline_name);
}
}
else
{
// TOOD: Don't panic
Panic(error_str);
@ -662,6 +724,7 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
pipeline->pso = pso;
pipeline->error = error_str;
pipeline->ok = ok;
EndScratch(scratch);
}
return pipeline;
@ -900,15 +963,22 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
desc.kind == G_ResourceKind_Texture2D ||
desc.kind == G_ResourceKind_Texture3D;
b32 is_sampler = desc.kind == G_ResourceKind_Sampler;
G_ResourceFlag flags =
is_buffer ? desc.buffer.flags :
is_texture ? desc.texture.flags :
desc.sampler.flags;
String new_debug_text =
is_buffer ? desc.buffer.debug :
is_texture ? desc.texture.debug :
desc.sampler.debug;
new_debug_text.len = MinU64(new_debug_text.len, countof(resource->debug_text));
//////////////////////////////
//- Initialize heap info
b32 can_reuse = 1;
b32 can_reuse = !AnyBit(flags, G_ResourceFlag_ForceNoReuse);
D3D12_HEAP_FLAGS heap_flags = 0;
D3D12_HEAP_PROPERTIES heap_props = Zi;
@ -1047,8 +1117,14 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
Unlock(&lock);
}
ZeroStruct(release);
release->d3d_resource = resource->d3d_resource;
SllQueuePush(cl->releases.first, cl->releases.last, release);
release->d3d_resource = resource->d3d_resource;
if (GPU_DEBUG)
{
StaticAssert(countof(release->debug_text) == countof(resource->debug_text));
release->debug_text_len = resource->debug_text_len;
CopyBytes(release->debug_text, resource->debug_text, resource->debug_text_len);
}
}
ZeroStruct(resource);
}
@ -1146,6 +1222,20 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
}
}
//////////////////////////////
//- Set debug information
if (GPU_DEBUG)
{
String old_debug_text = STRING(resource->debug_text_len, resource->debug_text);
if (!MatchString(old_debug_text, new_debug_text))
{
resource->debug_text_len = new_debug_text.len;
CopyBytes(resource->debug_text, new_debug_text.text, new_debug_text.len);
G_D12_SetObjectName((ID3D12Object *)resource->d3d_resource, new_debug_text);
}
}
//////////////////////////////
//- Barrier if reusing
@ -1221,7 +1311,7 @@ G_D12_Descriptor *G_D12_PushDescriptor(G_D12_Arena *gpu_arena, G_D12_DescriptorH
{
Panic(Lit("Max descriptors reached in heap"));
}
descriptor = PushStruct(heap->descriptors_arena, G_D12_Descriptor);
descriptor = PushStructNoZero(heap->descriptors_arena, G_D12_Descriptor);
index = descriptors_count;
}
}

View File

@ -11,7 +11,7 @@
#pragma comment(lib, "dxgi")
////////////////////////////////////////////////////////////
//~ Tweakable defines
//~ Tweakable definitions
#define G_D12_TearingIsAllowed 1
#define G_D12_FrameLatency 1
@ -25,6 +25,8 @@
#define G_D12_MaxSamplerDescriptors (1024 * 1)
#define G_D12_MaxRtvDescriptors (1024 * 64)
#define G_D12_MaxDebugTextLen 64
////////////////////////////////////////////////////////////
//~ Pipeline types
@ -90,6 +92,9 @@ Struct(G_D12_Resource)
// Backbuffer info
struct G_D12_Swapchain *swapchain;
u64 debug_text_len;
u8 debug_text[G_D12_MaxDebugTextLen];
};
Struct(G_D12_ResourceList)
@ -273,6 +278,9 @@ Struct(G_D12_Releasable)
i64 completion_queue_target;
ID3D12Resource *d3d_resource;
u64 debug_text_len;
u8 debug_text[G_D12_MaxDebugTextLen];
};
Struct(G_D12_ReleasableList)
@ -495,6 +503,9 @@ D3D12_BARRIER_SYNC G_D12_BarrierSyncFromStages(G_Stage stages);
D3D12_BARRIER_ACCESS G_D12_BarrierAccessFromAccesses(G_Access accesses);
D3D12_BARRIER_LAYOUT G_D12_BarrierLayoutFromLayout(G_Layout layout);
void G_D12_SetObjectName(ID3D12Object *object, String name);
String G_D12_NameFromObject(Arena *arena, ID3D12Object *object);
////////////////////////////////////////////////////////////
//~ Pipeline

View File

@ -426,11 +426,13 @@ void BuildEntryPoint(WaveLaneCtx *lane)
//- Dxc
{
PushStringToList(perm, &cp.flags_dxc, Lit("-O3"));
// PushStringToList(perm, &cp.flags_dxc, Lit("-Od"));
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"));
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wshadow"));
// Disable warnings
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-unused-variable"));

View File

@ -815,7 +815,6 @@ void NET_W32_TickForever(WaveLaneCtx *lane)
// Post initial recv
CreateIoCompletionPort((HANDLE)sock, NET_W32.iocp, 0, 0);
NET_W32_PostRecv(pipe);
}
else

View File

@ -392,7 +392,6 @@ PLT_FileMap PLT_OpenFileMap(PLT_File file)
map.mapped_memory = STRING(size, base_ptr);
map.valid = map_handle != INVALID_HANDLE_VALUE && base_ptr != 0;
return map;
}

View File

@ -411,7 +411,8 @@ void V_TickForever(WaveLaneCtx *lane)
gpu_perm, cl,
V_GpuState,
1,
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
.debug = Lit("Gpu state")
);
gpu_state_ref = G_PushRWStructuredBufferRef(gpu_perm, gpu_state, V_GpuState);
}
@ -422,7 +423,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R8_Uint,
tiles_dims,
G_Layout_DirectQueue_ShaderRead,
.flags = G_ResourceFlag_ZeroMemory
.flags = G_ResourceFlag_ZeroMemory,
.debug = Lit("Tiles")
);
gpu_tiles_ref = G_PushTexture2DRef(gpu_perm, gpu_tiles);
}
@ -432,7 +434,8 @@ void V_TickForever(WaveLaneCtx *lane)
gpu_perm, cl,
V_Particle,
V_ParticlesCap,
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
.debug = Lit("Particles")
);
gpu_particles_ref = G_PushRWStructuredBufferRef(gpu_perm, gpu_particles, V_Particle);
}
@ -446,7 +449,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R16G16B16A16_Float,
cells_dims,
G_Layout_DirectQueue_ShaderReadWrite,
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
.debug = Lit("Cells")
);
gpu_cells_ref = G_PushRWTexture2DRef(gpu_perm, gpu_cells);
}
@ -460,7 +464,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R16G16B16A16_Float,
cells_dims,
G_Layout_DirectQueue_ShaderReadWrite,
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
.debug = Lit("Stains")
);
gpu_stains_ref = G_PushRWTexture2DRef(gpu_perm, gpu_stains);
}
@ -475,7 +480,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R32_Float,
cells_dims,
G_Layout_DirectQueue_ShaderReadWrite,
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
.debug = Lit("Drynesses")
);
gpu_drynesses_ref = G_PushRWTexture2DRef(gpu_perm, gpu_drynesses);
}
@ -853,9 +859,10 @@ void V_TickForever(WaveLaneCtx *lane)
f32 fire_presses = fire_held && !prev_frame->held_buttons[Button_M1];
{
// TODO: Adjustable sensitivity
f32 mouse_sensitivity = TweakFloat("Mouse sensitivity", 1.0, 0.1, 5.0);
f32 mouse_scale_factor = 0.005;
look = frame->look;
look = AddVec2(look, MulVec2(mouse_delta, mouse_scale_factor));
look = AddVec2(look, MulVec2(mouse_delta, mouse_sensitivity * mouse_scale_factor));
look = ClampVec2Len(look, look_radius);
}
if (frame->is_editing)
@ -4445,7 +4452,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R16G16B16A16_Float,
frame->screen_dims,
G_Layout_DirectQueue_RenderTargetWrite,
.flags = G_ResourceFlag_AllowRenderTarget
.flags = G_ResourceFlag_AllowRenderTarget,
.debug = StringF(frame->arena, "Screen target [%F]", FmtSint(frame->tick))
);
G_Texture2DRef screen_target_ro = G_PushTexture2DRef(frame->gpu_arena, screen_target);
Rng3 screen_viewport = RNG3(VEC3(0, 0, 0), VEC3(frame->screen_dims.x, frame->screen_dims.y, 1));
@ -4457,7 +4465,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R16G16B16A16_Float,
frame->screen_dims,
G_Layout_DirectQueue_RenderTargetWrite,
.flags = G_ResourceFlag_AllowRenderTarget
.flags = G_ResourceFlag_AllowRenderTarget,
.debug = StringF(frame->arena, "Albedo target [%F]", FmtSint(frame->tick))
);
G_Texture2DRef albedo_target_ro = G_PushTexture2DRef(frame->gpu_arena, albedo_target);
@ -4467,7 +4476,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R16G16B16A16_Float,
frame->shade_dims,
G_Layout_DirectQueue_ShaderReadWrite,
.flags = G_ResourceFlag_AllowShaderReadWrite
.flags = G_ResourceFlag_AllowShaderReadWrite,
.debug = StringF(frame->arena, "Shade target [%F]", FmtSint(frame->tick))
);
G_Texture2DRef shade_target_ro = G_PushTexture2DRef(frame->gpu_arena, shade_target);
G_RWTexture2DRef shade_target_rw = G_PushRWTexture2DRef(frame->gpu_arena, shade_target);
@ -4475,12 +4485,24 @@ void V_TickForever(WaveLaneCtx *lane)
Rng2 shade_scissor = RNG2(VEC2(shade_viewport.p0.x, shade_viewport.p0.y), VEC2(shade_viewport.p1.x, shade_viewport.p1.y));
// Quad buffers
G_ResourceHandle quads_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->quads_arena));
G_ResourceHandle quads_buff = G_PushBufferFromCpuCopy(
frame->gpu_arena, frame->cl,
StringFromArena(frame->quads_arena),
.debug = StringF(frame->arena, "quads [%F]", FmtSint(frame->tick))
);
G_StructuredBufferRef quads_ref = G_PushStructuredBufferRef(frame->gpu_arena, quads_buff, V_Quad);
// Debug shape buffers
G_ResourceHandle dverts_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->dverts_arena));
G_ResourceHandle dvert_idxs_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->dvert_idxs_arena));
G_ResourceHandle dverts_buff = G_PushBufferFromCpuCopy(
frame->gpu_arena, frame->cl,
StringFromArena(frame->dverts_arena),
.debug = StringF(frame->arena, "dverts [%F]", FmtSint(frame->tick))
);
G_ResourceHandle dvert_idxs_buff = G_PushBufferFromCpuCopy(
frame->gpu_arena, frame->cl,
StringFromArena(frame->dvert_idxs_arena),
.debug = StringF(frame->arena, "dvert idxs [%F]", FmtSint(frame->tick))
);
G_StructuredBufferRef dverts_ref = G_PushStructuredBufferRef(frame->gpu_arena, dverts_buff, V_DVert);
G_IndexBufferDesc dvert_idxs_ib = G_IdxBuff32(dvert_idxs_buff);
@ -4497,7 +4519,11 @@ void V_TickForever(WaveLaneCtx *lane)
++emitter_idx;
}
}
gpu_emitters = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromStructs(flattened_emitters, frame->emitters_count));
gpu_emitters = G_PushBufferFromCpuCopy(
frame->gpu_arena, frame->cl,
StringFromStructs(flattened_emitters, frame->emitters_count),
.debug = StringF(frame->arena, "emitters [%F]", FmtSint(frame->tick))
);
}
G_StructuredBufferRef gpu_emitters_ref = G_PushStructuredBufferRef(frame->gpu_arena, gpu_emitters, V_Emitter);
@ -4573,7 +4599,11 @@ void V_TickForever(WaveLaneCtx *lane)
}
}
}
G_ResourceHandle gpu_params = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromStruct(&params));
G_ResourceHandle gpu_params = G_PushBufferFromCpuCopy(
frame->gpu_arena, frame->cl,
StringFromStruct(&params),
.debug = StringF(frame->arena, "Gpu params [%F]", FmtSint(frame->tick))
);
G_StructuredBufferRef gpu_params_ref = G_PushStructuredBufferRef(frame->gpu_arena, gpu_params, V_GpuParams);
// Upload tiles
@ -4680,12 +4710,9 @@ void V_TickForever(WaveLaneCtx *lane)
G_DumbMemoryLayoutSync(frame->cl, shade_target, G_Layout_DirectQueue_ShaderRead);
}
//////////////////////////////
//- Composite pass
G_DumbMemoryLayoutSync(frame->cl, screen_target, G_Layout_DirectQueue_RenderTargetWrite);
{
G_Rasterize(
frame->cl,

View File

@ -25,11 +25,12 @@ ComputeShader2D(V_PrepareShadeCS, 8, 8)
{
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
RWTexture2D<Vec4> shade = G_Dereference<Vec4>(params.shade_rw);
Vec2 shade_idx = SV_DispatchThreadID;
if (all(shade_idx < countof(shade)))
Vec2 shade_pos = SV_DispatchThreadID;
if (all(shade_pos < countof(shade)))
{
// Clear shade
shade[shade_idx] = 0;
shade[shade_pos] = 0;
}
}
@ -39,26 +40,26 @@ ComputeShader2D(V_PrepareCellsCS, 8, 8)
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
RWTexture2D<Vec4> cells = G_Dereference<Vec4>(params.cells);
RWTexture2D<f32> drynesses = G_Dereference<f32>(params.drynesses);
Vec2 cells_idx = SV_DispatchThreadID;
if (all(cells_idx < countof(cells)))
Vec2 cells_pos = SV_DispatchThreadID;
if (all(cells_pos < countof(cells)))
{
// Clear cell
cells[cells_idx] = 0;
cells[cells_pos] = 0;
// Increase dryness
f32 dry_rate = params.dt * 0.1;
{
f32 old_dryness = drynesses[cells_idx];
f32 old_dryness = drynesses[cells_pos];
f32 new_dryness = lerp(old_dryness, 1, dry_rate);
drynesses[cells_idx] = new_dryness;
drynesses[cells_pos] = new_dryness;
}
// Clear stain
if (params.should_clear_stains)
{
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains);
stains[cells_idx] = 0;
drynesses[cells_idx] = 0;
stains[cells_pos] = 0;
drynesses[cells_pos] = 0;
}
}
}
@ -114,223 +115,11 @@ PixelShader(V_QuadPS, V_QuadPSOutput, V_QuadPSInput input)
Texture2D<Vec4> tex = G_Dereference<Vec4>(quad.tex);
Vec4 albedo = tex.Sample(clamp_sampler, input.samp_uv);
// Vec4 albedo = Color_Cyan;
V_QuadPSOutput output;
output.sv_target0 = albedo;
return output;
}
////////////////////////////////////////////////////////////
//~ Backdrop
// ComputeShader2D(V_BackdropCS, 8, 8)
// {
// V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
// RWTexture2D<Vec4> screen = G_Dereference<Vec4>(params.screen_rw);
// Texture2D<P_TileKind> tiles = G_Dereference<P_TileKind>(params.tiles);
// SamplerState wrap_sampler = G_Dereference(params.pt_wrap_sampler);
// const Vec4 background_color_a = LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1));
// const Vec4 background_color_b = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1));
// Vec2 screen_pos = SV_DispatchThreadID + Vec2(0.5, 0.5);
// Vec4 result = Vec4(0.025, 0.025, 0.025, 1);
// Vec2 world_pos = mul(params.af.screen_to_world, Vec3(screen_pos, 1));
// Vec2 cell_pos = floor(mul(params.af.world_to_cell, Vec3(world_pos, 1)));
// Vec2 tile_pos = mul(params.af.world_to_tile, Vec3(world_pos, 1));
// P_TileKind tile = tiles.Load(Vec3(tile_pos, 0));
// f32 half_thickness = 1;
// f32 half_world_bounds_size = P_WorldPitch * 0.5;
// Vec2 world_bounds_screen_p0 = mul(params.af.world_to_screen, Vec3(-half_world_bounds_size, -half_world_bounds_size, 1));
// Vec2 world_bounds_screen_p1 = mul(params.af.world_to_screen, Vec3(half_world_bounds_size, half_world_bounds_size, 1));
// b32 is_in_world_bounds =
// screen_pos.x > (world_bounds_screen_p0.x - half_thickness) &&
// screen_pos.y > (world_bounds_screen_p0.y - half_thickness) &&
// screen_pos.x < (world_bounds_screen_p1.x + half_thickness) &&
// screen_pos.y < (world_bounds_screen_p1.y + half_thickness);
// if (is_in_world_bounds)
// {
// // // Checkered grid
// // {
// // i32 color_idx = 0;
// // Vec4 colors[2] = {
// // background_color_a,
// // background_color_b
// // };
// // const f32 checker_size = 0.5;
// // Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(checker_size * 2, checker_size * 2));
// // if (world_pos_modded.x < checker_size)
// // {
// // color_idx = !color_idx;
// // }
// // if (world_pos_modded.y < checker_size)
// // {
// // color_idx = !color_idx;
// // }
// // if (world_pos.x < 0)
// // {
// // color_idx = !color_idx;
// // }
// // if (world_pos.y < 0)
// // {
// // color_idx = !color_idx;
// // }
// // result = colors[color_idx];
// // }
// // Tile test
// // TODO: Remove this
// {
// P_TileKind tile_tl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y - 1, 0));
// P_TileKind tile_tr = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y - 1, 0));
// P_TileKind tile_br = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y + 1, 0));
// P_TileKind tile_bl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y + 1, 0));
// P_TileKind tile_t = tiles.Load(Vec3(tile_pos.x, tile_pos.y - 1, 0));
// P_TileKind tile_r = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y, 0));
// P_TileKind tile_b = tiles.Load(Vec3(tile_pos.x, tile_pos.y + 1, 0));
// P_TileKind tile_l = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y, 0));
// f32 tile_edge_dist = Inf;
// P_TileKind edge_tile = tile;
// if (tile_tl != tile) { edge_tile = tile_tl; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(floor(tile_pos.x), floor(tile_pos.y)))); }
// if (tile_tr != tile) { edge_tile = tile_tr; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(ceil(tile_pos.x), floor(tile_pos.y)))); }
// if (tile_br != tile) { edge_tile = tile_br; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(ceil(tile_pos.x), ceil(tile_pos.y)))); }
// if (tile_bl != tile) { edge_tile = tile_bl; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(floor(tile_pos.x), ceil(tile_pos.y)))); }
// if (tile_l != tile) { edge_tile = tile_l; tile_edge_dist = min(tile_edge_dist, frac(tile_pos.x)); }
// if (tile_r != tile) { edge_tile = tile_r; tile_edge_dist = min(tile_edge_dist, 1.0 - frac(tile_pos.x)); }
// if (tile_t != tile) { edge_tile = tile_t; tile_edge_dist = min(tile_edge_dist, frac(tile_pos.y)); }
// if (tile_b != tile) { edge_tile = tile_b; tile_edge_dist = min(tile_edge_dist, 1.0 - frac(tile_pos.y)); }
// if (tile == P_TileKind_Wall)
// {
// Vec4 outer = LinearFromSrgb(Vec4(0.05, 0.05, 0.05, 1));
// Vec4 inner = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1));
// result = lerp(outer, inner, smoothstep(0, 1, tile_edge_dist / 0.375));
// // result = lerp(outer, inner, smoothstep(0, 1, tile_edge_dist / 0.5));
// }
// else if (tile != P_TileKind_Empty)
// {
// SPR_Slice slice = params.tile_slices[tile];
// Texture2D<Vec4> tile_tex = G_Dereference<Vec4>(slice.tex);
// Vec4 tile_col = tile_tex.SampleLevel(wrap_sampler, world_pos, 0);
// result = tile_col;
// }
// // switch (tile)
// // {
// // default: break;
// // case P_TileKind_Floor:
// // {
// // result = Color_Blue;
// // } break;
// // case P_TileKind_Wall:
// // {
// // // result = Color_Red;
// // result = Color_Black;
// // } break;
// // }
// }
// // TODO: Remove this
// // Cells test
// {
// RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains);
// RWTexture2D<Vec4> cells = G_Dereference<Vec4>(params.cells);
// RWTexture2D<f32> drynesses = G_Dereference<f32>(params.drynesses);
// Vec4 stain = stains.Load(cell_pos);
// Vec4 cell = cells.Load(cell_pos);
// f32 dryness = drynesses[cell_pos];
// stain = V_DryColor(stain, dryness);
// // cell.rgb *= cell.a;
// // stain.rgb *= stain.a;
// result.rgb = (stain.rgb * stain.a) + (result.rgb * (1.0 - stain.a));
// result.a = (stain.a * 1) + (result.a * (1.0 - stain.a));
// result.rgb = (cell.rgb * cell.a) + (result.rgb * (1.0 - cell.a));
// result.a = (cell.a * 1) + (result.a * (1.0 - cell.a));
// // Vec4 cell = cells.Load(cell_pos);
// // if (cell.a != 0)
// // {
// // result = cell;
// // }
// // else
// // {
// // Vec4 stain = stains.Load(cell_pos);
// // if (stain.a != 0)
// // {
// // result = stain;
// // }
// // }
// }
// // // TODO: Remove this
// // // Cells test
// // {
// // RWTexture2D<Vec4> cells = G_Dereference<Vec4>(params.cells);
// // Vec2 cell_pos = floor(mul(params.af.world_to_cell, Vec3(world_pos, 1)));
// // Vec4 cell = cells.Load(cell_pos);
// // if (cell.a != 0)
// // {
// // result = cell;
// // }
// // else
// // {
// // RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains);
// // Vec4 stain = stains.Load(cell_pos);
// // if (stain.a != 0)
// // {
// // result = stain;
// // }
// // }
// // }
// // TODO: Remove this
// // Stains test
// // {
// // RWTexture2D<V_ParticleKind> stains = G_Dereference<V_ParticleKind>(params.stains);
// // Vec2 cell_pos = mul(params.af.world_to_cell, Vec3(world_pos, 1));
// // V_ParticleKind stain = stains.Load(cell_pos);
// // if (stain == V_ParticleKind_Test)
// // {
// // // result = Color_Yellow;
// // // result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1));
// // // result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1));
// // }
// // }
// }
// if (all(screen_pos < countof(screen)))
// {
// screen[screen_pos] = result;
// }
// }
////////////////////////////////////////////////////////////
//~ Particle simulation
@ -378,7 +167,9 @@ ComputeShader(V_SimParticlesCS, 64)
V_Particle particle = particles[particle_idx];
if (particle.exists > 0)
{
// Initialize
//////////////////////////////
//- Initialize particle
if (particle.emitter_init_num != 0)
{
V_Emitter emitter = G_Dereference<V_Emitter>(params.emitters)[particle.emitter_init_num - 1];
@ -418,63 +209,81 @@ ComputeShader(V_SimParticlesCS, 64)
particle.emitter_init_num = 0;
}
Vec2 cell_pos = floor(mul(params.af.world_to_cell, Vec3(particle.pos, 1)));
b32 is_in_world_bounds = cell_pos.x >= 0 && cell_pos.y >= 0 && cell_pos.x < countof(stains).x && cell_pos.y < countof(stains).y;
//////////////////////////////
//- Simulate particle
// Simulate
f32 old_exists = particle.exists;
f32 prev_exists = particle.exists;
{
particle.pos += particle.velocity * params.dt;
particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt);
particle.exists -= params.dt / particle.lifetime;
if ((particle.flags & V_ParticleFlag_PruneWhenStill) && (dot(particle.velocity, particle.velocity) < (0.1 * 0.1)))
Vec2 cell_pos = mul(params.af.world_to_cell, Vec3(particle.pos, 1));
b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells));
// Simulate
{
particle.exists = 0;
}
if (particle.exists < 0.000001)
{
particle.exists = 0;
}
if (!is_in_world_bounds)
{
particle.exists = 0;
particle.pos += particle.velocity * params.dt;
particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt);
particle.exists -= params.dt / particle.lifetime;
if ((particle.flags & V_ParticleFlag_PruneWhenStill) && (dot(particle.velocity, particle.velocity) < (0.1 * 0.1)))
{
particle.exists = 0;
}
if (particle.exists < 0.000001)
{
particle.exists = 0;
}
}
}
// Commit
//////////////////////////////
//- Commit particle
// FIXME: Atomic writes
{
b32 should_stain = is_in_world_bounds && (
AnyBit(particle.flags, V_ParticleFlag_StainTrail) ||
(AnyBit(particle.flags, V_ParticleFlag_StainOnPrune) && particle.exists == 0)
);
b32 should_draw = is_in_world_bounds;
Vec2 cell_pos = mul(params.af.world_to_cell, Vec3(particle.pos, 1));
Vec2 screen_pos = mul(params.af.world_to_screen, Vec3(particle.pos, 1));
b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells));
b32 is_in_screen = all(screen_pos >= 0) && all(screen_pos < params.screen_dims);
Vec4 color = particle.color;
color.a *= old_exists;
color.a *= prev_exists;
// Stain
if (should_stain)
if (is_in_world)
{
f32 old_dryness = drynesses[cell_pos];
Vec4 old_stain = stains[cell_pos];
// old_stain = V_DryColor(old_stain, drynesses[cell_pos] * 0.5);
// old_stain = V_DryColor(old_stain, old_dryness);
Vec4 new_stain = 0;
new_stain.rgb = (color.rgb * color.a) + (old_stain.rgb * (1.0 - color.a));
new_stain.a = color.a + (old_stain.a * (1.0 - color.a));
// new_stain = V_DryColor(new_stain, old_dryness * 0.1);
// new_stain = V_DryColor(new_stain, old_dryness * 0.5);
b32 should_stain = (
AnyBit(particle.flags, V_ParticleFlag_StainTrail) ||
(AnyBit(particle.flags, V_ParticleFlag_StainOnPrune) && particle.exists == 0)
);
stains[cell_pos] = new_stain;
drynesses[cell_pos] = 0;
// Stain
if (should_stain)
{
f32 old_dryness = drynesses[cell_pos];
Vec4 old_stain = stains[cell_pos];
// old_stain = V_DryColor(old_stain, drynesses[cell_pos] * 0.5);
// old_stain = V_DryColor(old_stain, old_dryness);
Vec4 new_stain = 0;
new_stain.rgb = (color.rgb * color.a) + (old_stain.rgb * (1.0 - color.a));
new_stain.a = color.a + (old_stain.a * (1.0 - color.a));
// new_stain = V_DryColor(new_stain, old_dryness * 0.1);
// new_stain = V_DryColor(new_stain, old_dryness * 0.5);
stains[cell_pos] = new_stain;
drynesses[cell_pos] = 0;
}
}
// Draw
if (should_draw)
{
cells[cell_pos] = color;
b32 should_draw = is_in_world;
if (should_draw)
{
cells[cell_pos] = color;
}
}
}
particles[particle_idx] = particle;
}
@ -488,7 +297,7 @@ ComputeShader2D(V_ShadeCS, 8, 8)
{
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
RWTexture2D<Vec4> shade_tex = G_Dereference<Vec4>(params.shade_rw);
// Texture2D<Vec4> albedo_tex = G_Dereference<Vec4>(params.albedo_ro);
Texture2D<Vec4> albedo_tex = G_Dereference<Vec4>(params.albedo_ro);
Texture2D<P_TileKind> tiles = G_Dereference<P_TileKind>(params.tiles);
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains);
RWTexture2D<f32> drynesses = G_Dereference<f32>(params.drynesses);
@ -496,13 +305,13 @@ ComputeShader2D(V_ShadeCS, 8, 8)
Vec2 shade_pos = SV_DispatchThreadID + Vec2(0.5, 0.5);
Vec2 world_pos = mul(params.af.shade_to_world, Vec3(shade_pos, 1));
Vec2 cell_pos = floor(mul(params.af.world_to_cell, Vec3(world_pos, 1)));
Vec2 cell_pos = mul(params.af.world_to_cell, Vec3(world_pos, 1));
Vec2 tile_pos = mul(params.af.world_to_tile, Vec3(world_pos, 1));
P_TileKind tile = tiles.Load(Vec3(tile_pos, 0));
Vec2 half_world_dims = Vec2(P_WorldPitch, P_WorldPitch) * 0.5;
b32 is_in_world_bounds = all(world_pos > -half_world_dims) && all(world_pos < half_world_dims);
b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(stains));
//////////////////////////////
//- Compute albedo
@ -543,7 +352,7 @@ VertexShader(V_CompositeVS, V_CompositePSInput)
PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
{
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
Texture2D<Vec4> shade_tex = G_Dereference<Vec4>(params.shade_ro);
// Texture2D<Vec4> shade_tex = G_Dereference<Vec4>(params.shade_ro);
Texture2D<Vec4> albedo_tex = G_Dereference<Vec4>(params.albedo_ro);
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains);
RWTexture2D<Vec4> cells = G_Dereference<Vec4>(params.cells);
@ -554,294 +363,313 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
Vec2 screen_pos = input.sv_position.xy;
Vec2 world_pos = mul(params.af.screen_to_world, Vec3(screen_pos, 1));
Vec2 tile_pos = mul(params.af.world_to_tile, Vec3(world_pos, 1));
Vec2 cell_pos = floor(mul(params.af.world_to_cell, Vec3(world_pos, 1)));
Vec2 cell_pos = mul(params.af.world_to_cell, Vec3(world_pos, 1));
Vec2 shade_pos = mul(params.af.screen_to_shade, Vec3(screen_pos.xy, 1));
f32 half_thickness = 1;
Vec2 half_world_dims = Vec2(P_WorldPitch, P_WorldPitch) * 0.5;
Vec2 world_bounds_screen_p0 = mul(params.af.world_to_screen, Vec3(-half_world_dims.xy, 1));
Vec2 world_bounds_screen_p1 = mul(params.af.world_to_screen, Vec3(half_world_dims.xy, 1));
b32 is_in_world_bounds = (
screen_pos.x > (world_bounds_screen_p0.x - half_thickness) &&
screen_pos.y > (world_bounds_screen_p0.y - half_thickness) &&
screen_pos.x < (world_bounds_screen_p1.x + half_thickness) &&
screen_pos.y < (world_bounds_screen_p1.y + half_thickness)
);
b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells));
P_TileKind tile = tiles.Load(Vec3(tile_pos, 0));
P_TileKind equipped_tile = params.equipped_tile;
//////////////////////////////
//- Shade color
//- World color
// Vec4 shade_color = 0;
// if (all(shade_pos >= Vec2(0, 0)) && all(shade_pos < countof(shade_tex)))
// {
// Vec2 shade_uv = shade_pos / countof(shade_tex);
// shade_color = shade_tex.SampleLevel(clamp_sampler, shade_uv, 0);
// }
//////////////////////////////
//- Albedo color
Vec4 albedo_color = 0;
Vec4 world_color = Vec4(0.025, 0.025, 0.025, 1);
if (is_in_world)
{
//////////////////////////////
//- Tile color
//- Shade color
Vec4 shade_color = 0;
// if (all(shade_pos >= Vec2(0, 0)) && all(shade_pos < countof(shade_tex)))
// {
// Vec2 shade_uv = shade_pos / countof(shade_tex);
// shade_color = shade_tex.SampleLevel(clamp_sampler, shade_uv, 0);
// }
//////////////////////////////
//- Albedo
Vec4 albedo_color = 0;
{
//////////////////////////////
//- Tile
// TODO: Remove this
b32 tile_is_wall = 0;
Vec4 tile_color = 0;
{
P_TileKind tile_tl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y - 1, 0));
P_TileKind tile_tr = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y - 1, 0));
P_TileKind tile_br = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y + 1, 0));
P_TileKind tile_bl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y + 1, 0));
P_TileKind tile_t = tiles.Load(Vec3(tile_pos.x, tile_pos.y - 1, 0));
P_TileKind tile_r = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y, 0));
P_TileKind tile_b = tiles.Load(Vec3(tile_pos.x, tile_pos.y + 1, 0));
P_TileKind tile_l = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y, 0));
f32 tile_edge_dist = Inf;
P_TileKind edge_tile = tile;
if (tile_tl != tile) { edge_tile = tile_tl; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(floor(tile_pos.x), floor(tile_pos.y)))); }
if (tile_tr != tile) { edge_tile = tile_tr; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(ceil(tile_pos.x), floor(tile_pos.y)))); }
if (tile_br != tile) { edge_tile = tile_br; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(ceil(tile_pos.x), ceil(tile_pos.y)))); }
if (tile_bl != tile) { edge_tile = tile_bl; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(floor(tile_pos.x), ceil(tile_pos.y)))); }
if (tile_l != tile) { edge_tile = tile_l; tile_edge_dist = min(tile_edge_dist, frac(tile_pos.x)); }
if (tile_r != tile) { edge_tile = tile_r; tile_edge_dist = min(tile_edge_dist, 1.0 - frac(tile_pos.x)); }
if (tile_t != tile) { edge_tile = tile_t; tile_edge_dist = min(tile_edge_dist, frac(tile_pos.y)); }
if (tile_b != tile) { edge_tile = tile_b; tile_edge_dist = min(tile_edge_dist, 1.0 - frac(tile_pos.y)); }
if (tile == P_TileKind_Wall)
{
Vec4 outer = LinearFromSrgb(Vec4(0.05, 0.05, 0.05, 1));
Vec4 inner = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1));
tile_color = lerp(outer, inner, smoothstep(0, 1, tile_edge_dist / 0.375));
tile_is_wall = 1;
}
else if (tile != P_TileKind_Empty)
{
V_TileDesc tile_desc = params.tile_descs[tile];
Texture2D<Vec4> tile_tex = G_Dereference<Vec4>(tile_desc.tex);
Vec2 tile_samp_uv = lerp(tile_desc.tex_slice_uv.p0, tile_desc.tex_slice_uv.p1, frac(world_pos));
tile_color = tile_tex.SampleLevel(clamp_sampler, tile_samp_uv, 0);
}
// Checkered grid
else if (tile == P_TileKind_Empty)
{
i32 color_idx = 0;
Vec4 colors[2] = {
LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1)),
LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1))
};
const f32 checker_size = 0.5;
Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(checker_size * 2, checker_size * 2));
if (world_pos_modded.x < checker_size)
{
color_idx = !color_idx;
}
if (world_pos_modded.y < checker_size)
{
color_idx = !color_idx;
}
if (world_pos.x < 0)
{
color_idx = !color_idx;
}
if (world_pos.y < 0)
{
color_idx = !color_idx;
}
tile_color = colors[color_idx];
}
}
//////////////////////////////
//- Stain
Vec4 stain_color = 0;
{
f32 dryness = drynesses.Load(cell_pos);
Vec4 stain = stains.Load(cell_pos);
stain_color = V_DryColor(stain, dryness);
stain_color.rgb *= 1.0 - (0.75 * tile_is_wall); // Darken wall stains
}
//////////////////////////////
//- Albedo tex
Vec4 albedo_tex_color = albedo_tex.Load(Vec3(screen_pos, 0));
//////////////////////////////
//- Compose albedo
if (!tile_is_wall)
{
albedo_color = BlendPremul(tile_color, albedo_color); // Blend floor tile
albedo_color = BlendPremul(stain_color, albedo_color); // Blend floor stain
}
albedo_color = BlendPremul(albedo_tex_color, albedo_color);
if (tile_is_wall)
{
albedo_color = BlendPremul(tile_color, albedo_color); // Blend wall tile
albedo_color = BlendPremul(stain_color, albedo_color); // Blend wall stain
}
}
//////////////////////////////
//- Particle
// TODO: Remove this
b32 tile_is_wall = 0;
Vec4 tile_color = Vec4(0.025, 0.025, 0.025, 1);
if (is_in_world_bounds)
Vec4 particle_color = cells.Load(cell_pos);
//////////////////////////////
//- Compose world
// world_color = BlendPremul(shade_color, world_color);
world_color = BlendPremul(albedo_color, world_color);
world_color = BlendPremul(particle_color, world_color);
}
//////////////////////////////
//- Overlay color
Vec4 overlay_color = 0;
{
f32 half_thickness = 1;
//////////////////////////////
//- Tile selection overlay
Vec4 selection_color = 0;
if (params.has_mouse_focus && params.selection_mode == V_SelectionMode_Tile)
{
P_TileKind tile_tl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y - 1, 0));
P_TileKind tile_tr = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y - 1, 0));
P_TileKind tile_br = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y + 1, 0));
P_TileKind tile_bl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y + 1, 0));
P_TileKind tile_t = tiles.Load(Vec3(tile_pos.x, tile_pos.y - 1, 0));
P_TileKind tile_r = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y, 0));
P_TileKind tile_b = tiles.Load(Vec3(tile_pos.x, tile_pos.y + 1, 0));
P_TileKind tile_l = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y, 0));
Vec4 border_color = LinearFromSrgb(Vec4(1, 1, 1, 1));
// Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.4, 0.4, 0.25));
Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.8, 0.4, 0.6));
f32 tile_edge_dist = Inf;
P_TileKind edge_tile = tile;
if (tile_tl != tile) { edge_tile = tile_tl; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(floor(tile_pos.x), floor(tile_pos.y)))); }
if (tile_tr != tile) { edge_tile = tile_tr; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(ceil(tile_pos.x), floor(tile_pos.y)))); }
if (tile_br != tile) { edge_tile = tile_br; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(ceil(tile_pos.x), ceil(tile_pos.y)))); }
if (tile_bl != tile) { edge_tile = tile_bl; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(floor(tile_pos.x), ceil(tile_pos.y)))); }
if (tile_l != tile) { edge_tile = tile_l; tile_edge_dist = min(tile_edge_dist, frac(tile_pos.x)); }
if (tile_r != tile) { edge_tile = tile_r; tile_edge_dist = min(tile_edge_dist, 1.0 - frac(tile_pos.x)); }
if (tile_t != tile) { edge_tile = tile_t; tile_edge_dist = min(tile_edge_dist, frac(tile_pos.y)); }
if (tile_b != tile) { edge_tile = tile_b; tile_edge_dist = min(tile_edge_dist, 1.0 - frac(tile_pos.y)); }
Rng2 screen_selection = params.screen_selection;
Rng2 world_selection = params.world_selection;
if (tile == P_TileKind_Wall)
Rng2 tile_selection;
tile_selection.p0 = floor(mul(params.af.world_to_tile, Vec3(world_selection.p0, 1)));
tile_selection.p1 = ceil(mul(params.af.world_to_tile, Vec3(world_selection.p1, 1)));
f32 dist = 100000000;
dist = min(dist, screen_pos.x - screen_selection.p0.x);
dist = min(dist, screen_pos.y - screen_selection.p0.y);
dist = min(dist, screen_selection.p1.x - screen_pos.x);
dist = min(dist, screen_selection.p1.y - screen_pos.y);
dist = -dist;
// if (dist >= -half_thickness && dist <= half_thickness)
// {
// selection_color = border_color;
// }
// else
{
Vec4 outer = LinearFromSrgb(Vec4(0.05, 0.05, 0.05, 1));
Vec4 inner = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1));
tile_color = lerp(outer, inner, smoothstep(0, 1, tile_edge_dist / 0.375));
// tile_color = lerp(outer, inner, smoothstep(0, 1, tile_edge_dist / 0.5));
tile_is_wall = 1;
if (
world_pos.x > -(P_WorldPitch / 2) &&
world_pos.y > -(P_WorldPitch / 2) &&
world_pos.x < (P_WorldPitch / 2) &&
world_pos.y < (P_WorldPitch / 2) &&
tile_pos.x >= tile_selection.p0.x &&
tile_pos.x <= tile_selection.p1.x &&
tile_pos.y >= tile_selection.p0.y &&
tile_pos.y <= tile_selection.p1.y
)
{
selection_color = inner_color;
}
}
else if (tile != P_TileKind_Empty)
// Premultiply
selection_color.rgb *= selection_color.a;
}
//////////////////////////////
//- Grid
Vec4 grid_color = 0;
if (is_in_world)
{
// Grid outline
if (V_ShaderConst_GpuFlags & V_GpuFlag_DebugDraw)
{
V_TileDesc tile_desc = params.tile_descs[tile];
Texture2D<Vec4> tile_tex = G_Dereference<Vec4>(tile_desc.tex);
Vec2 tile_samp_uv = lerp(tile_desc.tex_slice_uv.p0, tile_desc.tex_slice_uv.p1, frac(world_pos));
tile_color = tile_tex.SampleLevel(clamp_sampler, tile_samp_uv, 0);
const Vec4 line_color = LinearFromSrgb(Vec4(1, 1, 1, 0.1));
Vec2 line_screen_p0 = mul(params.af.world_to_screen, Vec3(floor(world_pos), 1));
Vec2 line_screen_p1 = mul(params.af.world_to_screen, Vec3(ceil(world_pos), 1));
f32 line_dist = 100000;
line_dist = min(line_dist, abs(screen_pos.x - line_screen_p0.x));
line_dist = min(line_dist, abs(screen_pos.x - line_screen_p1.x));
line_dist = min(line_dist, abs(screen_pos.y - line_screen_p0.y));
line_dist = min(line_dist, abs(screen_pos.y - line_screen_p1.y));
if (line_dist <= half_thickness * 0.5)
{
grid_color = line_color;
}
}
// Checkered grid
else if (tile == P_TileKind_Empty)
// Axis
if (V_ShaderConst_GpuFlags & V_GpuFlag_DebugDraw)
{
i32 color_idx = 0;
Vec4 colors[2] = {
LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1)),
LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1))
};
const f32 checker_size = 0.5;
Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(checker_size * 2, checker_size * 2));
if (world_pos_modded.x < checker_size)
const Vec4 x_axis_color = LinearFromSrgb(Vec4(0.75, 0, 0, 1));
const Vec4 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1));
Vec2 zero_screen = mul(params.af.world_to_screen, Vec3(0, 0, 1));
f32 x_dist = abs(screen_pos.x - zero_screen.x);
f32 y_dist = abs(screen_pos.y - zero_screen.y);
if (y_dist <= half_thickness)
{
color_idx = !color_idx;
grid_color = x_axis_color;
}
if (world_pos_modded.y < checker_size)
else if (x_dist <= half_thickness)
{
color_idx = !color_idx;
grid_color = y_axis_color;
}
if (world_pos.x < 0)
}
// World bounds
{
const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1));
f32 bounds_dist = 100000;
bounds_dist = min(bounds_dist, abs(screen_pos.x - world_bounds_screen_p0.x));
bounds_dist = min(bounds_dist, abs(screen_pos.x - world_bounds_screen_p1.x));
bounds_dist = min(bounds_dist, abs(screen_pos.y - world_bounds_screen_p0.y));
bounds_dist = min(bounds_dist, abs(screen_pos.y - world_bounds_screen_p1.y));
if (bounds_dist <= half_thickness)
{
color_idx = !color_idx;
grid_color = bounds_color;
}
if (world_pos.y < 0)
}
// Premultiply
grid_color.rgb *= grid_color.a;
}
//////////////////////////////
//- Crosshair
// TODO: Remove this
Vec4 crosshair_color = 0;
{
f32 dist = length(params.screen_crosshair - screen_pos);
if (dist < 4)
{
// Adaptive crosshair color based on underlying luminance
f32 world_luminance = LuminanceFromColor(world_color);
f32 adaptive_threshold = 0.5;
Vec4 adapted_crosshair_color = crosshair_color;
if (world_luminance <= adaptive_threshold)
{
color_idx = !color_idx;
crosshair_color = Color_White;
}
tile_color = colors[color_idx];
else
{
crosshair_color = InvertColor(Color_White);
}
crosshair_color = Premul(crosshair_color);
}
}
//////////////////////////////
//- Stain color
//- Compose overlay
Vec4 stain_color = 0;
{
f32 dryness = drynesses.Load(cell_pos);
stain_color = V_DryColor(stains.Load(cell_pos), dryness);
stain_color.rgb *= 1.0 - (0.75 * tile_is_wall); // Darken wall stains
}
//////////////////////////////
//- Albedo tex
Vec4 albedo_tex_color = albedo_tex.Load(Vec3(screen_pos, 0));
//////////////////////////////
//- Compose albedo
albedo_color = BlendPremul(!tile_is_wall * tile_color, albedo_color); // Blend floor tile
albedo_color = BlendPremul(!tile_is_wall * stain_color, albedo_color); // Blend floor stain
albedo_color = BlendPremul(albedo_tex_color, albedo_color);
albedo_color = BlendPremul(tile_is_wall * tile_color, albedo_color); // Blend wall tile
albedo_color = BlendPremul(tile_is_wall * stain_color, albedo_color); // Blend wall stain
overlay_color = BlendPremul(selection_color, overlay_color);
overlay_color = BlendPremul(grid_color, overlay_color);
overlay_color = BlendPremul(crosshair_color, overlay_color);
}
//////////////////////////////
//- Particle color
// TODO: Remove this
Vec4 particle_color = 0;
if (is_in_world_bounds)
{
particle_color = cells.Load(cell_pos);
}
//////////////////////////////
//- Tile selection overlay
Vec4 selection_color = 0;
if (params.has_mouse_focus && params.selection_mode == V_SelectionMode_Tile)
{
Vec4 border_color = LinearFromSrgb(Vec4(1, 1, 1, 1));
// Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.4, 0.4, 0.25));
Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.8, 0.4, 0.6));
Rng2 screen_selection = params.screen_selection;
Rng2 world_selection = params.world_selection;
Rng2 tile_selection;
tile_selection.p0 = floor(mul(params.af.world_to_tile, Vec3(world_selection.p0, 1)));
tile_selection.p1 = ceil(mul(params.af.world_to_tile, Vec3(world_selection.p1, 1)));
f32 dist = 100000000;
dist = min(dist, screen_pos.x - screen_selection.p0.x);
dist = min(dist, screen_pos.y - screen_selection.p0.y);
dist = min(dist, screen_selection.p1.x - screen_pos.x);
dist = min(dist, screen_selection.p1.y - screen_pos.y);
dist = -dist;
// if (dist >= -half_thickness && dist <= half_thickness)
// {
// selection_color = border_color;
// }
// else
{
if (
world_pos.x > -(P_WorldPitch / 2) &&
world_pos.y > -(P_WorldPitch / 2) &&
world_pos.x < (P_WorldPitch / 2) &&
world_pos.y < (P_WorldPitch / 2) &&
tile_pos.x >= tile_selection.p0.x &&
tile_pos.x <= tile_selection.p1.x &&
tile_pos.y >= tile_selection.p0.y &&
tile_pos.y <= tile_selection.p1.y
)
{
selection_color = inner_color;
}
}
// Premultiply
selection_color.rgb *= selection_color.a;
}
//////////////////////////////
//- Grid
Vec4 grid_color = 0;
if (is_in_world_bounds)
{
// Grid outline
if (V_ShaderConst_GpuFlags & V_GpuFlag_DebugDraw)
{
const Vec4 line_color = LinearFromSrgb(Vec4(1, 1, 1, 0.1));
Vec2 line_screen_p0 = mul(params.af.world_to_screen, Vec3(floor(world_pos), 1));
Vec2 line_screen_p1 = mul(params.af.world_to_screen, Vec3(ceil(world_pos), 1));
f32 line_dist = 100000;
line_dist = min(line_dist, abs(screen_pos.x - line_screen_p0.x));
line_dist = min(line_dist, abs(screen_pos.x - line_screen_p1.x));
line_dist = min(line_dist, abs(screen_pos.y - line_screen_p0.y));
line_dist = min(line_dist, abs(screen_pos.y - line_screen_p1.y));
if (line_dist <= half_thickness * 0.5)
{
grid_color = line_color;
}
}
// Axis
if (V_ShaderConst_GpuFlags & V_GpuFlag_DebugDraw)
{
const Vec4 x_axis_color = LinearFromSrgb(Vec4(0.75, 0, 0, 1));
const Vec4 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1));
Vec2 zero_screen = mul(params.af.world_to_screen, Vec3(0, 0, 1));
f32 x_dist = abs(screen_pos.x - zero_screen.x);
f32 y_dist = abs(screen_pos.y - zero_screen.y);
if (y_dist <= half_thickness)
{
grid_color = x_axis_color;
}
else if (x_dist <= half_thickness)
{
grid_color = y_axis_color;
}
}
// World bounds
{
const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1));
f32 bounds_dist = 100000;
bounds_dist = min(bounds_dist, abs(screen_pos.x - world_bounds_screen_p0.x));
bounds_dist = min(bounds_dist, abs(screen_pos.x - world_bounds_screen_p1.x));
bounds_dist = min(bounds_dist, abs(screen_pos.y - world_bounds_screen_p0.y));
bounds_dist = min(bounds_dist, abs(screen_pos.y - world_bounds_screen_p1.y));
if (bounds_dist <= half_thickness)
{
grid_color = bounds_color;
}
}
// Premultiply
grid_color.rgb *= grid_color.a;
}
//////////////////////////////
//- Crosshair
Vec4 crosshair_color = 0;
{
f32 screen_dist = length(params.screen_crosshair - screen_pos);
if (screen_dist < 5)
{
crosshair_color = Color_White;
}
crosshair_color.rgb *= crosshair_color.a;
}
//////////////////////////////
//- Blend
//- Compose result
Vec4 result = Vec4(0, 0, 0, 1);
// result = BlendPremul(shade_color, result);
result = BlendPremul(albedo_color, result);
result = BlendPremul(particle_color, result);
result = BlendPremul(selection_color, result);
result = BlendPremul(grid_color, result);
// Adaptively blend crosshair
{
f32 luminance = LuminanceFromColor(result);
f32 adaptive_threshold = 0.5;
Vec4 adapted_crosshair_color = crosshair_color;
if (luminance > adaptive_threshold)
{
adapted_crosshair_color = InvertColor(Unpremul(crosshair_color));
adapted_crosshair_color = Premul(adapted_crosshair_color);
}
result = BlendPremul(adapted_crosshair_color, result);
}
result = BlendPremul(world_color, result);
result = BlendPremul(overlay_color, result);
result = Unpremul(result);

View File

@ -430,6 +430,7 @@ void SPR_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame)
G_Format_R8G8B8A8_Unorm_Srgb,
atlas->dims,
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
.debug = Lit("Sprite atlas")
);
atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex);
}

View File

@ -89,7 +89,6 @@ typedef struct DWRITE_FONT_METRICS {
UINT16 strikethroughThickness;
} DWRITE_FONT_METRICS;
typedef enum DWRITE_GRID_FIT_MODE {
DWRITE_GRID_FIT_MODE_DEFAULT = 0,
DWRITE_GRID_FIT_MODE_DISABLED = 1,

View File

@ -1670,13 +1670,18 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
G_Format_R16G16B16A16_Float,
monitor_size,
G_Layout_DirectQueue_RenderTargetWrite,
.flags = G_ResourceFlag_AllowRenderTarget
.flags = G_ResourceFlag_AllowRenderTarget,
.debug = Lit("UI draw target")
);
G_Texture2DRef draw_target_ro = G_PushTexture2DRef(frame->gpu_arena, draw_target);
// Rects
u64 rects_count = ArenaCount(frame->rects_arena, UI_GpuRect);
G_ResourceHandle rects_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->rects_arena));
G_ResourceHandle rects_buff = G_PushBufferFromCpuCopy(
frame->gpu_arena, frame->cl,
StringFromArena(frame->rects_arena),
.debug = Lit("UI rects")
);
G_StructuredBufferRef rects_ro = G_PushStructuredBufferRef(frame->gpu_arena, rects_buff, UI_GpuRect);
// Params
@ -1689,7 +1694,11 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
params.cursor_pos = frame->cursor_pos;
params.aa = TweakFloat("UI anti-aliasing", 1, 0, 1);
}
G_ResourceHandle params_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromStruct(&params));
G_ResourceHandle params_buff = G_PushBufferFromCpuCopy(
frame->gpu_arena, frame->cl,
StringFromStruct(&params),
.debug = Lit("UI gpu params")
);
G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, UI_GpuParams);
// Constants