lowenware / dotrix

A 3D engine with ECS and Vulkan renderer for Rust developers
https://dotrix.rs
MIT License
292 stars 11 forks source link

Fix ProjView matrix loading system run level #140

Closed voxelias closed 2 years ago

voxelias commented 2 years ago
QuantumEntangledAndy commented 2 years ago

Is there any reason we don't make this a formal system defintition? I think it would be useful in more than one place as we already need a similar fix to the light binding system. Otherwise if a car with lights moved the lights would be trailing the mesh.

I also use this binding system (that really should be load) for a few of my storage buffers because they are used in multiple shaders. Having a formal pre-render stage would be a good place to put any buffers that need loading after standard updates and before any renders.

voxelias commented 2 years ago

I would keep bind at the place where it is now, adding a new RunLevel for the pre-rendering stage is possible though. Any naming suggestions? Must be a verb. At this moment only load comes to my mind.

QuantumEntangledAndy commented 2 years ago

We could call it pre_render to really make it clear when it is fired. Or maybe prepare as in prepare for render

Xaniaro commented 2 years ago

pre_render sounds best for ne

voxelias commented 2 years ago

IMAO pre_render is missleading. When something is prerendered, it means it is rendered already. While we speak about really a preparation for rendering.

voxelias commented 2 years ago

With the same success we can add a system with high priority at rendering stage BTW

voxelias commented 2 years ago

This sequence gives sense and seems logical for me.

  1. Startup
  2. Bind
  3. Compute / Calculate (Default)
  4. Load
  5. Render
  6. Release

For you don't? Maybe it is worth to rename the Standard RunLevel as well.

QuantumEntangledAndy commented 2 years ago

I think we should try not to worry to much about the name. Let's just go with load. As long as it's well documented.

I think perhaps I could rework the shader example to load the uniform in this stage. That would help make it clear what it's intended for too.

QuantumEntangledAndy commented 2 years ago

I do wonder about putting compute here though. I think compute would imply compute shader. Which you would want to fire after the uniforms and storage buffers are loaded but before render.

QuantumEntangledAndy commented 2 years ago

I feel that compute should be for the compute shader:

Standard: Load and update the world Load: Prepare buffers with worlds last state Compute: Gpu alterations to the buffers, clipping etc render: Using the buffers from cpu or altered by compute to render the scene

QuantumEntangledAndy commented 2 years ago

Alternatively the render stage could be renamed to combine compute as part of it. I was reading aboue metaI and found our that read that the order of compute/render are handled by the device so if a compute shader binds a texure as write and the render as read of the same texture buffer the device should schedule the compute before the render stage (and ensure it finishes)

Xaniaro commented 2 years ago

We can do some research. I personally like standard much more than compute. UE calls that tick. Unity calls that update.

I think it can look somehow like this:

  1. start
  2. ? (calculate delta times)
  3. update
  4. late_update (useful for moving cameras)
  5. before_render (load shaders)
  6. render

I am not sure about load. Another way is the priority. What about to set priority by some customizable enum where you can define execution order?

voxelias commented 2 years ago

Another way is the priority. What about to set priority by some customizable enum where you can define execution order?

There is already the Priority::Custom(u32) that allows to put a system at any place of specific RunLevel.

voxelias commented 2 years ago

Ok, here is the final call:

/// Defines when and how often a system should run.
#[derive(Debug, Eq, PartialEq)]
pub enum RunLevel {
    /// One time execution on application startup
    Startup,
    /// Execution on the beginning of each frame
    Bind,
    /// Execution on every frame for most of the calculations and updates (Default)
    Update,
    /// Execution on every frame to load data to GPU buffers right before rendering
    Load,
    /// Execution on every frame to submit compute passes
    Compute,
    /// Execution on every frame to submit rendering passes
    Render,
    /// Execution everytime after a frame was rendered
    Release,
    /// One-time execution after window resizing
    Resize,
}
QuantumEntangledAndy commented 2 years ago

That looks good for me :)