GPUOpen-LibrariesAndSDKs / RenderPipelineShaders

Render Pipeline Shaders SDK
MIT License
312 stars 24 forks source link

Implementing a custom backend #32

Open lasersson opened 1 year ago

lasersson commented 1 year ago

I'm looking for how to go about implementing a custom runtime backend. Is there any documentation available for this? I have been combing through the code and all the relevant interfaces seem to be hidden in private headers and I have not been able to find any obvious way of doing it.

expenses commented 1 year ago

Hi @lasersson, I've managed to implement a custom runtime here: https://github.com/expenses/rust-rps/blob/fcccd3e590ec088207285d89206b326274e1d3bb/callback_runtime.cpp.

I based it heavily off the NullRuntime and NullBackends here: https://github.com/GPUOpen-LibrariesAndSDKs/RenderPipelineShaders/blob/31183408385c1e3e1711bd0320e17fcdf1ee07e9/src/runtime/common/rps_null_runtime_device.cpp and here: https://github.com/GPUOpen-LibrariesAndSDKs/RenderPipelineShaders/blob/31183408385c1e3e1711bd0320e17fcdf1ee07e9/src/runtime/common/rps_null_runtime_device.cpp.

I've written this runtime to essentially just be a C++ wrapper which I pass callback functions written in Rust to. I think the essential functions to implement are

The CallbackRuntime mostly uses the dummy functions from NullRuntime but also registers the backend in BuildDefaultRenderGraphPhases: https://github.com/expenses/rust-rps/blob/fcccd3e590ec088207285d89206b326274e1d3bb/callback_runtime.cpp#L372-L373

and sets up some default nodes in GetBuiltInNodes: https://github.com/expenses/rust-rps/blob/fcccd3e590ec088207285d89206b326274e1d3bb/callback_runtime.cpp#L424-L442

FlorianHerickAMD commented 1 year ago

So far there is no extensive documentation on that. We have been thinking about creating either an overview or a tutorial like this one for the creation of backends. However, this is not a priority in the near future.

Right now, I would recommend familiarizing yourself with the general structure of the existing backends by running one of the slightly more involved samples like e.g. the downsample one and stepping with a debugger through the code.

Once you have a rough idea of the backend structure and are planning to use either Direct3D 12, Vulkan or Direct3D 11 I would recommend one out of two further approaches depending on your requirements.

  1. If you only need some modifications to a few backend parts I'd recommend to create a child backend w.r.t. to the backend of your graphics API overriding those specific parts.
  2. Otherwise, it probably makes more sense to create a new backend from scratch. But even in that case it may make sense to extract something like shared headers.

Out of curiosity, may I ask what your motivation for writing a custom backend is?

lasersson commented 1 year ago

Thanks for sharing @expenses!

Yes, basically what I'm wondering if that is the way to do it: inheriting from rps::RuntimeDevice et al. Since these headers are not exposed with the rest if the api in include/rps I would have to hack around that. Also how stable are you expecting those apis to be. I'd like to get a grasp on the maintenance investment before setting out.

The motivation is to use an api-agnostic HAL to not have to write node callbacks directly against Vulkan for example. This is to enable code sharing between projects. Also support a wider range of platforms. Mac, consoles etc

FlorianHerickAMD commented 1 year ago

Since the SDK is still in beta phase I cannot and will not make any guarantees but I can try to give you some insights.

Generally, I would not expect a radical overhaul of the backend structure or its interfaces. We do still have some ideas for parts of them to be improved but its unclear at the moment when and if these will be implemented. If we do, they would probably break an existing backend set up immediately after the update but I would expect the effort to restore compatibility to be moderate and the frequency of these events occurring to be rare.