Skip to content

Blueprint Generation Overhaul - #9

Draft
Zemogiter wants to merge 8 commits into
InflexCZE:masterfrom
Zemogiter:master
Draft

Blueprint Generation Overhaul#9
Zemogiter wants to merge 8 commits into
InflexCZE:masterfrom
Zemogiter:master

Conversation

@Zemogiter

Copy link
Copy Markdown

This PR adds a option to generate the blueprint using the graphics card rather than the CPU. Depending on the 3D model used, it could be much faster. Render time is displayed under the model size on the right-side display.
While I was at it, I've enchanced a few things:

  • the blueprint generation process is now run on a separate thread, making the program less likey to hang and become irresponsive. A fun side effect is that it is possible to play around with the model displayed on the right side.
  • there's now a loading bar that shows the progress of blueprint generation. During the process, it goes over the generation button. Once it's completed it disapears and the button is back.
  • the process of loading game files should now be faster, especially visible when debugging. It is also excecuted on a separate thread to prevent hangs
  • a general code cleanup, removing unused imports
  • the blueprint generation process can now be cancelled by pressing the Esc button, in case the user decided they wanted to try different settings

Implemented GPU-accelerated mesh voxelization using ILGPU. This means faster blueprint generation.
For instance this huge model https://sketchfab.com/3d-models/kyogre-265b2838b1824ec599274cef63a5b906 is converted to a blueprint in just under 15 seconds (RX 9070XT, all slope settings, 2.5m blocks. model size 638 - not changed by me) vs over 20 via the old method.
 Other features including:
- Progress reporting with cancellable operations (Esc key)
- CPU fallback mode available via Shift+click, the text under the model size informs the user what mode is used.
- Enhanced UI with progress bar and generation status. Jumps in place of the generate button when a blueprint generation is in place, colapses and restores the button once the blueprint is ready.
- Renamed original Generate() to GenerateCpu() for clarity.
- Added thread-safe generation state tracking to prevent concurrent operations
- Minor typo fixes in model size warning messages
Fix the progress bar not showing up on subsequent model conversions.
Precompute triangle edges and normals outside the inner loop to avoid redundant calculations. Add cache-friendly early exit check before atomic operations to prevent unnecessary memory bus locking. Include ILGPU accelerator verification debug output.
Major performance improvements across grid generation and serialization:

- Add GpuSetup static class to cache ILGPU context and kernel globally, eliminating repeated initialization overhead
- Parallelize grid reconstruction and slope evaluation passes instead of sequential iteration
- Track active (filled) blocks to skip empty cells during slope evaluation, reducing loop iterations by orders of magnitude
- Pre-cache reflection types in GameProxy to eliminate repeated FindType() lookups during serialization
- Optimize FileStream creation with proper FileAccess/FileShare flags
- Use dedicated lock object in LoadInputActions to prevent thread contention
- Add stopwatch timing and debug output
- Clean up unused imports and fix namespace references in MainWindow
GridShaper:
Unified the blueprint generation methods, since a substantial amount of the code was identical.
GpuSetup now exposes SyncLock, private-set context/accelerator/kernels and a RebuildContext() to safely reinitialize ILGPU (including InitGridKernel). This should prevent the exceptions when the user generates a blueprint, picks up a different model (without saving the previous one) and tries to generate that one.

GameProxy: made action-file loading resilient — filter for .sbc/.json, fast-skip files without a Guid, null-checks after deserialization, safer reflection when accessing Id, and broader exception handling to avoid runtime binder/serialization crashes. This should make the game file loading faster, especially when debugging.
@InflexCZE

Copy link
Copy Markdown
Owner

Very nice improvements.
Can you please check on the GPU integration, if it's enabled correctly.

My setup: 9700K + RTX3070
Test model: https://www.printables.com/model/57400-oneill-class-ship-from-stargate
Before update: +3minutes blueprint generation
After update: 30s (+/-2s) regardless if I run GPU or CPU (The UI says it used GPU/CPU but the time is barely different).

using System.Linq;
using System.Runtime.CompilerServices;
using ClrDebug;
using ClrDebug;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When contributing to open source projects, it is generally not appreciated to go ahead and reformat whole project. Makes review hard and maintainers unhappy

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about that. Won't touch code cleanup unless it's on the files I modify.

Comment thread Data/GameProxy.cs Outdated
Comment thread Data/GameProxy.cs Outdated
Comment thread Data/GameProxy.cs Outdated
Comment thread Data/GameProxy.cs
var validFiles = Directory.EnumerateFiles(actionsDir)
.Where(f => f.EndsWith(".sbc", StringComparison.OrdinalIgnoreCase) || f.EndsWith(".json", StringComparison.OrdinalIgnoreCase));

Parallel.ForEach(validFiles, file =>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loading is much faster, because this hits 0 files.
SE2 data files are .def.

The Key Binds tab is now broken.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just fired up the latest stable release, it's broken there as well.

Comment thread Data/GameProxy.cs Outdated
Comment thread Algorithms/GridShaper.cs
}

// Class to cache the GPU context and kernels globally
public static class GpuSetup

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the engineering, but pls check the final GPU gains.
I measure ~2s per 1M Blocks (SE2 cant' take any more now anyways).

If that's the case, I'm not sure if the added complexity is really desirable.
The Blueprint generator is very Alpha, needs a lot of improvements, which is hard to do when there are 2 code paths to maintain => Off putting for potential new maintainers.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just pushed a update on the slopes generation, should widen the gap betwen CPU ang GPU.

@Zemogiter

Zemogiter commented Jul 27, 2026

Copy link
Copy Markdown
Author

I've tried your model and my results are as follows (1st was 2.5m GPU, 2nd was 0.5m GPU, 3rd was 2.5 CPU and 4th was 0.5m CPU):

Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'System.DllNotFoundException' in ILGPU.dll

[ILGPU INITIALIZATION] Compiled and Cached on: gfx1201 (Type: OpenCL)

Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=uc'. BindingExpression:Path=SmallChange; DataItem=null; target element is 'SquarePicker' (Name='uc'); target property is 'SmallChange' (type 'Double')
The thread '.NET TP Worker' (11956) has exited with code 0 (0x0).
The thread '.NET TP Worker' (17020) has exited with code 0 (0x0).
The thread '.NET TP Worker' (5996) has exited with code 0 (0x0).
The thread '.NET TP Worker' (16708) has exited with code 0 (0x0).
The thread '.NET TP Worker' (19140) has exited with code 0 (0x0).
The thread '.NET TP Worker' (15804) has exited with code 0 (0x0).
The thread '.NET TP Worker' (19216) has exited with code 0 (0x0).
The thread '.NET TP Worker' (10428) has exited with code 0 (0x0).
The thread '.NET TP Worker' (26028) has exited with code 0 (0x0).
The thread '.NET TP Worker' (27036) has exited with code 0 (0x0).
The thread '.NET TP Worker' (26784) has exited with code 0 (0x0).
The thread '.NET TP Worker' (9880) has exited with code 0 (0x0).
The thread '.NET TP Worker' (17924) has exited with code 0 (0x0).
The thread '.NET TP Worker' (26332) has exited with code 0 (0x0).
The thread '.NET TP Worker' (17752) has exited with code 0 (0x0).
The thread '.NET TP Worker' (8068) has exited with code 0 (0x0).
The thread '.NET TP Worker' (23916) has exited with code 0 (0x0).
The thread '.NET TP Worker' (21192) has exited with code 0 (0x0).

[ILGPU VERIFICATION] Executing on: gfx1201 (Type: OpenCL)

The thread 'ILGPU_25_GCThread' (6712) has exited with code 0 (0x0).
The thread 'ILGPU_24_GCThread' (26608) has exited with code 0 (0x0).
The thread 'ILGPU_1_Frontend_0' (11044) has exited with code 0 (0x0).

[ILGPU INITIALIZATION] Compiled and Cached on: gfx1201 (Type: OpenCL)


[PERFORMANCE] Blueprint generated in 1,074 seconds using GPU.


[ILGPU VERIFICATION] Executing on: gfx1201 (Type: OpenCL)

The thread 'ILGPU_7347_GCThread' (8172) has exited with code 0 (0x0).
The thread 'ILGPU_7346_GCThread' (22064) has exited with code 0 (0x0).
The thread 'ILGPU_7323_Frontend_0' (22004) has exited with code 0 (0x0).

[ILGPU INITIALIZATION] Compiled and Cached on: gfx1201 (Type: OpenCL)

The thread 23180 has exited with code 0 (0x0).
The thread '.NET TP Worker' (3816) has exited with code 0 (0x0).
The thread '.NET TP Worker' (2072) has exited with code 0 (0x0).
The thread '.NET TP Worker' (5008) has exited with code 0 (0x0).
The thread '.NET TP Worker' (15848) has exited with code 0 (0x0).
The thread '.NET TP Worker' (23556) has exited with code 0 (0x0).
The thread '.NET TP Worker' (24024) has exited with code 0 (0x0).
The thread '.NET TP Worker' (4584) has exited with code 0 (0x0).
The thread '.NET TP Worker' (27328) has exited with code 0 (0x0).
The thread '.NET TP Worker' (11144) has exited with code 0 (0x0).
The thread '.NET TP Worker' (25360) has exited with code 0 (0x0).
The thread '.NET TP Worker' (24184) has exited with code 0 (0x0).
The thread '.NET TP Worker' (28012) has exited with code 0 (0x0).
The thread '.NET TP Worker' (21812) has exited with code 0 (0x0).

[PERFORMANCE] Blueprint generated in 23,176 seconds using GPU.

The thread '.NET TP Worker' (28104) has exited with code 0 (0x0).
The thread '.NET TP Worker' (11536) has exited with code 0 (0x0).
The thread '.NET TP Worker' (6600) has exited with code 0 (0x0).
The thread '.NET TP Worker' (16224) has exited with code 0 (0x0).
The thread '.NET TP Worker' (23008) has exited with code 0 (0x0).
The thread '.NET TP Worker' (23684) has exited with code 0 (0x0).

Executing the model to blueprint conversion on the CPU


[PERFORMANCE] Blueprint generated in 1,070 seconds using CPU.


Executing the model to blueprint conversion on the CPU

The thread '.NET TP Worker' (12956) has exited with code 0 (0x0).
The thread '.NET TP Worker' (17920) has exited with code 0 (0x0).
The thread '.NET TP Worker' (21700) has exited with code 0 (0x0).

[PERFORMANCE] Blueprint generated in 29,602 seconds using CPU.

The thread '.NET TP Worker' (22716) has exited with code 0 (0x0).
The thread '.NET TP Worker' (25564) has exited with code 0 (0x0).
The thread '.NET TP Worker' (11488) has exited with code 0 (0x0).
The thread '.NET TP Worker' (11056) has exited with code 0 (0x0).
The thread '.NET TP Worker' (7768) has exited with code 0 (0x0).
The thread '.NET TP Worker' (18536) has exited with code 0 (0x0).
The thread '.NET TP Worker' (6928) has exited with code 0 (0x0).
The thread '.NET TP Worker' (28840) has exited with code 0 (0x0).
The thread '.NET TP Worker' (15904) has exited with code 0 (0x0).
The thread '.NET TP Worker' (14936) has exited with code 0 (0x0).
The thread '.NET TP Worker' (23232) has exited with code 0 (0x0).
The thread '.NET TP Worker' (21988) has exited with code 0 (0x0).

The GPU rendering seems to be the most efficient at 0.5 scale. The problem is, the current implementation is sort of a hybrid approach. I wasnt able to move the phase 3 (slopes, the most complicated one) entirely to GPU. Of course, I will keep trying.

Moves slope generation to GPU execution as part of the voxelization pipeline instead of post-processing on CPU (will still be fully executed on CPU if the mode is enabled via shift key). Adds GpuSlopeParams struct to bypass C# 16-parameter limit for GPU kernels, and includes LOH compaction for memory management after voxelization. Added extra memory checks close to the end to make sure the software wont hog too much RAM.
Also updates GameProxy to filter for .def files instead of .sbc, and removes the GUID pre-check optimization  and unnecessary comments.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants