News:

Congratulations!
 You've won the News Item Lottery! Your prize? Reading this news item! :)

Experimental SDL3 / SDL_GPU accelerated renderer — technical preview

Started by victor_18993, August 07, 2026, 12:32:51 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

victor_18993

Experimental SDL3 / SDL_GPU accelerated renderer — technical preview

I have been working on an experimental SDL3 / SDL_GPU rendering backend for Simutrans, and I think the project has now reached a point where it makes sense to share an early technical preview.
This is still research work. I am not proposing to replace the current renderer yet, and this is not an integration request.

The goal of the experiment is quite simple:

Can Simutrans keep its existing 2D rendering semantics while moving the actual rendering work to a modern GPU backend?

So far, the results are encouraging.

The experimental renderer is now running on both Direct3D 12 and Vulkan, and it already handles sprites, text, primitives, GUI rendering, clipping, day/night state changes, player colour/state changes and the basic window lifecycle.

SDL 1.png

One of the main priorities throughout the work has been fidelity before performance.

I did not want to make the renderer faster by subtly changing the way Simutrans draws things.
For the deterministic scenes tested so far, the logical framebuffer generated by the GPU renderer is pixel-identical to the software reference on both D3D12 and Vulkan.

At the same time, the architecture has gradually moved away from the original one-draw-at-a-time experimental implementation.

Sprites now use a shared GPU atlas and batching, text has its own coverage atlas and batching path, and sprites, text and primitives are now coordinated by a unified command scheduler instead of constantly forcing each other to flush.
This has produced a substantial reduction in renderer overhead while keeping the tested output unchanged.

SDL 2.png

The figures above should still be treated as research measurements rather than general Simutrans benchmarks.
The current tests are deliberately controlled, and they are mainly intended to answer architectural and correctness questions.

One useful result from the latest work is that the renderer no longer needs to execute simply because the type of drawing changes from a sprite to text or to a primitive.
The unified scheduler can keep independent work pending and only materialize it when there is a real ordering dependency.

The frame lifecycle has also now been separated from presentation.
The renderer draws the logical frame into its offscreen target first, and the swapchain is acquired only when the frame is ready to be presented. This also allowed several mid-frame state cases and resize/fullscreen lifecycle situations to be tested properly.

For example, day/night transitions, multiple palette transitions and player-colour state changes can now happen during the same frame while preserving the expected output.

There are still important validation steps before I would call this MVP complete.

The current focus is validating something that none of the previous tests directly observed: the final image written to the swapchain.

Until now, the strict pixel comparisons have validated the logical framebuffer. The current test is extending that validation through the final presentation stage:
Simutrans
    ↓
GPU renderer
    ↓
logical framebuffer
    ↓
final presentation
    ↓
swapchain

The intention is to read the actual presented GPU image and compare it byte-for-byte against a CPU reference on both D3D12 and Vulkan.

After that, the next major step is no longer another renderer architecture experiment.
It is to load a representative real Simutrans game and observe what happens under normal gameplay: vehicles, buildings, map rendering, GUI, text, scrolling, state changes and the combination of rendering paths that a real game produces.
SDL 3.png

So at this stage I would describe the project as:
an experimental accelerated 2D renderer approaching MVP validation, rather than a finished replacement renderer.

There are still some less common rendering operations that will require additional coverage before anything could be considered production-ready, and I am deliberately keeping integration discussions separate from the research phase.
The encouraging part is that the work so far has not required changing Simutrans' fundamental 2D rendering semantics or restructuring the game around the new renderer.

The GPU-specific implementation remains isolated from the common rendering code, while the tested D3D12 and Vulkan paths continue to produce the same results.

Once the final presentation validation and the representative real-game test are complete, I will post the results here as well.

Feedback is very welcome, especially if there are unusual rendering situations, GUI combinations or game scenarios that you think would be useful to include in the final validation.
En la vida todo son vivencias y cada una de ellas nos hace mas grandes,¿Como de grande eres tu? :)

victor_18993

Small SDL3 / SDL_GPU development update.

I have now made the demonstration repository available publicly so anyone interested can inspect, build and test the current SDL3 work directly.

Public demo repository:
Dkijas/SDL3_SIMUTRAS_2.5D

The repository contains the experimental SDL3 platform backend together with the SDL_GPU renderer, including:

- existing software renderer through SDL3
- SDL_GPU renderer
- Vulkan backend
- Direct3D 12 backend
- build and test instructions
- launcher scripts
- the validated tutorial savegame
- architecture, testing and known-limitations notes

The published demo was validated from a fresh clone, with the automated suite passing on both SDL2 and SDL3 builds.

Please note that this is still an experimental demonstration, not an official Simutrans release and not an upstream-ready patch. Its purpose is to make the work reproducible and allow other developers or interested users to inspect the implementation and test it independently.

Development has continued beyond this public demo. The more recent GPU3 research cuts are still being hardened, particularly around deterministic multi-page atlas execution, D3D12 performance and the experimental visual rendering path. I prefer to keep those changes under validation before publishing them as another review point.

Feedback from anyone who builds or tests the demo is very welcome.
En la vida todo son vivencias y cada una de ellas nos hace mas grandes,¿Como de grande eres tu? :)

prissi

How much faster per frame is the GPU rendering? You have only compared Direct3D and Vulkan

victor_18993

Quote from: prissi on August 21, 2026, 07:37:53 PMHow much faster per frame is the GPU rendering? You have only compared Direct3D and Vulkan
In the current research version, it is actually not faster than the software renderer yet.
On the latest CUT-06 measurements, using the same L9 test workload:
  • software renderer: ~12 ms/frame
  • SDL_GPU Vulkan EXACT: ~58 ms/frame
  • SDL_GPU D3D12 EXACT: ~97 ms/frame
So at this stage the software renderer is still clearly faster.
The important result from the profiling is that the GPU itself is not the bottleneck. The remaining cost is almost entirely on the CPU side: command recording, atlas/run/pass construction and backend submission overhead. Vulkan is already considerably better than D3D12 here; D3D12 still has a relatively expensive per-pass cost.
Therefore I would not claim a performance advantage for SDL_GPU yet. The current work has been focused first on getting the GPU path deterministic and pixel-correct against the software renderer. The next cuts are intended to remove the remaining CPU-side overhead, after the multi-page atlas ordering issue is fixed.
I should have included the software baseline in the previous comparison — comparing only Vulkan and D3D12 was incomplete.
En la vida todo son vivencias y cada una de ellas nos hace mas grandes,¿Como de grande eres tu? :)

victor_18993

Small update on the SDL3/GPU renderer work.

The performance investigation is now giving us a much clearer picture of where the time is actually going.

In the current renderer, the main steady-state cost is not coming from atlas size, uploads or submission count. A large part of the overhead comes from the way exact rendering currently records many render passes and destination copies on the CPU.
D3D12 also has an additional issue once sampler descriptor usage crosses a specific threshold.

The first optimization work is already showing very encouraging results on cold frames. In one of the heavier test cases, Vulkan dropped from about 523 ms to 124 ms, while D3D12 dropped from about 588 ms to 193 ms.

We also corrected one earlier assumption during the investigation. The expensive first-use path is not caused by sprite data being copied back from the GPU. The actual problem is the synchronization model: newly uploaded sprites were creating a large number of separate transfer operations, submissions and blocking fence waits for a very small amount of data. Those uploads are now being batched much more efficiently.

Exact rendering is still matching the software reference in the tests completed so far, including multi-page atlas cases and different producer counts. We are continuing the longer validation campaign now to make sure the optimizations do not introduce regressions in warm rendering, clipping or general behaviour.

The next work will focus on the remaining D3D12 descriptor overhead and then on reducing the large number of destination-read passes required by exact rendering.

Once these optimizations are ready and the full correctness/regression checks are complete, we will try to release DEMO 4 as soon as possible so people can test the improved renderer directly.

There is still no production integration from this work yet; everything remains isolated while the renderer is being optimized and validated.
En la vida todo son vivencias y cada una de ellas nos hace mas grandes,¿Como de grande eres tu? :)