SBgl 0.1.0
A graphics framework in C99
Loading...
Searching...
No Matches
sbgl_voxel.c
Go to the documentation of this file.
1
6#include "sbgl_voxel.h"
7#include "sbgl_pool.h"
8#include "core/sbl_arena.h"
10#include <stdlib.h>
11#include <stdio.h>
12#include <string.h>
13#include <math.h>
14#include "voxel_gen.h"
15#include "voxel_mesh.h"
16#include "voxel_cull.h"
17
19#define SBGL_VOXEL_CHUNK_SIZE 256.0f
20
24typedef struct {
27} sbgl_AABB;
28
32typedef struct {
33 uint64_t maskAddress;
34 uint64_t _pad;
36 float seed;
37 uint32_t _pad2[3];
39
43typedef struct {
44 uint64_t maskAddress;
47 uint64_t _pad;
50
54typedef struct {
56 uint64_t aabbAddress;
58 uint64_t countsAddress;
59 float _pad[2];
62 uint32_t _pad2[3];
64
142
144 /*
145 * The voxel system is allocated from the context's persistent arena
146 * to remain consistent with the library's memory model.
147 */
148 SblArena* ctxArena = sbgl_GetContextArena(ctx);
149 if (!ctxArena)
150 return NULL;
151
153 if (!sys)
154 return NULL;
155
156 sys->ctx = ctx;
157 sys->chunk_radius = config->chunk_radius;
158 sys->enable_telemetry = config->enable_telemetry;
159 sys->last_update_time = sbgl_GetTime(ctx);
160
161 /*
162 * Initialize the voxel pool with the requested capacity.
163 * We utilize a dedicated internal arena for the CPU-side pool management metadata.
164 */
165 sbl_arena_init(&sys->poolArena, 1 * 1024 * 1024);
166 sys->pool = VoxelPool_Init(&sys->poolArena, config->max_slots);
167
168 if (!sys->pool) {
170 return NULL;
171 }
172
173 /*
174 * Allocate a CPU-side mirror of the AABB data. This avoids the read-write
175 * hazard that occurs when mapping the previous frame's GPU buffer while
176 * the GPU may still be consuming it.
177 */
179 if (!sys->cpuAABB) {
181 return NULL;
182 }
183
184 /*
185 * Initialize the camera tracking state to force an initial update.
186 */
187 sys->last_cam_chunk = (sbgl_ivec3){ -1000000, -1000000, -1000000 };
188
189 /*
190 * Load the compute shaders required for the voxel processing pipeline.
191 * These shaders handle generation, shell extraction, and frustum culling.
192 */
193 sbgl_Shader genShader = sbgl_LoadShader(ctx, SBGL_SHADER_STAGE_COMPUTE, (const uint32_t*)voxel_gen_comp_spv, voxel_gen_comp_spv_len);
194 sbgl_Shader shellShader = sbgl_LoadShader(ctx, SBGL_SHADER_STAGE_COMPUTE, (const uint32_t*)voxel_mesh_comp_spv, voxel_mesh_comp_spv_len);
195 sbgl_Shader cullShader = sbgl_LoadShader(ctx, SBGL_SHADER_STAGE_COMPUTE, (const uint32_t*)voxel_cull_comp_spv, voxel_cull_comp_spv_len);
196
197 if (genShader == SBGL_INVALID_HANDLE || shellShader == SBGL_INVALID_HANDLE || cullShader == SBGL_INVALID_HANDLE) {
198 if (genShader != SBGL_INVALID_HANDLE) sbgl_DestroyShader(ctx, genShader);
199 if (shellShader != SBGL_INVALID_HANDLE) sbgl_DestroyShader(ctx, shellShader);
200 if (cullShader != SBGL_INVALID_HANDLE) sbgl_DestroyShader(ctx, cullShader);
202 return NULL;
203 }
204
205 /*
206 * Create the compute pipelines. Once created, the shader modules can be released.
207 */
208 sys->genPipe = sbgl_CreateComputePipeline(ctx, genShader);
209 sys->shellPipe = sbgl_CreateComputePipeline(ctx, shellShader);
210 sys->cullPipe = sbgl_CreateComputePipeline(ctx, cullShader);
211
212 sbgl_DestroyShader(ctx, genShader);
213 sbgl_DestroyShader(ctx, shellShader);
214 sbgl_DestroyShader(ctx, cullShader);
215
216 /*
217 * Allocate the GPU-side buffers. The mask and instance buffers store the voxel
218 * data, while the AABB buffer is used for GPU-driven culling.
219 */
221 sys->instBuf = sbgl_CreateBuffer(ctx, SBGL_BUFFER_USAGE_STORAGE, config->max_slots * 65536 * sizeof(uint32_t) * 2, NULL);
222 for (int i = 0; i < 2; ++i) {
223 sys->aabbBuf[i] = sbgl_CreateBuffer(ctx, SBGL_BUFFER_USAGE_STORAGE, config->max_slots * sizeof(sbgl_AABB), NULL);
224 void* mappedAABB = sbgl_MapBuffer(ctx, sys->aabbBuf[i]);
225 if (mappedAABB) {
226 memset(mappedAABB, 0, config->max_slots * sizeof(sbgl_AABB));
227 sbgl_UnmapBuffer(ctx, sys->aabbBuf[i]);
228 }
229 }
230
231 /*
232 * Initialize the material palette with default terrain attributes.
233 * This provides a consistent base for procedural generation and shading.
234 */
237 if (palette) {
238 memset(palette, 0, 64 * sizeof(sbgl_Material));
239
240 /* Index 0: Grass (Greenish) */
241 palette[0].color = sbgl_Vec4Set(0.3f, 0.6f, 0.2f, 1.0f);
242 palette[0].roughness = 0.8f;
243 palette[0].metalness = 0.0f;
244
245 /* Index 1: Dirt (Brownish) */
246 palette[1].color = sbgl_Vec4Set(0.4f, 0.3f, 0.2f, 1.0f);
247 palette[1].roughness = 0.9f;
248 palette[1].metalness = 0.0f;
249
250 /* Index 2: Stone (Grey) */
251 palette[2].color = sbgl_Vec4Set(0.5f, 0.5f, 0.5f, 1.0f);
252 palette[2].roughness = 0.6f;
253 palette[2].metalness = 0.0f;
254
255 /* Index 3: Sand (Yellowish) */
256 palette[3].color = sbgl_Vec4Set(0.8f, 0.7f, 0.4f, 1.0f);
257 palette[3].roughness = 0.7f;
258 palette[3].metalness = 0.0f;
259
261 }
262
263 /*
264 * Initialize control buffers.
265 */
267 void* mappedShell = sbgl_MapBuffer(ctx, sys->shellCountsBuf);
268 if (mappedShell) {
269 memset(mappedShell, 0, config->max_slots * sizeof(uint32_t));
271 }
272
273 for (int i = 0; i < 2; ++i) {
275
276 void* mappedCmd = sbgl_MapBuffer(ctx, sys->indirectCmdBuf[i]);
277 if (mappedCmd) {
278 memset(mappedCmd, 0, config->max_slots * sizeof(sbgl_IndirectCommand));
279 sbgl_UnmapBuffer(ctx, sys->indirectCmdBuf[i]);
280 }
281 }
282
283 return sys;
284}
285
287 /*
288 * The update phase performs camera-relative chunk management.
289 * It identifies chunks that have entered the visibility radius and
290 * schedules them for generation in the compute pipelines.
291 * The frame index is synchronized with the engine backend to ensure
292 * correct double-buffering.
293 */
294 sys->frame_idx = sbgl_GetFrameIndex(sys->ctx);
295
296 double currentTime = sbgl_GetTime(sys->ctx);
297 float dt = (float)(currentTime - sys->last_update_time);
298 sys->last_update_time = currentTime;
299
300 sys->telemetry_timer += dt;
301 sys->fps_frames++;
302
303 sys->camera_pos = camera_pos;
304 int camCX = (int)floorf(camera_pos.x / SBGL_VOXEL_CHUNK_SIZE);
305 int camCY = (int)floorf(camera_pos.y / SBGL_VOXEL_CHUNK_SIZE);
306 int camCZ = (int)floorf(camera_pos.z / SBGL_VOXEL_CHUNK_SIZE);
307
308 int radius = (int)sys->chunk_radius;
309
310 /* Always refresh timestamps for all slots that are within the visibility radius.
311 This prevents the LRU pool from prematurely recycling chunks while the camera
312 is moving within a single chunk or stationary. */
313 for (uint32_t i = 0; i < sys->pool->capacity; i++) {
314 if (sys->pool->active[i]) {
315 sbgl_ivec3 p = sys->pool->positions[i];
316 if (abs(p.x - camCX) <= radius && abs(p.z - camCZ) <= radius && p.y >= (camCY - 1) && p.y <= (camCY + 2)) {
317 sys->pool->last_used_frames[i] = sys->pool->current_frame;
318 }
319 }
320 }
321
322 /* Update logic is triggered only when the camera crosses a chunk boundary
323 to minimize unnecessary CPU/GPU overhead. */
324 if (camCX != sys->last_cam_chunk.x || camCY != sys->last_cam_chunk.y || camCZ != sys->last_cam_chunk.z) {
326
327 uint64_t maskBaseAddr = sbgl_GetBufferDeviceAddress(sys->ctx, sys->maskBuf);
328 uint64_t instBaseAddr = sbgl_GetBufferDeviceAddress(sys->ctx, sys->instBuf);
329 uint64_t shellCountsBaseAddr = sbgl_GetBufferDeviceAddress(sys->ctx, sys->shellCountsBuf);
330
331 sbgl_AABB* aabbPtr = (sbgl_AABB*)sbgl_MapBuffer(sys->ctx, sys->aabbBuf[sys->frame_idx]);
332
333 /* Copy current persistent state from the CPU-side mirror to the new frame's GPU buffer. */
334 if (aabbPtr) {
335 memcpy(aabbPtr, sys->cpuAABB, sys->pool->capacity * sizeof(sbgl_AABB));
336 }
337
338 /* First pass: Acquire and generate new chunks in the radius. */
339 for (int dz = -radius; dz <= radius; dz++) {
340 for (int dx = -radius; dx <= radius; dx++) {
341 for (int dy = -1; dy <= 2; dy++) {
342 sbgl_ivec3 pos = { camCX + dx, camCY + dy, camCZ + dz };
343
344 bool is_new = false;
345 int32_t slot = VoxelPool_AcquireSlot(sys->pool, pos, &is_new);
346
347 if (is_new) {
348 uint64_t maskAddr = maskBaseAddr + (slot * 65536);
349 uint64_t instAddr = instBaseAddr + (slot * 65536 * 8);
350 uint64_t countAddr = shellCountsBaseAddr + (slot * 4);
351
352 /* Clear the presence mask and instance counts using GPU-side commands
353 to avoid expensive host-to-device synchronization. */
354 sbgl_FillBuffer(sys->ctx, sys->maskBuf, slot * 65536, 65536, 0);
355 sbgl_FillBuffer(sys->ctx, sys->shellCountsBuf, slot * 4, 4, 0);
356
357 /* Ensure the GPU-side clears are visible before the compute shaders start.
358 SBGL_BARRIER_COMPUTE_TO_COMPUTE now includes TRANSFER synchronization. */
360
363 .maskAddress = maskAddr,
364 .offset = sbgl_Vec4Set((float)pos.x * SBGL_VOXEL_CHUNK_SIZE, (float)pos.y * SBGL_VOXEL_CHUNK_SIZE, (float)pos.z * SBGL_VOXEL_CHUNK_SIZE, 0.0f),
365 .seed = 42.0f
366 };
367 sbgl_PushConstants(sys->ctx, sizeof(gpc), &gpc);
368 sbgl_DispatchCompute(sys->ctx, 4096, 1, 1);
369
371
374 .maskAddress = maskAddr,
375 .instanceAddress = instAddr,
376 .counterAddress = countAddr,
377 .offset = gpc.offset
378 };
379 sbgl_PushConstants(sys->ctx, sizeof(spc), &spc);
380 sbgl_DispatchCompute(sys->ctx, 1, 64, 1);
381
382 sbgl_AABB aabb;
383 aabb.min = sbgl_Vec4Set((float)pos.x * SBGL_VOXEL_CHUNK_SIZE, (float)pos.y * SBGL_VOXEL_CHUNK_SIZE, (float)pos.z * SBGL_VOXEL_CHUNK_SIZE, 1.0f);
385 if (aabbPtr) memcpy(aabbPtr + slot, &aabb, sizeof(sbgl_AABB));
386 sys->cpuAABB[slot] = aabb;
387 }
388 }
389 }
390 }
391
392 /* Second pass: Deactivate slots that have left the visibility radius.
393 This prevents orphaned chunks from flickering or appearing in the wrong location. */
394 for (uint32_t i = 0; i < sys->pool->capacity; i++) {
395 if (sys->pool->active[i]) {
396 sbgl_ivec3 p = sys->pool->positions[i];
397 if (abs(p.x - camCX) > radius || abs(p.z - camCZ) > radius || p.y < (camCY - 1) || p.y > (camCY + 2)) {
398 sys->pool->active[i] = 0;
399 /* Reset the instance count on the GPU to immediately silence the chunk. */
400 sbgl_FillBuffer(sys->ctx, sys->shellCountsBuf, i * 4, 4, 0);
401 }
402 }
403 }
404
405 if (aabbPtr) sbgl_UnmapBuffer(sys->ctx, sys->aabbBuf[sys->frame_idx]);
406
407 /* Ensure that the host-side updates to the AABB buffer are visible to the GPU
408 before the culling and graphics phases begin. */
411
412 /* Ensure that the GPU-side clears from the deactivation pass are visible
413 before the culling phase starts. */
415
416 sbgl_EndCompute(sys->ctx);
417
418 sys->last_cam_chunk = (sbgl_ivec3){ camCX, camCY, camCZ };
419 } else {
420 /* Even if the camera hasn't crossed a chunk boundary, we must still update the
421 AABB buffer for the current frame by copying from the CPU-side mirror.
422 This ensures that the culling shader always has a valid set of AABBs. */
423 sbgl_AABB* aabbPtr = (sbgl_AABB*)sbgl_MapBuffer(sys->ctx, sys->aabbBuf[sys->frame_idx]);
424 if (aabbPtr) {
425 memcpy(aabbPtr, sys->cpuAABB, sys->pool->capacity * sizeof(sbgl_AABB));
426 sbgl_UnmapBuffer(sys->ctx, sys->aabbBuf[sys->frame_idx]);
427 }
430 }
431
433}
434
435
437 /*
438 * Voxel culling follows a GPU-driven pipeline. A compute shader performs
439 * frustum culling on all managed chunks, populating an indirect draw buffer
440 * with commands for only the visible portions of the world.
441 * This is done outside the main render pass to avoid validation errors.
442 */
444
445 /* Ensure any prior host writes to mapped buffers are visible. */
447
448 /*
449 * Retrieve the double-buffered GPU handles for the current frame.
450 */
451 sbgl_Buffer currCmds = sys->indirectCmdBuf[sys->frame_idx];
452 sbgl_Buffer currCounts = sys->shellCountsBuf;
453
454 /*
455 * Bind the culling pipeline and upload the camera and frustum metadata via
456 * push constants.
457 */
459
461 cpc.viewProj = view_proj;
463 cpc.commandAddress = sbgl_GetBufferDeviceAddress(sys->ctx, currCmds);
464 cpc.countsAddress = sbgl_GetBufferDeviceAddress(sys->ctx, currCounts);
465 cpc.cameraPos = sbgl_Vec4Set(sys->camera_pos.x, sys->camera_pos.y, sys->camera_pos.z, 1.0f);
466 cpc.maxDistance = (float)(sys->chunk_radius + 1) * SBGL_VOXEL_CHUNK_SIZE * 1.5f;
467
468 sbgl_PushConstants(sys->ctx, sizeof(cpc), &cpc);
469
470 /*
471 * Dispatch the culling kernel. Each workgroup processes a subset of the
472 * total chunk slots available in the pool.
473 */
474 uint32_t groupCount = (sys->pool->capacity + 63) / 64;
475 sbgl_DispatchCompute(sys->ctx, groupCount, 1, 1);
476
477 /*
478 * Inject memory barriers to ensure that the indirect command buffer and
479 * graphics pipelines can safely consume the results of the compute culling.
480 */
483
484 sbgl_EndCompute(sys->ctx);
485}
486
488 /*
489 * Issue the multi-draw indirect call. The GPU will execute the array of
490 * commands generated by the culling phase in a single submission.
491 * This must be called inside the dynamic rendering pass.
492 */
493 sbgl_Buffer currCmds = sys->indirectCmdBuf[sys->frame_idx];
494 sbgl_DrawIndirect(sys->ctx, currCmds, 0, sys->pool->capacity);
495
496 /*
497 * Handle telemetry reporting if enabled.
498 */
499 if (sys->enable_telemetry && sys->telemetry_timer >= 1.0f) {
500 uint32_t visibleCount = 0;
501 uint32_t totalInstances = 0;
503 if (cmds) {
504 for (uint32_t i = 0; i < sys->pool->capacity; i++) {
505 if (cmds[i].instanceCount > 0) {
506 visibleCount++;
507 totalInstances += cmds[i].instanceCount;
508 }
509 }
510 sbgl_UnmapBuffer(sys->ctx, currCmds);
511 }
512
513 printf("FPS: %u | GPU: %.2fms | Visible: %u/%u | Instances: %u\n",
514 sys->fps_frames,
516 visibleCount,
517 sys->pool->capacity,
518 totalInstances);
519
520 sys->telemetry_timer = 0.0f;
521 sys->fps_frames = 0;
522 }
523}
524
526 /*
527 * GPU resources are released back to the driver before the context
528 * handle itself is discarded.
529 */
530 if (!sys) return;
531
532 /*
533 * Ensure the GPU is no longer accessing the resources before destruction.
534 */
536
537 if (sys->genPipe) sbgl_DestroyComputePipeline(sys->ctx, sys->genPipe);
539 if (sys->cullPipe) sbgl_DestroyComputePipeline(sys->ctx, sys->cullPipe);
540
541 if (sys->maskBuf) sbgl_DestroyBuffer(sys->ctx, sys->maskBuf);
542 if (sys->instBuf) sbgl_DestroyBuffer(sys->ctx, sys->instBuf);
544 for (int i = 0; i < 2; ++i) {
545 if (sys->aabbBuf[i]) sbgl_DestroyBuffer(sys->ctx, sys->aabbBuf[i]);
546 }
547
549 for (int i = 0; i < 2; ++i) {
550 if (sys->indirectCmdBuf[i]) sbgl_DestroyBuffer(sys->ctx, sys->indirectCmdBuf[i]);
551 }
552
554 /* The sys struct itself is allocated from the context arena and is freed
555 when the context is shut down. */
556}
557
559 if (!sys) return 0;
560 return sbgl_GetBufferDeviceAddress(sys->ctx, sys->aabbBuf[sys->frame_idx]);
561}
562
564 if (!sys) return 0;
565 return sbgl_GetBufferDeviceAddress(sys->ctx, sys->instBuf);
566}
567
569 if (!sys) return 0;
571}
572
void sbgl_DestroyComputePipeline(sbgl_Context *ctx, sbgl_ComputePipeline pipeline)
Destroys a compute pipeline.
Definition sbgl_core.c:629
void sbgl_FillBuffer(sbgl_Context *ctx, sbgl_Buffer buffer, size_t offset, size_t size, uint32_t value)
Fills a region of a GPU buffer with a fixed 32-bit value.
Definition sbgl_core.c:480
void sbgl_DrawIndirect(sbgl_Context *ctx, sbgl_Buffer buffer, size_t offset, uint32_t drawCount)
Submits a batch of draw calls stored in a GPU buffer.
Definition sbgl_core.c:720
sbgl_Telemetry sbgl_GetTelemetry(sbgl_Context *ctx)
Retrieves the performance telemetry data for the previous frame.
Definition sbgl_core.c:436
void sbgl_DestroyShader(sbgl_Context *ctx, sbgl_Shader shader)
Destroys a shader module.
Definition sbgl_core.c:565
sbgl_Shader sbgl_LoadShader(sbgl_Context *ctx, sbgl_ShaderStage stage, const uint32_t *bytecode, size_t size)
Loads a shader from SPIR-V bytecode.
Definition sbgl_core.c:523
void sbgl_PushConstants(sbgl_Context *ctx, size_t size, const void *data)
Updates push constants for the currently bound pipeline.
Definition sbgl_core.c:733
void sbgl_BindComputePipeline(sbgl_Context *ctx, sbgl_ComputePipeline pipeline)
Binds a compute pipeline for subsequent dispatch calls.
Definition sbgl_core.c:649
void sbgl_EndCompute(sbgl_Context *ctx)
Finalizes the compute phase.
Definition sbgl_core.c:385
void sbgl_DestroyBuffer(sbgl_Context *ctx, sbgl_Buffer buffer)
Destroys a GPU buffer.
Definition sbgl_core.c:457
void sbgl_BeginCompute(sbgl_Context *ctx)
Prepares the engine for compute operations before the main drawing pass.
Definition sbgl_core.c:344
sbgl_ComputePipeline sbgl_CreateComputePipeline(sbgl_Context *ctx, sbgl_Shader shader)
Creates a compute pipeline.
Definition sbgl_core.c:619
void * sbgl_MapBuffer(sbgl_Context *ctx, sbgl_Buffer buffer)
Maps a GPU buffer into the CPU's address space.
Definition sbgl_core.c:497
void sbgl_MemoryBarrier(sbgl_Context *ctx, sbgl_BarrierType type)
Injects a memory barrier to synchronize compute and graphics operations.
Definition sbgl_core.c:665
void sbgl_UnmapBuffer(sbgl_Context *ctx, sbgl_Buffer buffer)
Unmaps a previously mapped GPU buffer.
Definition sbgl_core.c:511
void sbgl_DeviceWaitIdle(sbgl_Context *ctx)
Synchronizes the CPU with the GPU, waiting for all commands to complete.
Definition sbgl_core.c:391
uint32_t sbgl_GetFrameIndex(sbgl_Context *ctx)
Retrieves the current frame index for double/triple buffering.
Definition sbgl_core.c:489
double sbgl_GetTime(sbgl_Context *ctx)
Retrieves the current monotonic system time in seconds.
Definition sbgl_core.c:245
uint64_t sbgl_GetBufferDeviceAddress(sbgl_Context *ctx, sbgl_Buffer buffer)
Retrieves the 64-bit GPU virtual address for a buffer.
Definition sbgl_core.c:689
sbgl_Buffer sbgl_CreateBuffer(sbgl_Context *ctx, sbgl_BufferUsage usage, size_t size, const void *data)
Creates a GPU buffer.
Definition sbgl_core.c:445
void sbgl_DispatchCompute(sbgl_Context *ctx, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ)
Dispatches a compute workload.
Definition sbgl_core.c:657
Internal helpers for accessing context state from library subsystems.
SblArena * sbgl_GetContextArena(sbgl_Context *ctx)
Retrieves the persistent arena associated with a context.
Definition sbgl_core.c:62
static sbgl_Vec4 sbgl_Vec4Set(float x, float y, float z, float w)
Creates a Vec4.
Definition sbgl_math.h:98
void VoxelPool_UpdateFrame(VoxelPool *pool, uint64_t frame)
Advances the pool's internal frame counter for LRU tracking.
Definition sbgl_pool.c:78
VoxelPool * VoxelPool_Init(SblArena *arena, uint32_t capacity)
Initializes a VoxelPool on the provided arena.
Definition sbgl_pool.c:10
int32_t VoxelPool_AcquireSlot(VoxelPool *pool, sbgl_ivec3 pos, bool *is_new)
Acquires a slot for a given chunk position. Returns the slot index (0 to capacity-1)....
Definition sbgl_pool.c:25
@ SBGL_BUFFER_USAGE_INDIRECT
Definition sbgl_types.h:126
@ SBGL_BUFFER_USAGE_TRANSFER_DST
Definition sbgl_types.h:127
@ SBGL_BUFFER_USAGE_STORAGE
Definition sbgl_types.h:125
@ SBGL_BARRIER_COMPUTE_TO_INDIRECT
Definition sbgl_types.h:144
@ SBGL_BARRIER_COMPUTE_TO_COMPUTE
Definition sbgl_types.h:143
@ SBGL_BARRIER_HOST_TO_GRAPHICS
Definition sbgl_types.h:148
@ SBGL_BARRIER_HOST_TO_COMPUTE
Definition sbgl_types.h:147
@ SBGL_BARRIER_COMPUTE_TO_GRAPHICS
Definition sbgl_types.h:145
uint32_t sbgl_Buffer
Handle for a GPU-side buffer.
Definition sbgl_types.h:37
uint32_t sbgl_Shader
Handle for a shader module.
Definition sbgl_types.h:42
@ SBGL_SHADER_STAGE_COMPUTE
Definition sbgl_types.h:136
uint32_t sbgl_ComputePipeline
Handle for a compute pipeline.
Definition sbgl_types.h:52
#define SBGL_INVALID_HANDLE
Definition sbgl_types.h:8
uint64_t sbgl_Voxel_GetInstanceAddress(sbgl_VoxelSystem *sys)
Returns the device address of the instance buffer.
Definition sbgl_voxel.c:563
void sbgl_Voxel_Cull(sbgl_VoxelSystem *sys, sbgl_Mat4 view_proj)
Performs GPU-driven frustum culling on voxel chunks. MUST be called BEFORE sbgl_BeginDrawing.
Definition sbgl_voxel.c:436
uint64_t sbgl_Voxel_GetPaletteAddress(sbgl_VoxelSystem *sys)
Returns the device address of the material palette buffer.
Definition sbgl_voxel.c:568
uint64_t sbgl_Voxel_GetAABBAddress(sbgl_VoxelSystem *sys)
Returns the device address of the AABB buffer.
Definition sbgl_voxel.c:558
void sbgl_Voxel_Update(sbgl_VoxelSystem *sys, sbgl_Vec3 camera_pos)
Updates the voxel system state based on the current camera position. This function handles chunk gene...
Definition sbgl_voxel.c:286
void sbgl_Voxel_Render(sbgl_VoxelSystem *sys)
Issues the indirect draw calls for visible voxel chunks. MUST be called BETWEEN sbgl_BeginDrawing and...
Definition sbgl_voxel.c:487
#define SBGL_VOXEL_CHUNK_SIZE
World-space size of a single voxel chunk in meters.
Definition sbgl_voxel.c:19
void sbgl_Voxel_Destroy(sbgl_VoxelSystem *sys)
Destroys the voxel system and releases all associated resources.
Definition sbgl_voxel.c:525
sbgl_VoxelSystem * sbgl_Voxel_Create(sbgl_Context *ctx, const sbgl_VoxelConfig *config)
Creates and initializes a new voxel system. This operation allocates GPU resources and internal track...
Definition sbgl_voxel.c:143
Public API for the SBgl voxel rendering system.
Arena allocator implementation.
#define SBL_ARENA_PUSH_ARRAY_ZERO(arena, type, count)
Definition sbl_arena.h:23
#define SBL_ARENA_PUSH_STRUCT_ZERO(arena, type)
Definition sbl_arena.h:20
SBL_ARENA_DEF void sbl_arena_free(SblArena *arena)
SBL_ARENA_DEF bool sbl_arena_init(SblArena *arena, uint64_t initial_size)
Arena allocator.
Definition sbl_arena.h:47
VoxelPool manages a fixed number of slots for voxel chunks. It uses a flat array layout to maintain c...
Definition sbgl_pool.h:20
uint64_t * last_used_frames
Definition sbgl_pool.h:22
uint32_t capacity
Definition sbgl_pool.h:24
sbgl_ivec3 * positions
Definition sbgl_pool.h:21
uint64_t current_frame
Definition sbgl_pool.h:25
uint8_t * active
Definition sbgl_pool.h:23
Axis-Aligned Bounding Box (AABB).
Definition sbgl_camera.h:56
sbgl_Vec3 max
Definition sbgl_camera.h:58
sbgl_Vec3 min
Definition sbgl_camera.h:57
sbgl_Vec4 max
Definition sbgl_voxel.c:26
sbgl_Vec4 min
Definition sbgl_voxel.c:25
Engine context.
Definition sbgl_types.h:268
Push constants for the frustum culling and indirect draw compute shader.
Definition sbgl_voxel.c:54
Push constants for the voxel generation compute shader.
Definition sbgl_voxel.c:32
Standard Vulkan Indirect Draw command layout.
Definition sbgl_types.h:111
4x4 Matrix, 16-byte aligned, column-major.
Definition sbgl_math.h:83
float roughness
Definition sbgl_voxel.h:42
float metalness
Definition sbgl_voxel.h:43
sbgl_Vec4 color
Definition sbgl_voxel.h:41
Push constants for the shell extraction compute shader.
Definition sbgl_voxel.c:43
float gpu_render_time
Definition sbgl_types.h:178
Configuration parameters for initializing the voxel system.
Definition sbgl_voxel.h:21
bool enable_telemetry
Enables console output for performance metrics and visible chunk counts.
Definition sbgl_voxel.h:37
uint32_t max_slots
Maximum number of chunk slots to manage in the GPU-side pool. This value determines the total memory ...
Definition sbgl_voxel.h:26
uint32_t chunk_radius
Radius (in chunks) around the camera that should be maintained. Chunks outside this radius are candid...
Definition sbgl_voxel.h:32
Internal state for the voxel system. This structure adheres to Data-Oriented Design principles by mai...
Definition sbgl_voxel.c:70
sbgl_Buffer materialPaletteBuf
GPU buffer storing the material palette attributes.
Definition sbgl_voxel.c:102
sbgl_AABB * cpuAABB
CPU-side mirror of AABB data to avoid mapping the previous frame's GPU buffer.
Definition sbgl_voxel.c:108
sbgl_ComputePipeline shellPipe
Compute pipeline for shell/boundary processing.
Definition sbgl_voxel.c:90
sbgl_Vec3 camera_pos
Current world-space position of the camera.
Definition sbgl_voxel.c:125
sbgl_Buffer shellCountsBuf
GPU storage for shell/active instance counts.
Definition sbgl_voxel.c:119
sbgl_Buffer maskBuf
GPU buffer storing the presence mask for all active chunks.
Definition sbgl_voxel.c:96
uint32_t chunk_radius
Radius (in chunks) for visibility and generation logic.
Definition sbgl_voxel.c:81
uint32_t frame_idx
Monotonically increasing index for double-buffer rotation.
Definition sbgl_voxel.c:128
SblArena poolArena
Arena for the CPU-side management pool for chunk slots.
Definition sbgl_voxel.c:75
sbgl_ivec3 last_cam_chunk
World-space chunk coordinates of the camera in the previous frame.
Definition sbgl_voxel.c:122
sbgl_Context * ctx
Pointer to the active engine context.
Definition sbgl_voxel.c:72
double last_update_time
Time of the previous update for delta calculation.
Definition sbgl_voxel.c:140
sbgl_Buffer indirectCmdBuf[2]
Double-buffered GPU storage for indirect draw commands. Double buffering prevents CPU-GPU synchroniza...
Definition sbgl_voxel.c:114
sbgl_Buffer aabbBuf[2]
GPU buffer storing Axis-Aligned Bounding Boxes for culling. Double-buffered.
Definition sbgl_voxel.c:105
sbgl_Buffer instBuf
GPU buffer containing per-instance data for visible chunks.
Definition sbgl_voxel.c:99
sbgl_ComputePipeline genPipe
Compute pipeline for initial chunk generation.
Definition sbgl_voxel.c:87
sbgl_ComputePipeline cullPipe
Compute pipeline for frustum culling and indirect command generation.
Definition sbgl_voxel.c:93
float telemetry_timer
Timer for periodic telemetry reporting.
Definition sbgl_voxel.c:134
VoxelPool * pool
Pointer to the CPU-side management pool for chunk slots.
Definition sbgl_voxel.c:78
uint64_t total_frames
Total number of frames processed for LRU tracking.
Definition sbgl_voxel.c:131
bool enable_telemetry
Enables console output for performance metrics.
Definition sbgl_voxel.c:84
uint32_t fps_frames
Frame counter for FPS calculation.
Definition sbgl_voxel.c:137
3D integer vector for chunk coordinates.
Definition sbgl_pool.h:12
int32_t x
Definition sbgl_pool.h:13
int32_t y
Definition sbgl_pool.h:13
int32_t z
Definition sbgl_pool.h:13
3D Vector, 16-byte aligned and padded for SIMD safety.
Definition sbgl_math.h:49
float y
Definition sbgl_math.h:52
float z
Definition sbgl_math.h:52
float x
Definition sbgl_math.h:52
4D Vector, 16-byte aligned.
Definition sbgl_math.h:61