u/EchoXTech_N3TW0RTH

SimpleX Engine Development (Continued)

SimpleX Engine Development (Continued)

I originally had a string of posts with various other reddit communities regarding game and game engine development and finally felt confident enough to post to this community! I went dark in my development logging/blogging(?) for awhile due to lifestyle responsibilities taking precedance over developing an engine or at least at the moment what is considered heavy boilerplate engine development.

Current development components/systems:

Three graphics backends - DirectX 11, DirectX 12, and OpenGL (WGL on Windows, GLX on Linux) behind an IRenderer interface. Vulkan is scaffolded but not implemented yet. Shadow maps, cubemaps, bloom, IBL/irradiance convolution, and instancing are supported at the moment.

HLSL as single source of truth compiling offline via DXC to DXBX/DXIL/SIPR-V with SIPRV-Cross transpiling to GLSL for the GL backend. Compiled byte code is also cached on disk and keyed by source hash as filename.

Three windowing backends - Win32, GLFW, and SDL3, with a fallback chain. Win32 is default for Windows and GLFW is default for Linux, but will fallback to GLFW and if GLFW fails fallback to SDL3; if DX fails on any window type under Windows platform fallback to OpenGL (if Vulkan would work with me DX would fallback to Vulkan then back to OpenGL) - similar results would also occur for Linux if Vulkan failed fallback to OpenGL but that requires Vulkan to be developed and not be a stub at the moment...

HLSL as a single truth - compiled offline via DXC to DXBC/DXIL/SPIR-V, with SPIRV-Cross transpiling to GLSL for the GL backend. Compiled bytecode is cached on disk keyed by source hash as well.

Fiber-based Job System - Win32 fibers and Linux ucontext behind one class - a worker thread has a dedicated dispatcher fiber that never runs job code, so fibers are pooled to switch back rather than to each other - no fiber needs to know any other fiber's state.

I went with no cross-thread fiber migration in my first attempt - less load-balancing from the inspirational full Naughty Dog design, but it buys a genuinely nice property: since a job's whole execution stays pinned to one thread, a pool allocator allocates inside a job function automatically thread-safe with zero sync.

Custom allocators - arena, pool, and a frame allocator with N rotating arenas.

BC texture compression with no on-disk cache - BC1 for opaque color, BC3 for color with alpha, and BC5 for normal maps.

TLDR; I've tested the boilerplate logic against the Sponza Palace model from Intel's site GPU Research Samples (https://www.intel.com/content/www/us/en/developer/topic-technology/graphics-research/samples.html) with the Colorful Curtains and Ivy extensions at 4K texture resolutions. The original load time took around 5.5 minutes (unbearable to test shader changes and object additions to the scene), but I cut it down to 4.6 seconds after texture compression, precompiled shader code, and submesh merging. The model (as an *.obj - I haven't implemented third-party vendor model software to utilize every model type just yet...) is 995MB on disk with nearly 2730MB of textures (4K per texture for the conjoining material *.mtl file) after texture compression all textures were compressed to 501MB on disk which originally took 933ms average to load cutting down to 259ms average.

intel.com
u/EchoXTech_N3TW0RTH — 2 days ago