Closed emberian closed 6 years ago
I am unsure the precise requirements here but I plan on looking into it further and doing a full report here.
This would be great, and very much in scope for gfx-rs. :+1:
I've started reviewing PRs for D3D compatability.
I basically think this is impossible with any sane non-runtime-switchable interface, see https://github.com/rust-lang/rfcs/pull/195#issuecomment-53127823. I'm going to close this for now, though it is sad...
sadface
Maybe we need a status tag for "blocked on rust-lang/rust
"
I'm not sure it will ever be possible.
Although, it's conceivable that we could have a SwitchableDevice
trait that returns trait objects instead of any concrete type, in addition to just Device
.
I remember the game engines in the latter half of the 90's. You had Direct3D and OpenGL and even software rasterizers, and you could actually see the difference between the API's. E.g. software rasterizers would render these blocky textures, since bilinear filtering would take too much CPU, and a lot of the time vendor implementations of OpenGL vs Direct3D would differ such that for example some 3D accelerators had artefacts in OpenGL, but not in Direct3D, or things like glass materials didn't look like glass in Direct3D because it didn't support something and you could change the rasterizer in the settings. I haven't seen an engine that allows the user to change the rasterizer for over a decade now. I figure it's because things like the aforementioned artifacts are all but gone now, so I'm wondering: what would be the use in having gfx support switching rendering apis at runtime?
@eugene2k Unity supports it, for example. Though of course not at runtime. I originally opened this issue as a, "can we do this?". I am not any more sure that it's valuable as I was when I opened it :) One thing that might be nice is shipping a single binary for all the various APIs, which could be quite useful - Vulkan where it's supported, OpenGL or DX11 where it's not.
What is clearly out of scope is changing the backend of a currently-running renderer - you'll definitely need to tear it down and build it back up with the new API in place. I'm not sure whether and to what extent windowing APIs support reusing windows in this way (the biggest concern really being Windows, which is where multiple APIs are usually present, though in the future I guess it will be OpenGL vs Vulkan on Linux, or OpenGL vs Metal on OS X/iOS).
Hmm... I didn't think about api switching in that context, but it should be possible without runtime switching, shouldn't it? Theoretially all you need is to create two (or more) renderers instead of one, place them into separate dlls, and choose between them at runtime, before initialization.
Yes, that's a fine theory, but that's not how it works out in Rust, especially how we use generics. You need to have everything going through the same ABI or otherwise via trait objects, which looks exactly the same as runtime switching.
If I may offer my use case and experience, we desperately need this feature:
One thing that might be nice is shipping a single binary for all the various APIs, which could be quite useful - Vulkan where it's supported, OpenGL or DX11 where it's not.
We are trying to reimplement our visualization front-end for long-running distributed computing applications and our end-users are generally non-programmers or at least not keen enough to configure and build the application such that it fits their specific machine. We definitely need the ability to select the particular implementation we'd like to use at runtime. Being able to switch that backend at runtime would be nice but being able to deploy a single binary for each platform and allow the end user to specify rendering backends via config file is a serious must.
Also, if anyone at all has any examples of an application that provides multiple, selectable backends that does not use the gfx_app
package, I would really love to see some sample source.
@dkushner it all comes down to narrowing down the part of the program that knows about different backends. E.g. it may just be your main()
function doing:
match config.graphics_backend {
Backend::OpenGL3 => {
gfx_window_glutin::init(...);
gfx_device_gl::init(...);
run(window, device, factory);
},
Backend::Direct3D11 => {
gfx_window_dxgi::init(...);
gfx_device_dx11::init(...);
run(window, device, factory);
},
}
Another (simpler) solution is to use config flags, like Amethyst does. It used to have enums for some of the types, where enumeration values are basically backend versions of the same concepts (GL Device, D3D11 Device, etc), but this approach turned out to be pretty verbose.
I did a PoC for an additional backend some time ago, which would handle runtime dispatching. https://github.com/msiglreith/gfx-frontend/blob/master/src/lib.rs An application would then only interface this backend or it could be, additionally, coupled with compile time switching as done in Amethyst.
@kvark, oh yeah I'm up to here at least, my issue is mostly the fact that I need a service like RenderManager
to be in charge of creating GPU-bound resources at any arbitrary time over the lifetime of the application. For this reason, RenderManager
needs to hold a reference to the Factory
and Device
but these traits cannot be trait objects, so I'm thinking the absolute only way to accomplish this is to similarly type paramaterize the RenderManager
implementation? Is my thinking correct?
Basically, it's like your example but instead of passing the device and factory off to a run()
I need to store it in a struct.
With LL transition we are getting more traits and associated types. We are full on the generic backend API, and providing run-time switching is escaping the scope. If that's badly needed, there are 2 ways to achieve it that I can think of:
enum
at the type level like @msiglreith proposed. This is rather tedious, and I believe should be explored from the point of view of procedural macros or compiler plugins, generating all the boilerplate automatically.On this note, I believe the issue can be closed.
In particular, switching between OpenGL, DirectX, and whatever other APIs may be supported by gfx-rs (Mantle, Metal, ...) in the future.