-
Notifications
You must be signed in to change notification settings - Fork 61
Proposal to solve the overreaching hardware support issue #1650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Just doing a quick answer because I'm very busy today and tomorrow, so I'll read it more in details and respond more deeply (and likely ask questions 😃️) later. But I thik the global idea goes the right way because yes I want experts to lead their areas and contributors being more autonomous on their own topic. Also for tackling a huge work like doing a Vulkan renderer, we should aim for the faster development rythme possible or this will never succeed. Fortunately having a stable OpenGL renderer means we can be very much relaxed on something like that. So it looks like it's the right time and right landscape to consider such effort. |
Although the renderer DLL thing was done both in our own codebase's history (scars remain in I'm not sure how a separate release cycle would work given the need for an agreed-upon ABI. The client and all rendering DLLs would have to be updated simultaneously on any rendering ABI change. Anyway, supposing we surmount the challenges of the ABI and managing large bodies of code that needs to be shared between the implementations.... DLLs suck. If we we're going to build the renderer as a separate unit, let's go all the way and make it a separate process. DLLs give you all of the drawbacks and none of the benefits of running in a separate process: memory leaks, memory corruption, and crashes still affect the main thread, but you nonetheless have to redo the plumbing for all facilities like cvars, logging, filesystem, etc. The only good side is being easier to check in a debugger. Due to the interfaces designed for r_smp, we already have an architecture that is suitable for running the renderer in a separate process: all the instructions are written to a big command buffer that can be executed later. All the The one thing I don't understand how to do is having the rendering be in a separate process while having the window managed by the main process. But I think browsers do this, with different tabs running and rendering from separate processes, so it must be possible. |
DLLs are being proposed because a Vulkan renderer would have a brand new and vastly different architecture. Instead of doing IPC, I'd go to the other extreme and just use |
Those would be releases that don't require compatibility-breaking changes.
That sounds way worse.
Hiding memory issues behind process separation is not the solution to them. I also don't get how it's supposed to help with crashes, since at that point the renderer wouldn't be running anymore anyway.
Same as with IPC? Except that the IPC implementation is much worse to work with with all of the templated stuff.
That is, in fact, a huge advantage.
As was noted earlier by enneract, the architecture would be entirely different. I don't really get why the FooCmd->ExecuteSelf() stuff would be relevant, it's quite likely such commands wouldn't exist at all in the Vulkan renderer.
I like this idea. It's more similar to the proposed option 1 if I understood correctly, which wouldn't have the drawbacks of extra maintenance for interfaces. Having a separate repository is something I'd still want, just to avoid flooding this repo. |
Why not? Works great for gamelogic. Since the proposal is to allow renderer releases without any testing, code review, or other validation, it would be nice to have some fault isolation for that module. A renderer crash would be treated the same as a cgame crash now: drop to the main menu and restart cgame/renderer.
You're right, that suggestion did not make sense. We already have a renderer IPC interface: the cgame->client
Not sure what you mean here. In either case I assume the normal programmer interfaces like
I don't like the idea that selecting the rendering backend selects a different client as a whole. It would be weird that some non-rendering-related features can appear or disappear based on the renderer settings. Instead of having a renderer-specific release cycle, why not have separate testing and stable channels, selectable in the updater, for Daemon as a whole? (This has been proposed before.) Then everyone could benefit from faster testing of new features, not only renderer devs. And just make the experimental renderer part of the normal binary. It could work like this: there is a vtable/function table defining the interface for the client to call the renderer, probably consisting of R_Init, R_Shutdown, and all the trap_R_xxx functions. The default renderer fills the table with all the functions we have now. The experimental renderer functions can live in a submodule repository. But the submodule code would be linked into the main binary the same as any other object files. Then there would be no need for special cvar/logging interfaces and the experimental code could freely choose to reuse any functions from the standard renderer or not without any need to formally decide on a shared body of code. Assuming we got nightly builds going, pushing an experimental renderer update just means bumping the submodule. |
I just kindly remind that I am the one whose response is expected from. So until I get time to properly respond (I hope starting with Friday), most of this discussion is just wasting people's time and attention. |
So, I read all the first post! I finally got not time on last Friday, now the deadlines I had are behind me. So I have more time for this discussion. I have not yet read the answers you got from others, so I'm only answering to your first post for now. I will read the rest later. I hope to have not forgotten anything. As a start, I want to say I like the idea of a vulkan renderer a lot, especially because not only I like to see the engine getting new techniques as at heart (in fact the Dæmon-name was already the name of the effort to modernize the engine for Trem-derivated games, and it dates from way before the TremZ story and the OpenWolf episode (example in 2009](https://web.archive.org/web/20090822020349/http://unvanquished.net/forum/index.php?topic=242.0)). Though, our current OpenGL renderer took years to stabilize, and we also need some stability, so there is some opposing forces between that need of some stability and that desire to push things forward. Also, our OpenGL renderer has now almost reached the level of completeness I want it to have, the last regressions from Quake 3 to take care about to claim having no renderer regression are the dynamic shadows and some Quake 3 specular stuff. Some extra things I would like to see are the linear light blending, the finishing of the PBR code, and some water shader. I hope I forgot nothing, but that's the things we may see being worked on for the OpenGL renderer in the future, and outside of that, it looks pretty “finished”. I believe such Vulkan renderer effort solves many problems because:
Also, I find it wrong if updating the OpenGL renderer makes it only runnable it on devices supporting Vulkan. We better run Vulkan on devices supporting Vulkan than requiring a device that supports Vulkan for running OpenGL. Also the fact we have a stable OpenGL renderer also makes it easier to ship some bleeding-edge work-in-progress Vulkan renderer, because we can redirect the user to the stable OpenGL renderer if something goes wrong with the Vulkan one. The OpenGL renderer is not meant to be dropped soon, first because it works, it is stable (and that's now very precious), and on some systems like macOS that's our current only option anyway (and even not latest macOS). I don't mind if the Vulkan renderer doesn't support some old Vulkan devices, we already have the OpenGL renderer for supporting old devices anyway. Branch-dedicated forgeThe idea of having a separate repository can have some drawbacks but also other benefits and I believe that for such task it is good. For example splitting engine and Unvanquished main repository broughts annoyances related to submodules, but on the other hand offered dedicated issue and pull request list, which is very appreciable. Having a similar mechanism for a specific development on the engine can help, especially when there are two different levels of stability between two components. A rendered being in a submodule would be too painful. The best solution fo the problem may be a branch-dedicated forge, where a git branch would have its own issue and pull requests list and merge rules etc. But GitHub doesn't propose such feature and I even don't know if that exists in any forge software. So the closest we can get to this is like you said, having a speparate repository. It can simply be named Such For convenience, and easy merges between the two branches, we may even keep in sync with a cron task “the other repository's branch” in each repository. So from a repository point of view, one could just create a merge PR to merge the other branch. Renderer selectionI believe that for now, the best is to propduces different engine binaries, selecting the renderer at build time, with some In th future we may think about turning the vulkan renderer as a loadable component later once stabilized, but that's not for today. And also, having the updater unpacking a Project organizationSo with a
Now for:
We at least need to make sure that when merging the Vulkan code from time to time, the OpenGL code remains buildable, working, and stable enough, as I just said. Such merge thread would not be to discuss the Vulkan implementation itself as I said. For the shared part, and if it doesn't break the OpenGL code, I think we better go your way in any case. That's already what I want for your current contributions, as you know what you are doin, and I don't want to slow you down. My condition is that it should not break the OpenGL renderer.
I'm not sure what exactly you need to put in DPK files, but I believe it's fine to do that way. Like for shared code with OpenGL, if a file in a DPK happens to be shared with the OpenGL code, we may have more review on this, but even this I don't really believe it would happen that much and in a way it would break the current OpenGL code. I expect that most in-DPK file shared with OpenGL code and Vulkan would be for experimental, disabled by default OpenGL features anyway, so we could go on the fast merge route for them too. I deeply recommend to put engine in-DPK files in the unvanquished DPK like we already do, to avoid submodule hell. The unvanquished dpk is supposed to provide all the engine needs to start. I remind that at some point, I would like to see som “daemon” dpk to be embedded as a builtin within the engine itself, like we already do with the GLSL files, implementing that may help updating the in-DPK engine files without touching the Unvanquished repository, and would be perfect for such vulkan engine branch: This has been discussed there: Implementing this is not required to havin you starting working on your Vulkan backend, but this could help.
I'm not sure to get everything you meant on that part. For such For the build system, I don't really know what you mean. If you talk about CMake, it would probably a huge waste of time to switch to something else especially if the vulkan flavour would just be the whole I expect the CMake plumbing for the Vulkan flavour to just add some I’ll be happy to help on the CMake code anyway, if that is needed. You would have to clarify your mind more for me to fully answer on such topic. Distribution
The vulkan engine branch repository will be I can help on setting up the docker part for the release build of the Vulkan engine flavour.
Having the updater downloading only one engine would be over-complicated. How the updater works is that it downloads a whole unizip content as torrent and unpacks the engine zip. I would like to keep this with the most minimal changes. But unpacking some Updating the vulkan flavour without requiring to update the base engine is over-complicated. The updater isn't designed for that at all. Having such mechanism was actually discussed for delivering some nightly builds of the engine. Doing a separate vulkan engine update or delivering some nightly engine build in the renderer requires the same very deep work on the updater. So we better implement the nightly-engine download instead. Once we have a way to download a nightly engine, this would also update the engine, whatever the flavour. Such deep updater rework cannot be promised. If implemented by someone, it will be welcome, though: Note that we are now very close to the point of being able to build nightly builds of the engine, but that's not the same as distributing it. So for technical reasons, do not hold your breath waiting for a separate update mechanism for a special engine flavour, but contribution on adding generic nightly engine update is welcome. Also, it would help if we can implement the builtin engine DPK so we only have to implement engine nightly update delivery while allowing us to ship some engine extra in-DPK files.
Yes, I remind what does the updater is to download the universal zip content and unpack the engine zip, so it is the way to do it. We build the Vvulkan client in Docker like other stuff, we ship the vulkan client within the unizip, add some checkbox to the updater to prefer Vulkan, iwhen the checkbox is ticked, the vulkan engine archive is unpacked instead and the vulkan engine is ued instead.
We can delay such topic for later. VersioningWe already have a versionning mechanism where some components can have their own versions. For example texture dpk and map dpk. So That said, having a different versioning for the engine is very troublesome. Actually the engine is the only component for which the version should match the game code version (modulo the 3rd number). So I don't think thats doable for the binary unfortunately. That would be doable for a renderer as a library in a submodule, not for a static binary flavour from a branch and built with some It's fine to add an extra version variable in some So it means you can have a static variable and a cvar for the renderer version, different from the engine, with any number you want (just avoid funny inappropriate things like
For now I see no way to display this unfortunately, neither to implement that easily. For technical reasons, don't hold your breath waiting for that as well. Extra words
Yes, just you described what I want in general, not just for the Vulkan renderer. Though some things are not ready yet, like us not having yet a nightly build update option in the updater, but even that is even not a new idea. I want to insist that:
|
I agree, both should be available.
That sounds good. For shader compilation I'll see if I can also setup something later in the CI to make sure all shader permutations build without errors.
This would be ideal, yeah. I find this future-branch like style of updating between the two to be way better than submodules.
Sure, that is reasonable.
I was thinking of presets, where Vulkan might not have some OpenGL-specific things like
True. I guess this is where the hard requirement to load Unvanquished base pak comes from?
Ah, no, I mean things like pulling https://github.com/KhronosGroup/glslang into external_deps when such USE_DAEMON_VULKAN_RENDERER is defined.
Yeah, I believe it can even be something like:
IIRC that would allow cmake changes to the disabled include without requiring a full rebuild.
Yeah, the docker setup would be hugely appreciated. Repo + binary/zip naming sounds good.
Oh, I see, didn't realise it was downloading the whole thing.
Yeah, nightly-engine + checkmark should work well.
That is the kind of version string in the UI I was thinking of, yes. I guess RML can have a conditional there for if Vulkan is used, and if it is - add the Vulkan version there from such cvar.
That's fine, just the nightly-engine + checkmark would be hugely helpful. |
Is there really some good reason to build two different client binaries? Building a single engine binary and switching renderers with a cvar seems greatly preferable. Separate binaries would force us to write a bunch of extra code in the updater and other release infra. A CMake option to disable the Vulkan renderer would be good of course, to avoid extra dependencies etc., but I see no reason that enabling Vulkan should force one to disable OpenGL. I assume Vulkan would be informed by the GLEW experience and not prevent the application from starting (in OpenGL mode) even if the system lacks minimum Vulkan functionality, CMIIW. We can have a single binary but stuff in a directory or submodule designated for Vulkan-mode-only code would have the special rules of not needing review. I agree that it makes sense to have a special case for skipping review on Vulkan code since it is an infamously verbose API, whose usage no one will be able to meaningfully critique. I'm glad to forego reading 50k lines of VK API mumbo-jumbo. But I oppose anything outside the Vulkan-mode renderer code being exempt from code review. There is no such thing as "safe" changes, or at least not ones reliably identifiable by developers. For example, the UI drawing code for the non-default BP vampire mode sounds like a safe experimental change. But in fact this code also ran in the default mode and could crash the renderer when doing so. Anything that affects users who did not enable Vulkan mode in any way should be subject to code review. (Some RML code with a conditional does fall into this bucket as the RML is still processed, element objects created, etc.) |
Somebody might look at this project as if it had two heads.
Yes, the reasons were outlined already.
Preferable for what? Increased build times and burying it somewhere in settings?
Why would you want to enable OpenGL if you're using Vulkan, wat.
GLEW doesn't have anything Vulkan-related.
User, by some miracle, finds the Vulkan setting -> engine restarts, falls back on OpenGL -> user thinks that it's running Vulkan, even though it's not, attributing any issues to the Vulkan version.
I have doubts that you read the GL spec either.
Which you reviewed and approved.
This was already addressed anyway:
|
This was addressed as well:
|
Where? I haven't seen any discussion of technical reasons for this. Only the organizational one of possibly making it easier to develop in a fork.
There is no imaginable way that having two flavors of client binaries would improve your build times. Building one binary would be at least as fast for any fair comparison between equal sets of features. (A scheme of ifdefs to build exactly one renderer can be equally well used to build any subset of renderers.) Anyway, to go over the advantages of a unified binary:
For switching back and forth while testing. For going back to OpenGL if the Vulkan renderer doesn't work for some map. Any other reason that we switch the material system on or off without exiting the program.
"Informed by the GLEW experience" does not mean "using GLEW". My hope is that a Vulkan-enabled binary can still run fine in OpenGL mode on a system without good Vulkan support. If that's not the case, there would be a technical reason for using separate binaries or DLLs.
Sure. I would pretend to understand the Daemon renderer architecture reasonably well, but not the OpenGL API.
I missed a spot? Darn, guess the whole methodology of code review is invalidated.
We can better ensure that it does not break the OpenGL renderer by giving other contributors the chance to review and test. |
Sections 1 and 3 of the proposal and illwieckz's comment. Also:
Sounds like there aren't many changes required to do that.
It would certainly improve my build times because I'm not insane enough to build both every time.
Just build the binary separately, what's the problem? Besides, why would you even need to rebuild the GL binary given that most of the features in it are pretty set in stone?
Why would you want to switch them in-game? No end-user is gonna bother doing that.
illwieckz seems to be fine with that, so it mustn't be that much of an issue.
Just switch the binaries or run both at the same time?
What exactly do you mean by doesn't work? Crashes or features missing?
Totally different as it cannot run outside of the existing GL renderer in the first place. Also, I don't know of any reason to toggle it during normal use.
Yet that was the only example used. Anyway, you seem to be arguing with something that the project head agrees with and wrote in-depth about, so I'm not sure what the point of such argument is supposed to be. |
So to answer @VReaperV:
That would be nice! I remember there had been discussions for that about OpenGL as well. Note that on Linux CI we can use some Mesa software renderer (llvmpipe for OpenGL and lavapipe for Vulkan) and actually run the graphical client. We have not implemented that yet in CI but this is doable.
We can easily do some And actually setting a cvar not used by the current renderer (or even not defined) would have no effect any way.
Yes. Until we get a way to embed random assets in the engine, assets required by the engine should be stored in
endif()
Indeed.
Let's do this.
Yes that's doable, If I'm right we have a
We do what I said. |
Here are some answers to @slipher:
There are multiple solutions available there, the drawback of the dual-binary solution is the need of extra code in release infra. I'm fine with doing myself that extra effort on the release infra, so I'm OK with that dual-binary solution. For the updater, I guess it's only a matter of concatenating some string to the engine name before starting it. For the docker build, it requires some extra code but I'm very confident with that code as I'm now the author of almost everything in it now. Actually me having added recently the ability to build in docker random engine branches without building the game and actually fetching an game repository that references that engine branch will help testing early “release-like” vulkan engine builds. It's like I already started to write that infrastructure anyway…
That's why I believe the dual-binary is currently the best solution because we have less change to distribute a broken binary if the experimental vulkan code that gets frenetic 50k lines of VK API mumbo-jumbo rewrites isn't even touched by the compiler at build time to begin with. Anyway, we're not gods and we have to start with something, even if not the perfect architecture on paper. Maybe one day we will find it better to do in another way, but the dual binary seems to be the right solution for the today problem. |
I will not discuss more in that thread things that I have already decided for that proposal. Proposals for other architectures can be discussed in dedicated threads that are not this one. Like, if one day we think the Vulkan renderer is mature enough to have the API be a runtime switch, or if we face unsolvable technical problems with the current decided workflow, we would discuss such new proposals in other and new threads. Now further discussions in that thread are about actually implementing the decided workflow. |
So, I created the repository: The branch is I wrote a small script that pulls every night So, we can do pull requests to merge |
Thanks, that is very good. I'll do a pr for the above cmake change to avoid rebuilding both all the time, in a bit (or just push it to the other repo, then we can make use of the script to create the pr automatically - though I'll need to know how to make use of that script). |
All the script is doing is to mirror the branches across repositories. It is just purposed to make it easy to create a pull request to merge So you can start doing work on the vulkan repo, and from time to time we will merge it to master. |
Here is some vulkan toolchain bits: It introduces the That produces a client executable named I added an |
Oh, I see how it works now. |
It is no secret that the continued support for ancient fossilised hardware has caused various issues and stalled progress (see e.g: #1567 and #1587). It also seems that such support in the OpenGL renderer isn't going away anytime soon.
As such, I make the following proposal to project head @illwieckz to resolve this problem in a way that would benefit everyone involved:
1. General
This describes the steps towards the creation of a Vulkan-based Daemon derivative that can be readily swapped with it. There are 2 main ways of structuring it in relation to Daemon that I think would work well:
In either case these would be 2 different repositories, because I want to avoid cmake hell and submodules, plus this would be a very clean solution to having renderer-specific issues, since they would use separate issue trackers and therefore would be easy to keep track of. Also, the main repository then wouldn't be receiving constant changes and a barrage of Vulkan-specific issues burying everything else, which are sure to follow for some time after beginning such a development.
Additionally, I would need to separate out some of the code into the shared renderer part. E. g. splitting the lightmapping shader, so there would be one shared part that would just take API-agnostic input, one GL part to process those inputs from how they're stored with GL, and one Vulkan part to process the inputs from how they'd be stored with Vulkan; that is just an example though, the actual split of shared vs data input would need to be pretty sane to avoid a lot of duplication, plus likely some macros or something for things that are used in the middle of the shader code multiple times.
This also would make it a lot more visible, instead of just burying it somewhere in the settings, where it would be easily overlooked, at least after some initial post announcing it once it's in a working condition.
2. Project organisation
I would have the ultimate authority on how the Vulkan renderer is developed. This includes:
3. Distribution
The Vulkan-based derivative (name pending) would be distributed alongside Daemon in the updater, as a separate binary. This would make it easy to both avoid disk space pollution by using only one or the other, as well as provide the option of using both to those who would like to have a fallback (in which case both can exist in the same directory).
This would also help with getting bug reports from players, which is an important concern I've seen from people who've hosted Tremulous servers for a long time, because there's a pretty high likelihood that if you asked someone, "Which rendering API are you using?" it would be met with a "wtf is that?", whereas "Are you using Daemon or [Vulkan binary]?" is a lot more straightforward.
That is, of course, something that would more so work with option 1 in section 1.
The updater would allow updating it without requiring an update to Unvanquished/Daemon.
The same binary would also be distributed as part of the universal zip.
I don't know what Daemon does for distributing through package systems, like Flatpak, so I don't yet have anything concrete for that.
4. Versioning
The Vulkan renderer would have a separate versioning system from Daemon, and I would have the ultimate authority on said system (this ties in to section 2.3). This version is to be displayed in the updater as well.
Given @illwieckz's words about wanting experts to lead their areas, which according to various people would be me in this case, I believe this would be a very reasonable way to both do some rapid improvements, test them without waiting for a long time for release, while providing a more stable version at the same time, and backport those changes where possible.
The text was updated successfully, but these errors were encountered: