Implementing a custom backend
lasersson opened this issue · 4 comments
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.
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
CallbackBackend::CreateResources
: https://github.com/expenses/rust-rps/blob/fcccd3e590ec088207285d89206b326274e1d3bb/callback_runtime.cpp#L125-L128
andCallbackBackend::DestroyRuntimeResourceDeferred
: https://github.com/expenses/rust-rps/blob/fcccd3e590ec088207285d89206b326274e1d3bb/callback_runtime.cpp#L116-L118
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
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.
- 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.
- 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?
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
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.