KhronosGroup / Vulkan-Samples

One stop solution for all Vulkan samples
Apache License 2.0
4.33k stars 645 forks source link

Goal: Dynamic Runtime Samples #458

Closed TomAtkinsonArm closed 1 month ago

TomAtkinsonArm commented 2 years ago

As the project will become more modular over time it makes sense to reintroduce single sample compilation. This was scrapped a while back due to the setup of the framework and build system. This time around we should approach it in a different way to make sure that compilation time stay as fast as possible.

The benefits of this approach is that there is no cyclical dependency between compiling samples, launchers or the framework components. Each sample can be compiled individually with the only other dependency needed to run the sample being the launcher. Launchers can be extremely light weight and can take advantage off code already written and tested in framework modules.

Samples will no longer be classes or be tied to any vkb::Platform lifecycle. They should be able to be composed off any components they deem fit and run in a way which best demonstrates their lessons.

This is purely pseudo code of a sample.cpp file

#include <components/events/events.hpp>
#include <components/windows/window.hpp>
#include <components/assts/models.hpp>
#include <components/input/manager.hpp>
#include <components/sample/defines.hpp>

static std::shared_ptr<SampleContext> sample_context;

sample::Result prepare(sample::Context context) {

   auto default_window =  windows::_default(context);

   input::Manager input;

   input.subscribe(default_window); // < subcribe to input events (cursor pos, key input)

   events::EventBus bus;

   bus.subscribe(context); // < possibly control a samples execution from external sources
   bus.subscribe(default_window); // < subscribe to window events (resize, move, close)

  // Init some vulkan stuff
  sample_context = {};

   bus.on<events::Update>([&](float delta_time){
      // Do some update stuff

     if (input.get_key<input::KeyCode::A>() == input::KeyAction::Down) {
        // move forward?
    }
   });

   bus.on<events::Draw>([&](){
      // ready to draw again
   })

  auto result = bus.run();

   return // do some error handling
}

sample::Result destroy() {
  // clean up code
  // might not be needed if we treat prepare as a main replacement
}

Each sample can choose how to configure its own running environment which allows for super simple samples or more robust samples. The current frameworks can be made into helper libraries which can be used or not. No need to compile the render graph for a hello world sample.

TomAtkinsonArm commented 2 years ago

Hey @gpx1000, this is the end goal that I want a sample to look like.

The build system will be a mix of static, dynamic compile time (components) and dynamic runtime libraries (samples).

A sample may contain 1 or more entry points. We might be able to get away with sample_main() instead of prepare() and destroy().

The event bus will orchestrate all events and the render loop. We might be able to add custom event logic in here too but that is further down the line if a sample needs it. Something like EventBus events{event_intercept_functions};

This set-up should allow samples to be compiled in parallel with zero linking. As this is a major bottleneck this improvement alone should dramatically reduce the build time. Components add to this efficiency by breaking the code base up into smaller libraries with a very specific subset of third parties. I'm hoping to reach build times similar to engines like Godot with sub 10 minutes.

Let me know your thoughts on this when you get chance

gpx1000 commented 2 years ago

I LOVE this idea!

SaschaWillems commented 5 months ago

Do we still want to pursue this idea?