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); WaveSync(lane);
////////////////////////////// //////////////////////////////

View File

@ -439,7 +439,6 @@ CR_Item *CR_ItemFromString(Arena *arena, String str)
} }
} }
EndScratch(scratch); EndScratch(scratch);
return result; 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; } 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; } f64 ClampF64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ? max : v; }
//- Saturate //- Saturate
u32 SaturateU32(u32 v) { return v < 0 ? 0 : v > 1 ? 1 : v; } u32 SaturateU32(u32 v) { return v < 0 ? 0 : v > 1 ? 1 : v; }
i32 SaturateI32(i32 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 //~ Resource ops

View File

@ -49,66 +49,65 @@ u32 countof(T arr[N])
//~ C -> HLSL interoperability stubs //~ C -> HLSL interoperability stubs
//- Min //- Min
#define MinU8 min #define MinU8 (u8)min
#define MinI8 min #define MinI8 (i8)min
#define MinU32 min #define MinU32 (u32)min
#define MinI32 min #define MinI32 (i32)min
#define MinF32 min #define MinF32 (f32)min
#define MinU64 min #define MinU64 (u64)min
#define MinI64 min #define MinI64 (i64)min
#define MinF64 min #define MinF64 (f64)min
//- Max //- Max
#define MaxU8 max #define MaxU8 (u8)max
#define MaxI8 max #define MaxI8 (i8)max
#define MaxU32 max #define MaxU32 (u32)max
#define MaxI32 max #define MaxI32 (i32)max
#define MaxF32 max #define MaxF32 (f32)max
#define MaxU64 max #define MaxU64 (u64)max
#define MaxI64 max #define MaxI64 (i64)max
#define MaxF64 max #define MaxF64 (f64)max
//- Clamp //- Clamp
#define ClampU32 clamp #define ClampU32 (u32)clamp
#define ClampI32 clamp #define ClampI32 (i32)clamp
#define ClampF32 clamp #define ClampF32 (f32)clamp
#define ClampU64 clamp #define ClampU64 (u64)clamp
#define ClampI64 clamp #define ClampI64 (i64)clamp
#define ClampF64 clamp #define ClampF64 (f64)clamp
//- Round //- Round
#define RoundF32 round #define RoundF32 (f32)round
#define RoundF64 round #define RoundF64 (f64)round
//- Floor //- Floor
#define FloorF32 floor #define FloorF32 (f32)floor
#define FloorF64 floor #define FloorF64 (f64)floor
//- Ceil //- Ceil
#define CeilF32 ceil #define CeilF32 (f32)ceil
#define CeilF64 ceil #define CeilF64 (f64)ceil
//- Trunc //- Trunc
#define TruncF32 trunc #define TruncF32 (f32)trunc
#define TruncF64 trunc #define TruncF64 (f64)trunc
//- Mod //- Mod
#define ModF32 fmod #define ModF32 (f32)fmod
#define ModF64 fmod #define ModF64 (f64)fmod
//- Abs //- Abs
#define AbsF32 abs #define AbsF32 (f32)abs
#define AbsF64 abs #define AbsF64 (f64)abs
//- Sign //- Sign
#define SignF32 sign #define SignF32 (f32)sign
#define SignF64 sign #define SignF64 (f64)sign
//- Smoothstep //- Smoothstep
#define SmoothstepF32 smoothstep #define SmoothstepF32 (f32)smoothstep
#define SmoothstepF64 smoothstep #define SmoothstepF64 (f64)smoothstep
//- Matchfloor
#define MatchFloor(a, b) all(floor(a) == floor(b)) #define MatchFloor(a, b) all(floor(a) == floor(b))
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -166,12 +165,12 @@ Inline Vec4 LinearFromSrgb(Vec4 srgb)
Inline f32 LuminanceFromColor(Vec4 v) Inline f32 LuminanceFromColor(Vec4 v)
{ {
return 0.2126 * v.r + 0.7152 * v.g + 0.0722 * v.b; return 0.2126 * v.r + 0.7152 * v.g + 0.0722 * v.b;
}; }
Inline Vec4 InvertColor(Vec4 v) Inline Vec4 InvertColor(Vec4 v)
{ {
return Vec4(Vec3(1, 1, 1) - v.rgb, v.a); return Vec4(Vec3(1, 1, 1) - v.rgb, v.a);
}; }
Inline Vec4 Premul(Vec4 v) 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 FmtChar(v, ...) FMTARG(FmtArgKind_Char, .value.c = (v), __VA_ARGS__)
#define FmtString(v, ...) FMTARG(FmtArgKind_String, .value.string = (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 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 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__) #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, G_Format_R8G8B8A8_Unorm_Srgb,
atlas->dims, atlas->dims,
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present, G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
.debug = Lit("Glyph atlas")
); );
atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex); 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_ZeroMemory = (1 << 3),
G_ResourceFlag_HostMemory = (1 << 4), // Resource will be mapped into the cpu's address space 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_Uncached = (1 << 5), // Cpu writes will be combined & reads will be uncached
G_ResourceFlag_ForceNoReuse = (1 << 6),
}; };
Struct(G_BufferDesc) Struct(G_BufferDesc)
{ {
G_ResourceFlag flags; G_ResourceFlag flags;
u64 size; u64 size;
String debug;
}; };
Struct(G_TextureDesc) Struct(G_TextureDesc)
@ -431,6 +433,7 @@ Struct(G_TextureDesc)
G_Layout initial_layout; G_Layout initial_layout;
i32 mip_levels; // Will be clamped to range [1, inf) i32 mip_levels; // Will be clamped to range [1, inf)
Vec4 clear_color; Vec4 clear_color;
String debug;
}; };
Struct(G_SamplerDesc) Struct(G_SamplerDesc)
@ -446,6 +449,7 @@ Struct(G_SamplerDesc)
Vec4 border_color; Vec4 border_color;
f32 min_lod; f32 min_lod;
f32 max_lod; f32 max_lod;
String debug;
}; };
Struct(G_ResourceDesc) Struct(G_ResourceDesc)

View File

@ -450,6 +450,34 @@ D3D12_BARRIER_LAYOUT G_D12_BarrierLayoutFromLayout(G_Layout layout)
return result; 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 //~ Pipeline
@ -497,13 +525,39 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
// Create pipeline // Create pipeline
if (is_pipeline_new) if (is_pipeline_new)
{ {
TempArena scratch = BeginScratchNoConflict();
HRESULT hr = 0; HRESULT hr = 0;
b32 ok = 1; b32 ok = 1;
String error_str = Zi; 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 // Create PSO
ID3D12PipelineState *pso = 0; ID3D12PipelineState *pso = 0;
if (ok && (!IsResourceNil(desc.vs.resource) || !IsResourceNil(desc.ps.resource))) if (ok)
{
if (!is_compute)
{ {
i32 rts_count = 0; i32 rts_count = 0;
b32 has_multiple_blend_modes = 0; b32 has_multiple_blend_modes = 0;
@ -632,11 +686,11 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
hr = ID3D12Device_CreateGraphicsPipelineState(G_D12.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso); hr = ID3D12Device_CreateGraphicsPipelineState(G_D12.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
if (FAILED(hr)) if (FAILED(hr))
{ {
error_str = Lit("Failed to create graphics pipeline"); error_str = StringF(scratch.arena, "Failed to create graphics pipeline \"%F\"", FmtString(pipeline_name));
ok = 0; ok = 0;
} }
} }
else if (ok) else
{ {
String cs = DataFromResource(desc.cs.resource); String cs = DataFromResource(desc.cs.resource);
D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc = Zi; D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc = Zi;
@ -648,12 +702,20 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
hr = ID3D12Device_CreateComputePipelineState(G_D12.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso); hr = ID3D12Device_CreateComputePipelineState(G_D12.device, &pso_desc, &IID_ID3D12PipelineState, (void **)&pso);
if (FAILED(hr)) if (FAILED(hr))
{ {
error_str = Lit("Failed to create compute pipeline"); error_str = StringF(scratch.arena, "Failed to create compute pipeline \"%F\"", FmtString(pipeline_name));
ok = 0; ok = 0;
} }
} }
}
if (!ok) if (ok)
{
if (GPU_DEBUG)
{
G_D12_SetObjectName((ID3D12Object *)pso, pipeline_name);
}
}
else
{ {
// TOOD: Don't panic // TOOD: Don't panic
Panic(error_str); Panic(error_str);
@ -662,6 +724,7 @@ G_D12_Pipeline *G_D12_PipelineFromDesc(G_D12_PipelineDesc desc)
pipeline->pso = pso; pipeline->pso = pso;
pipeline->error = error_str; pipeline->error = error_str;
pipeline->ok = ok; pipeline->ok = ok;
EndScratch(scratch);
} }
return pipeline; 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_Texture2D ||
desc.kind == G_ResourceKind_Texture3D; desc.kind == G_ResourceKind_Texture3D;
b32 is_sampler = desc.kind == G_ResourceKind_Sampler; b32 is_sampler = desc.kind == G_ResourceKind_Sampler;
G_ResourceFlag flags = G_ResourceFlag flags =
is_buffer ? desc.buffer.flags : is_buffer ? desc.buffer.flags :
is_texture ? desc.texture.flags : is_texture ? desc.texture.flags :
desc.sampler.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 //- Initialize heap info
b32 can_reuse = 1; b32 can_reuse = !AnyBit(flags, G_ResourceFlag_ForceNoReuse);
D3D12_HEAP_FLAGS heap_flags = 0; D3D12_HEAP_FLAGS heap_flags = 0;
D3D12_HEAP_PROPERTIES heap_props = Zi; D3D12_HEAP_PROPERTIES heap_props = Zi;
@ -1047,8 +1117,14 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
Unlock(&lock); Unlock(&lock);
} }
ZeroStruct(release); ZeroStruct(release);
release->d3d_resource = resource->d3d_resource;
SllQueuePush(cl->releases.first, cl->releases.last, release); 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); 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 //- 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")); 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; index = descriptors_count;
} }
} }

View File

@ -11,7 +11,7 @@
#pragma comment(lib, "dxgi") #pragma comment(lib, "dxgi")
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Tweakable defines //~ Tweakable definitions
#define G_D12_TearingIsAllowed 1 #define G_D12_TearingIsAllowed 1
#define G_D12_FrameLatency 1 #define G_D12_FrameLatency 1
@ -25,6 +25,8 @@
#define G_D12_MaxSamplerDescriptors (1024 * 1) #define G_D12_MaxSamplerDescriptors (1024 * 1)
#define G_D12_MaxRtvDescriptors (1024 * 64) #define G_D12_MaxRtvDescriptors (1024 * 64)
#define G_D12_MaxDebugTextLen 64
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Pipeline types //~ Pipeline types
@ -90,6 +92,9 @@ Struct(G_D12_Resource)
// Backbuffer info // Backbuffer info
struct G_D12_Swapchain *swapchain; struct G_D12_Swapchain *swapchain;
u64 debug_text_len;
u8 debug_text[G_D12_MaxDebugTextLen];
}; };
Struct(G_D12_ResourceList) Struct(G_D12_ResourceList)
@ -273,6 +278,9 @@ Struct(G_D12_Releasable)
i64 completion_queue_target; i64 completion_queue_target;
ID3D12Resource *d3d_resource; ID3D12Resource *d3d_resource;
u64 debug_text_len;
u8 debug_text[G_D12_MaxDebugTextLen];
}; };
Struct(G_D12_ReleasableList) 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_ACCESS G_D12_BarrierAccessFromAccesses(G_Access accesses);
D3D12_BARRIER_LAYOUT G_D12_BarrierLayoutFromLayout(G_Layout layout); 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 //~ Pipeline

View File

@ -426,11 +426,13 @@ void BuildEntryPoint(WaveLaneCtx *lane)
//- Dxc //- Dxc
{ {
PushStringToList(perm, &cp.flags_dxc, Lit("-O3")); PushStringToList(perm, &cp.flags_dxc, Lit("-O3"));
// PushStringToList(perm, &cp.flags_dxc, Lit("-Od"));
PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug")); PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug"));
// Enable warnings // Enable warnings
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wall")); PushStringToList(perm, &cp.warnings_dxc, Lit("-Wall"));
PushStringToList(perm, &cp.warnings_dxc, Lit("-WX")); PushStringToList(perm, &cp.warnings_dxc, Lit("-WX"));
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wshadow"));
// Disable warnings // Disable warnings
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-unused-variable")); PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-unused-variable"));

View File

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

View File

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

View File

@ -411,7 +411,8 @@ void V_TickForever(WaveLaneCtx *lane)
gpu_perm, cl, gpu_perm, cl,
V_GpuState, V_GpuState,
1, 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); gpu_state_ref = G_PushRWStructuredBufferRef(gpu_perm, gpu_state, V_GpuState);
} }
@ -422,7 +423,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R8_Uint, G_Format_R8_Uint,
tiles_dims, tiles_dims,
G_Layout_DirectQueue_ShaderRead, G_Layout_DirectQueue_ShaderRead,
.flags = G_ResourceFlag_ZeroMemory .flags = G_ResourceFlag_ZeroMemory,
.debug = Lit("Tiles")
); );
gpu_tiles_ref = G_PushTexture2DRef(gpu_perm, gpu_tiles); gpu_tiles_ref = G_PushTexture2DRef(gpu_perm, gpu_tiles);
} }
@ -432,7 +434,8 @@ void V_TickForever(WaveLaneCtx *lane)
gpu_perm, cl, gpu_perm, cl,
V_Particle, V_Particle,
V_ParticlesCap, 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); gpu_particles_ref = G_PushRWStructuredBufferRef(gpu_perm, gpu_particles, V_Particle);
} }
@ -446,7 +449,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R16G16B16A16_Float, G_Format_R16G16B16A16_Float,
cells_dims, cells_dims,
G_Layout_DirectQueue_ShaderReadWrite, 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); gpu_cells_ref = G_PushRWTexture2DRef(gpu_perm, gpu_cells);
} }
@ -460,7 +464,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R16G16B16A16_Float, G_Format_R16G16B16A16_Float,
cells_dims, cells_dims,
G_Layout_DirectQueue_ShaderReadWrite, 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); gpu_stains_ref = G_PushRWTexture2DRef(gpu_perm, gpu_stains);
} }
@ -475,7 +480,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R32_Float, G_Format_R32_Float,
cells_dims, cells_dims,
G_Layout_DirectQueue_ShaderReadWrite, 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); 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]; f32 fire_presses = fire_held && !prev_frame->held_buttons[Button_M1];
{ {
// TODO: Adjustable sensitivity // TODO: Adjustable sensitivity
f32 mouse_sensitivity = TweakFloat("Mouse sensitivity", 1.0, 0.1, 5.0);
f32 mouse_scale_factor = 0.005; f32 mouse_scale_factor = 0.005;
look = frame->look; 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); look = ClampVec2Len(look, look_radius);
} }
if (frame->is_editing) if (frame->is_editing)
@ -4445,7 +4452,8 @@ void V_TickForever(WaveLaneCtx *lane)
G_Format_R16G16B16A16_Float, G_Format_R16G16B16A16_Float,
frame->screen_dims, frame->screen_dims,
G_Layout_DirectQueue_RenderTargetWrite, 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); 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)); 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, G_Format_R16G16B16A16_Float,
frame->screen_dims, frame->screen_dims,
G_Layout_DirectQueue_RenderTargetWrite, 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); 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, G_Format_R16G16B16A16_Float,
frame->shade_dims, frame->shade_dims,
G_Layout_DirectQueue_ShaderReadWrite, 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_Texture2DRef shade_target_ro = G_PushTexture2DRef(frame->gpu_arena, shade_target);
G_RWTexture2DRef shade_target_rw = G_PushRWTexture2DRef(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)); Rng2 shade_scissor = RNG2(VEC2(shade_viewport.p0.x, shade_viewport.p0.y), VEC2(shade_viewport.p1.x, shade_viewport.p1.y));
// Quad buffers // 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); G_StructuredBufferRef quads_ref = G_PushStructuredBufferRef(frame->gpu_arena, quads_buff, V_Quad);
// Debug shape buffers // Debug shape buffers
G_ResourceHandle dverts_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->dverts_arena)); G_ResourceHandle dverts_buff = G_PushBufferFromCpuCopy(
G_ResourceHandle dvert_idxs_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->dvert_idxs_arena)); 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_StructuredBufferRef dverts_ref = G_PushStructuredBufferRef(frame->gpu_arena, dverts_buff, V_DVert);
G_IndexBufferDesc dvert_idxs_ib = G_IdxBuff32(dvert_idxs_buff); G_IndexBufferDesc dvert_idxs_ib = G_IdxBuff32(dvert_idxs_buff);
@ -4497,7 +4519,11 @@ void V_TickForever(WaveLaneCtx *lane)
++emitter_idx; ++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); 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); G_StructuredBufferRef gpu_params_ref = G_PushStructuredBufferRef(frame->gpu_arena, gpu_params, V_GpuParams);
// Upload tiles // Upload tiles
@ -4680,12 +4710,9 @@ void V_TickForever(WaveLaneCtx *lane)
G_DumbMemoryLayoutSync(frame->cl, shade_target, G_Layout_DirectQueue_ShaderRead); G_DumbMemoryLayoutSync(frame->cl, shade_target, G_Layout_DirectQueue_ShaderRead);
} }
////////////////////////////// //////////////////////////////
//- Composite pass //- Composite pass
G_DumbMemoryLayoutSync(frame->cl, screen_target, G_Layout_DirectQueue_RenderTargetWrite);
{ {
G_Rasterize( G_Rasterize(
frame->cl, frame->cl,

View File

@ -25,11 +25,12 @@ ComputeShader2D(V_PrepareShadeCS, 8, 8)
{ {
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0]; V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
RWTexture2D<Vec4> shade = G_Dereference<Vec4>(params.shade_rw); RWTexture2D<Vec4> shade = G_Dereference<Vec4>(params.shade_rw);
Vec2 shade_idx = SV_DispatchThreadID; Vec2 shade_pos = SV_DispatchThreadID;
if (all(shade_idx < countof(shade)))
if (all(shade_pos < countof(shade)))
{ {
// Clear 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]; V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
RWTexture2D<Vec4> cells = G_Dereference<Vec4>(params.cells); RWTexture2D<Vec4> cells = G_Dereference<Vec4>(params.cells);
RWTexture2D<f32> drynesses = G_Dereference<f32>(params.drynesses); RWTexture2D<f32> drynesses = G_Dereference<f32>(params.drynesses);
Vec2 cells_idx = SV_DispatchThreadID; Vec2 cells_pos = SV_DispatchThreadID;
if (all(cells_idx < countof(cells))) if (all(cells_pos < countof(cells)))
{ {
// Clear cell // Clear cell
cells[cells_idx] = 0; cells[cells_pos] = 0;
// Increase dryness // Increase dryness
f32 dry_rate = params.dt * 0.1; 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); f32 new_dryness = lerp(old_dryness, 1, dry_rate);
drynesses[cells_idx] = new_dryness; drynesses[cells_pos] = new_dryness;
} }
// Clear stain // Clear stain
if (params.should_clear_stains) if (params.should_clear_stains)
{ {
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains); RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains);
stains[cells_idx] = 0; stains[cells_pos] = 0;
drynesses[cells_idx] = 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); Texture2D<Vec4> tex = G_Dereference<Vec4>(quad.tex);
Vec4 albedo = tex.Sample(clamp_sampler, input.samp_uv); Vec4 albedo = tex.Sample(clamp_sampler, input.samp_uv);
// Vec4 albedo = Color_Cyan;
V_QuadPSOutput output; V_QuadPSOutput output;
output.sv_target0 = albedo; output.sv_target0 = albedo;
return output; 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 //~ Particle simulation
@ -378,7 +167,9 @@ ComputeShader(V_SimParticlesCS, 64)
V_Particle particle = particles[particle_idx]; V_Particle particle = particles[particle_idx];
if (particle.exists > 0) if (particle.exists > 0)
{ {
// Initialize //////////////////////////////
//- Initialize particle
if (particle.emitter_init_num != 0) if (particle.emitter_init_num != 0)
{ {
V_Emitter emitter = G_Dereference<V_Emitter>(params.emitters)[particle.emitter_init_num - 1]; V_Emitter emitter = G_Dereference<V_Emitter>(params.emitters)[particle.emitter_init_num - 1];
@ -418,11 +209,15 @@ ComputeShader(V_SimParticlesCS, 64)
particle.emitter_init_num = 0; 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
f32 prev_exists = particle.exists;
{
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 // Simulate
f32 old_exists = particle.exists;
{ {
particle.pos += particle.velocity * params.dt; particle.pos += particle.velocity * params.dt;
particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt); particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt);
@ -435,23 +230,31 @@ ComputeShader(V_SimParticlesCS, 64)
{ {
particle.exists = 0; particle.exists = 0;
} }
if (!is_in_world_bounds)
{
particle.exists = 0;
} }
} }
// Commit //////////////////////////////
//- Commit particle
// FIXME: Atomic writes // FIXME: Atomic writes
{ {
b32 should_stain = 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 *= prev_exists;
// Stain
if (is_in_world)
{
b32 should_stain = (
AnyBit(particle.flags, V_ParticleFlag_StainTrail) || AnyBit(particle.flags, V_ParticleFlag_StainTrail) ||
(AnyBit(particle.flags, V_ParticleFlag_StainOnPrune) && particle.exists == 0) (AnyBit(particle.flags, V_ParticleFlag_StainOnPrune) && particle.exists == 0)
); );
b32 should_draw = is_in_world_bounds;
Vec4 color = particle.color;
color.a *= old_exists;
// Stain // Stain
if (should_stain) if (should_stain)
@ -469,13 +272,19 @@ ComputeShader(V_SimParticlesCS, 64)
stains[cell_pos] = new_stain; stains[cell_pos] = new_stain;
drynesses[cell_pos] = 0; drynesses[cell_pos] = 0;
} }
}
// Draw // Draw
{
b32 should_draw = is_in_world;
if (should_draw) if (should_draw)
{ {
cells[cell_pos] = color; cells[cell_pos] = color;
} }
} }
}
particles[particle_idx] = particle; particles[particle_idx] = particle;
} }
} }
@ -488,7 +297,7 @@ ComputeShader2D(V_ShadeCS, 8, 8)
{ {
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0]; V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
RWTexture2D<Vec4> shade_tex = G_Dereference<Vec4>(params.shade_rw); 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); Texture2D<P_TileKind> tiles = G_Dereference<P_TileKind>(params.tiles);
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains); RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains);
RWTexture2D<f32> drynesses = G_Dereference<f32>(params.drynesses); 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 shade_pos = SV_DispatchThreadID + Vec2(0.5, 0.5);
Vec2 world_pos = mul(params.af.shade_to_world, Vec3(shade_pos, 1)); 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)); Vec2 tile_pos = mul(params.af.world_to_tile, Vec3(world_pos, 1));
P_TileKind tile = tiles.Load(Vec3(tile_pos, 0)); P_TileKind tile = tiles.Load(Vec3(tile_pos, 0));
Vec2 half_world_dims = Vec2(P_WorldPitch, P_WorldPitch) * 0.5; 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 //- Compute albedo
@ -543,7 +352,7 @@ VertexShader(V_CompositeVS, V_CompositePSInput)
PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input) PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
{ {
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0]; 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); Texture2D<Vec4> albedo_tex = G_Dereference<Vec4>(params.albedo_ro);
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains); RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains);
RWTexture2D<Vec4> cells = G_Dereference<Vec4>(params.cells); RWTexture2D<Vec4> cells = G_Dereference<Vec4>(params.cells);
@ -554,27 +363,27 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
Vec2 screen_pos = input.sv_position.xy; Vec2 screen_pos = input.sv_position.xy;
Vec2 world_pos = mul(params.af.screen_to_world, Vec3(screen_pos, 1)); 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 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)); 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 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_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)); Vec2 world_bounds_screen_p1 = mul(params.af.world_to_screen, Vec3(half_world_dims.xy, 1));
b32 is_in_world_bounds = ( b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells));
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)
);
P_TileKind tile = tiles.Load(Vec3(tile_pos, 0)); P_TileKind tile = tiles.Load(Vec3(tile_pos, 0));
P_TileKind equipped_tile = params.equipped_tile; P_TileKind equipped_tile = params.equipped_tile;
//////////////////////////////
//- World color
Vec4 world_color = Vec4(0.025, 0.025, 0.025, 1);
if (is_in_world)
{
////////////////////////////// //////////////////////////////
//- Shade color //- Shade color
// Vec4 shade_color = 0; Vec4 shade_color = 0;
// if (all(shade_pos >= Vec2(0, 0)) && all(shade_pos < countof(shade_tex))) // if (all(shade_pos >= Vec2(0, 0)) && all(shade_pos < countof(shade_tex)))
// { // {
// Vec2 shade_uv = shade_pos / countof(shade_tex); // Vec2 shade_uv = shade_pos / countof(shade_tex);
@ -582,18 +391,17 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
// } // }
////////////////////////////// //////////////////////////////
//- Albedo color //- Albedo
Vec4 albedo_color = 0; Vec4 albedo_color = 0;
{ {
////////////////////////////// //////////////////////////////
//- Tile color //- Tile
// TODO: Remove this // TODO: Remove this
b32 tile_is_wall = 0; b32 tile_is_wall = 0;
Vec4 tile_color = Vec4(0.025, 0.025, 0.025, 1); Vec4 tile_color = 0;
if (is_in_world_bounds)
{ {
P_TileKind tile_tl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y - 1, 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_tr = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y - 1, 0));
@ -620,7 +428,6 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
Vec4 outer = LinearFromSrgb(Vec4(0.05, 0.05, 0.05, 1)); Vec4 outer = LinearFromSrgb(Vec4(0.05, 0.05, 0.05, 1));
Vec4 inner = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 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.375));
// tile_color = lerp(outer, inner, smoothstep(0, 1, tile_edge_dist / 0.5));
tile_is_wall = 1; tile_is_wall = 1;
} }
else if (tile != P_TileKind_Empty) else if (tile != P_TileKind_Empty)
@ -661,12 +468,13 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
} }
////////////////////////////// //////////////////////////////
//- Stain color //- Stain
Vec4 stain_color = 0; Vec4 stain_color = 0;
{ {
f32 dryness = drynesses.Load(cell_pos); f32 dryness = drynesses.Load(cell_pos);
stain_color = V_DryColor(stains.Load(cell_pos), dryness); 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 stain_color.rgb *= 1.0 - (0.75 * tile_is_wall); // Darken wall stains
} }
@ -678,24 +486,41 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
////////////////////////////// //////////////////////////////
//- Compose albedo //- Compose albedo
albedo_color = BlendPremul(!tile_is_wall * tile_color, albedo_color); // Blend floor tile if (!tile_is_wall)
albedo_color = BlendPremul(!tile_is_wall * stain_color, albedo_color); // Blend floor stain {
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); albedo_color = BlendPremul(albedo_tex_color, albedo_color);
albedo_color = BlendPremul(tile_is_wall * tile_color, albedo_color); // Blend wall tile if (tile_is_wall)
albedo_color = BlendPremul(tile_is_wall * stain_color, albedo_color); // Blend wall stain {
albedo_color = BlendPremul(tile_color, albedo_color); // Blend wall tile
albedo_color = BlendPremul(stain_color, albedo_color); // Blend wall stain
}
} }
////////////////////////////// //////////////////////////////
//- Particle color //- Particle
// TODO: Remove this // TODO: Remove this
Vec4 particle_color = 0; Vec4 particle_color = cells.Load(cell_pos);
if (is_in_world_bounds)
{ //////////////////////////////
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 //- Tile selection overlay
@ -749,7 +574,7 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
//- Grid //- Grid
Vec4 grid_color = 0; Vec4 grid_color = 0;
if (is_in_world_bounds) if (is_in_world)
{ {
// Grid outline // Grid outline
if (V_ShaderConst_GpuFlags & V_GpuFlag_DebugDraw) if (V_ShaderConst_GpuFlags & V_GpuFlag_DebugDraw)
@ -808,40 +633,43 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
////////////////////////////// //////////////////////////////
//- Crosshair //- Crosshair
// TODO: Remove this
Vec4 crosshair_color = 0; Vec4 crosshair_color = 0;
{ {
f32 screen_dist = length(params.screen_crosshair - screen_pos); f32 dist = length(params.screen_crosshair - screen_pos);
if (dist < 4)
if (screen_dist < 5) {
// 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)
{ {
crosshair_color = Color_White; crosshair_color = Color_White;
} }
else
crosshair_color.rgb *= crosshair_color.a; {
crosshair_color = InvertColor(Color_White);
}
crosshair_color = Premul(crosshair_color);
}
} }
////////////////////////////// //////////////////////////////
//- Blend //- Compose overlay
overlay_color = BlendPremul(selection_color, overlay_color);
overlay_color = BlendPremul(grid_color, overlay_color);
overlay_color = BlendPremul(crosshair_color, overlay_color);
}
//////////////////////////////
//- Compose result
Vec4 result = Vec4(0, 0, 0, 1); Vec4 result = Vec4(0, 0, 0, 1);
// result = BlendPremul(shade_color, result); result = BlendPremul(world_color, result);
result = BlendPremul(albedo_color, result); result = BlendPremul(overlay_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 = Unpremul(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, G_Format_R8G8B8A8_Unorm_Srgb,
atlas->dims, atlas->dims,
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present, G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
.debug = Lit("Sprite atlas")
); );
atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex); atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex);
} }

View File

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

View File

@ -1670,13 +1670,18 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
G_Format_R16G16B16A16_Float, G_Format_R16G16B16A16_Float,
monitor_size, monitor_size,
G_Layout_DirectQueue_RenderTargetWrite, 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); G_Texture2DRef draw_target_ro = G_PushTexture2DRef(frame->gpu_arena, draw_target);
// Rects // Rects
u64 rects_count = ArenaCount(frame->rects_arena, UI_GpuRect); 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); G_StructuredBufferRef rects_ro = G_PushStructuredBufferRef(frame->gpu_arena, rects_buff, UI_GpuRect);
// Params // Params
@ -1689,7 +1694,11 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync)
params.cursor_pos = frame->cursor_pos; params.cursor_pos = frame->cursor_pos;
params.aa = TweakFloat("UI anti-aliasing", 1, 0, 1); 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); G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, UI_GpuParams);
// Constants // Constants