godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.86k stars 21.14k forks source link

Compile shaders when a scene is loaded #13954

Closed endragor closed 3 years ago

endragor commented 6 years ago

Operating system or device, Godot version, GPU Model and driver (if graphics related): Godot af27414b1c10173584539186e396668a899e06b2, any OS

Issue description:

Currently shaders are compiled lazily - whenever a shader needs to be invoked, glCompileShader is called. This results in noticeable freezes in-game when some object is rendered for the first time. Behaviour that would make more sense is to compile the shader when a scene depending on it is loaded.

Zylann commented 6 years ago

Or more precisely, maybe compile the shader when its resource is loaded, which is actually what would be expected? It allows to load them on loading screen / in background without needing a scene, and if they are embedded in the scene it would still work as expected

reduz commented 6 years ago

You don't know what to compile until you render it. Also even with that, OpenGL driver can do a lazy compilation anyway. The solution for this is shader caching, which will need to be implemented in 3.1

On Mon, Dec 4, 2017 at 8:24 AM, Marc notifications@github.com wrote:

Or more precisely, maybe compile the shader when its resource is loaded, which is actually what would be expected?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/godotengine/godot/issues/13954#issuecomment-348934476, or mute the thread https://github.com/notifications/unsubscribe-auth/AF-Z291pfd4DG8ImBb_4sqyUwzKqsJwEks5s89ZSgaJpZM4Q0bDZ .

bruvzg commented 6 years ago

Is there any way to cache compiled shaders besides glGetProgramBinary? It is supported only in OpenGL 4.1+/GLES 3.0+, and Godot targets GL 3.3 on desktop platforms.

fracteed commented 6 years ago

Ah, so this is why I have been getting all the pauses at the start of my game! Always noticed this when bullets, bonuses, explosions are being spawned the first time. Thought it was the particle systems, but it must be the shaders being compiled...makes sense now :)

To avoid this, does the shader have to be seen on an object to compile or can I put them on meshes or particles that are behind other objects out of sight?

Calinou commented 6 years ago

It is supported only in OpenGL 4.1+/GLES 3.0+, and Godot targets GL 3.3 on desktop platforms.

From what I've heard, Godot 3.0 doesn't run on GeForce 8/9 GPUs anyway (which support OpenGL 3.3 at most). I've heard conflicting reports about Radeon HD 6000 GPUs (which support up to OpenGL 4.2, IIRC, which is enough for that feature). As for Intel graphics, you need an Haswell IGP at least (older generations are too slow to be useful for modern gaming anyway).

So, we may not need to bother about keeping OpenGL 3.3 compatibility, unless you want to keep compatibility with software fallbacks (see Mesa matrix), which are extremely slow anyway – their only use is for vendor-independent OpenGL testing.

Zireael07 commented 6 years ago

Bump, any hope of getting this in 3.1?

LinuxUserGD commented 6 years ago

I've noticed that loading animations in the ResourceInteractiveLoader (background loading) freeze if the scene contains 3d objects with lots of materials. Currently I spawn all objects at loading time and call remove_child to keep them in memory.

eon-s commented 6 years ago

Probably related to #17263 (but particles even freeze the game with no materials!).

I hope this gets in 3.1 because it makes mobile games unplayable.

ProbDenis commented 6 years ago

Yeah, it's really a problem. I tried to display all important materials when the game starts, and that seems to have improved it a little - but the particles still cause these freezes (maybe because the ParticlesMaterial has to be compiled too?) It would be insane to run every existing particle effect at the start of the game.

LinuxUserGD commented 6 years ago

On html5 (3d game) it takes more than 10 seconds to pre-render 3 cars offscreen in a car selection menu.

fracteed commented 6 years ago

@ProbDenis I have also tried these workaround, but still get the pauses on the first time particle systems are instanced. I was also guessing that it was that the particle system material that needs to be compiled. This is the main issue I am having with my game (along with lights turning themselves on/off at random). I am pinning my hopes on Vulkan to resolve these issues!

endragor commented 6 years ago

You can make particle materials pre-compile the same way - just add hidden particles with materials that can be used in the scene during your loading screen.

eon-s commented 6 years ago

If you have, lets say, an endless runner with a few different little effects, the loading screen will be unresponsive for half minute.

There should be a real solution for this (I mean, I have never seen this issue on the rest of the engines, with few materials), I do not know if that can be some kind of threaded process or compilation queued in frames or what.

Zylann commented 6 years ago

Half a minute for a few materials sounds really long... maybe the generated shaders themselves are quite big, or the optimizer is having a hard time crunching if branches? (if there is an optimizer though)

endragor commented 6 years ago

@eon-s Well I make a mobile game that has lots of particles and the loading screen between missions doesn't hang for half a minute, it takes few seconds on an average device. Did you base your statement on an actual experience or was it a guess?

eon-s commented 6 years ago

The super simple coin effect on the platformer demo takes from 3-5 seconds to load on mobile, for example.

LinuxUserGD commented 6 years ago

@eon-s I think it's a driver problem in this case. 20 materials should be loaded in ~ 5 seconds (even on mobile), html5 takes much longer.

Zireael07 commented 6 years ago

@LinuxUserGD: It's not just loading the materials, it's also compiling the shaders so it takes a lot of time.

endragor commented 6 years ago

Compiling shaders doesn't take that much time. The game I mentioned compiles 100-200 different shaders during loading screen and it takes less than 5 seconds on mobile. So either there is something with that shader specifically, or with the specific GPU that you test on, and it needs to be investigated as a separate issue. Even if pre-compilation of shaders is implemented, it will not solve the problem you describe.

endragor commented 6 years ago

Ah, but the game uses a fork of Godot with PR #14902 merged into it, which significantly reduces compilation time of shaders (see "Issue 2" in the description of the PR). It wasn't merged into master though and I don't know why.

eon-s commented 6 years ago

That was not merged because is a hack for Adreno and do not solve all the issues with that chip.

Could be nice to be able to set those things as setting for android and wasm, if these huge and normally useless arrays are the problem, maybe a pr only for that option (limit on some arrays) can solve a lot of issues.

endragor commented 6 years ago

Well it's a "hack" just as much as other hacks existing Godot codebase and really any other large codebase that solves real-world problems. There are no side effects created by that PR that I'm aware of and it solves plenty of issues, while not complicating the architecture. So I think the benefits outweigh the vague "it's a hack" argument.

fracteed commented 6 years ago

@endragor I had previously tried this with particles, but still seem to get some pauses the first time they are truly used in the game. When say "add hidden particles" at the start of the game do you mean that they are emitted offscreen or behind geometry or maybe onscreen but with .hide() on? I am wondering if culling is why it is not working for me.

When you say that you have 200 materials how are you displaying these. I have tried having all my materials on cubes in a separate scene and then instancing this for a frame at the start of the game, which does seem to help but not totally alleviate the problem. Maybe there is a way with the profiler or monitor to know when a shader is being compiled?

endragor commented 6 years ago

We have a ShaderCacheNode that is added to the level scene. During loading screen it's supplied with PackedScenes that could be instantiated in the level, extracts materials from them, then creates either a Skeleton or Particles or MeshInstance (quad), depending on where the material is used in the scene. The created node is hidden (node.hide()) and is added as a child to ShaderCacheNode. When addChild is called, the shader is compiled. ShaderCacheNode exists for the whole duration of the level to ensure the shaders are always there and are compiled.

Zireael07 commented 6 years ago

@fracteed: No way to tell when a shader is being compiled. I have a PR in progress that separates rendering from 'idle' for profiling, which will hopefully let us tell the other stuff better: #18357

fracteed commented 6 years ago

@endragor thanks that is very useful info! It is similar to what I had been trying but I was just doing it manually and instancing in ready function and then freeing. I have tried your way of parenting to a hidden dummy node and it does seem a bit better. Still getting some random pauses at the start, but only sometimes, which is frustrating.

Just wanted some more clarification on what will trigger a shader to be compiled:

@Zireael07 this sounds like a very useful feature, hopefully it will be committed!

LinuxUserGD commented 6 years ago

@fracteed The object has to be in the camera view (e. g. 100 meters behind the 3D camera doesn't work). And it gets decompiled if the object is freed (use remove_child() to keep it in memory).

fracteed commented 6 years ago

@LinuxUserGD the strange thing is that when my player dies and the scene is reloaded for another level, I get no pauses, even though the whole tree has been freed. This is without me doing anything manually to try and precache shaders. You would think that if all shaders are decompiled after objects are freed from a scene, that I would get pauses each time a new scene is loaded. It is only the first time each object or particle system is instanced when first running a game.

Zylann commented 6 years ago

@fracteed if you queue_free the root and load a new root at the same time, refcounts won't drop to zero, maybe

Megalomaniak commented 6 years ago

@Calinou said: I've heard conflicting reports about Radeon HD 6000 GPUs (which support up to OpenGL 4.2, IIRC, which is enough for that feature).

Even HD 5xx0 should support 4.2 https://opengl.gpuinfo.org/gl_generatereport.php?reportID=804

Chaosus commented 6 years ago

I dont think it can be fixed quickly, pushed to 3.2...

CoolOppo commented 6 years ago

I dont think it can be fixed quickly, pushed to 3.2...

Ouch. I don't know why this isn't as high of a priority as literally (in the literal sense) anything else in 3.1. Having your game freeze every time a new object that hasn't been used yet enters the screen is an enormous deal-breaker for most people, and asking people to use hacky solutions that work sometimes is honestly pretty awful.

I am lead dev on a very big-name project right now, and we're investigating different engines to make a decision on what to go with. I really like Godot...actually a lot more than Unreal from a conceptual standpoint. The architecture in Godot is very well done: GDScript is going to speed up the workflow immensely compared to using the Blueprint system or C++ in Unreal, and the architecture of using nodes and scenes is a big plus as well (child actors in Unreal are very hacky).

Anyways, the problem here is that we can't go with this engine on a serious long-term project if we're going to be running into things like the game completely freezing when something pops onto the screen for the first time. It is not commercially feasible or responsible for us to spend the time doing. That's not even something you would find in a Shockwave game from 14 years ago, so it's kinda odd to me that you guys are just dusting this off.

This is honestly a very, very big thing, and I have to tell you, there are definitely some prioritization issues if this isn't high up on the list. It's not some little thing that should just be pushed off while new features are being added instead. Just keep in mind, games freeze for seconds intermittently because of this issue. Even the official material demo. I'm not trying to come off condescendingly about this...I actually care a lot about this and I want to see you guys succeed. That's why I am spending my own time (which I do value 😉) to write all of this.

So please just hear me out here. Serious contenders--like my team--who are evaluating Godot are not going to go with this engine when you guys refuse to even get the 3D demos to work without stuttering. Most wouldn't even have the courtesy to tell you guys this; they would just choose another engine. The reason I'm not doing that is because I see a lot of potential in Godot. It just needs some work here and there for it to be worth my team spending the coming years developing a game in this engine. Sure, you could work on new features...doing that looks good at first to outsiders, and admittedly does add appeal, but people who are actually planning a serious project are always going to delve a little deeper, and issues like this are exactly the kind of thing that is going to get Godot written off right away for the majority of projects.

If you guys seriously don't have the resources to get this done soon, I might take a look into doing it myself if the engine seems strong enough in other ways that we end up using it, because I really do want to be able to go with this engine. I don't know the internals of the engine at all though (yet), so it would be a pretty big hassle for me...it would take me quite a bit more time than someone who already knows how the gears are turning in there.


And if you are still not convinced...I'd like to know: @reduz @akien-mga @godotengine, how much $$$ per month do you guys need for our team to get the support we need in getting high-priority issues (for us) fixed in a reasonable amount of time? I'm talking strictly about getting specific things necessary for us moved up on the priority list, not adding crazy new features or anything ridiculous. It would mostly be things like getting this glitch fixed...just stuff that you guys will get around to anyways. I'm not asking for you guys to let us choose what direction to take things in or anything at all like that. Of course, we'd love to give the input, but really, the rest is up to you guys. We just need some mission-critical stuff to be in working order, and instead of just deciding not to go with Godot for this project, I figured it's worth a shot to ask.

Obviously I'm not making any offers yet, but I am curious what you guys think, because if something like this is possible for us, that would be a huge factor in deciding what engine we roll with. I just need some numbers I can tell my boss. We would have to pay Unreal 5% of our revenue anyways, or we'd have to pay $125/mo for Unity Pro. Are you guys willing to be competitive to those projects (in our eyes) for a certain amount of money? It would be a better use of our money to pay this project instead of those big names if you guys are going to be able to offer up what we need to get things happening. Keep in mind, your competition actually has the ability to make 3D games that don't freeze/stutter all the time, so if you guys aren't able to offer up the same (by fixing the big bugs like this one), how can anybody decide to use Godot on anything other than a toy project? Don't get me wrong, Godot is a really fine piece of software, and in time, it'll probably be the best engine out there. We just can't sit around and wait for that to happen though, so if you guys are willing to work with us here, and respond to input about a real indie team's needs in an engine, that would be some seriously awesome shit. It would definitely be way cooler than paying some giant corporation a bunch of money.

Epic Games and Unity surely don't care about the end-users or take feedback even close to as much as you guys anyways. If you guys want this thing to finally start getting used on a big name game...now is your opportunity. How much money would it take to get:

Keep in mind, we're not billionaires here, so we're not gonna be throwing like $1000 a month at you or something. We are a very small team so far, but there are some big names involved here...that's all I can say right now unfortunately. I realize you guys already have a lot of support on Patreon as well, and you have other sponsors, but how much would it take to help some brothers out and prioritize fixing the things they need to make an indie game with your engine?

I swear I'm not exaggerating or being cocky when I say this: our game will definitely be the biggest game made in this engine ever if we decide to go with this engine. It took me like an hour just to write all of this, so please believe me when I tell you, this is a serious message, and I wouldn't spend the time typing this whole thing just to screw around. I know you guys value your time and really love this project, and I honestly think having some back-and-forth with us would be a huge benefit for everyone involved. Please do let me know what you think, I'd love to hear your opinions. Keep up the great work, even if you guys aren't interested in anything like this, I wish you the best. The amount of progress you guys have made in like two years is super impressive, and I have a strong feeling that two years down the road, this engine is going to be the go-to.

starry-abyss commented 6 years ago

@CoolOppo Please excuse me, just a random contributor here, but I have to say:

Looking forward to your game in Godot!

eon-s commented 6 years ago

@CoolOppo I have not read the full text, but if you need some work on a particular feature, I think donations to Conservancy can be directed to a specific purpose if you want to, contact the dev team via the address pointed in the previous comment, you can also contact core devs on IRC (you can find it on the community section of the official site), and you will get official help even if you cannot donate because devs want to see games made in Godot.

Right now there is an event on Europe so they may be a bit busy for a week or so, so be patient.

reduz commented 6 years ago

@CoolOppo If you are working with a large company, the best approach you can take is hire one of the core contributors to add this feature and assist your company on anything you might need (write to
contact@godototengine.org). Otherwise sorry, can't help you, this will happen when it can happen.

CoolOppo commented 6 years ago

@reduz So either we have to hire someone from your team or we can't get the critical bugs fixed that are stopping us from making a game with your engine? I'm not asking for you guys to spend extra time doing specialty things, I'm asking for you guys to fix the important bugs that are roadblocks for us.

We can't afford to hire one of the core contributors, and regardless, this is a feature that everyone wants in the first place. Is there a way to put bounties on specific bugs, like @starry-abyss and @eon-s said in their helpful responses?

I have to say, I am honestly super disappointed with this response. It seems to me like you didn't take any time to read what I wrote, and that took me a pretty long time. Telling me that getting the crucial things done for literally anyone to make a viable 3D game "will happen when it can happen" is not at all what I would expect to see.

reduz commented 6 years ago

@CoolOppo Yes, that is pretty much what any other large company using Godot is doing.

Regarding this issue, as I mentioned before, in GLES2 this is a lot less of a problem given shaders are tiny. The high end renderer is being rewritten in Vulkan in Godot 3.2 so no new functionality is being added now.

Sorry if you are expecting a more mature engine, but as I mentioned, there are higher priorities right now than what your company needs so, if you can't hire someone, we are not going to work for you.

endragor commented 6 years ago

@CoolOppo As a lead developer of a larger-than-average 3D game on Godot (www.summonage.com), I feel you. We switched to Godot from UE4 about a year ago, because UE4 had pretty poor support of Android at that point, and as far as I know still doesn't run great even on some high end devices. You should understand that Godot is developed mostly by enthusiasts who do not treat like a business/product, but rather a project where they can work on something they find fun. As recent survey revealed, most of Godot users (and, subsequently, contributors) are single hobby-project developers. Obviously, hobby projects have different requirements and expectations than products, so what we get is that some very important features, like this one, do not get implemented and some others, less important ones, do.

You haven't shared much about the kind of game you will be working on, so I'll try to make a short (EDIT: turned out not so short) comparison between Godot and UE4. Unity was not an option for us, because we already had significant codebase implemented on a native programming language (Nim) which would be hard/inconvenient to integrate with Unity.

So this is what I can tell without knowing specifics of the project. I could probably provide more insights on whether Godot would work for you if I knew more (at least genre/platform). Hoping to see more serious products implemented with Godot, as it would help make the engine more mature and appealing. I feel Godot can definitely take the "best for medium-sized projects" niche with time, if developers focus on ironing our the existing features/concepts rather than keep adding the new ones. There is already plenty you can do with Godot, but many things feel raw and unpolished.

Anyway, feel free to reach out to me for more info. This discussion has already gone off-topic and should probably be extracted into somewhere else.

reduz commented 6 years ago

@endragor I have the feeling that, save for rendering issues, most expected features should be there in 3.1.

The whole GLES3 thing ended up being a costly mess, though. We have found dozens of driver bugs both on desktop and mobile that are not easy or obvious to work around.

Hope after 3.1 is out, I can fully work on fixing all the remaining rendering things.

endragor commented 6 years ago

@reduz no problem with me specifically, as this particular issue is workarounded in our code/engine fork. However, now for two versions in a row people can't build a production-ready game without running into this issue. If 3.1 stays there for another ~9 months, it means 1.5 years of not being able to make a non-trivial game without having to jump through hoops. So I can understand the pain new people feel when seeing issues like this stay unresolved for a long time.

I agree that Godot has the necessary features, and even 3.0 already provided all you need to build a medium-sized game. In my opinion, product-wise, the focus should be on ironing out and iterating on existing features rather than adding new ones. This issue in particular feels more like a bug than a feature request, because noticeable freezes is not what people expect when calling add_child() with anything that has (not already used) materials in it.

endragor commented 6 years ago

@CoolOppo By the way, I don't think freezes you see in demo projects are caused by this issue - new things aren't added dynamically in those projects. Or which project did you see it in?

If you launched the project from the editor, the freezes come from the blocking IO that is performed on the game's main thread to talk with the editor. That's another annoying issue, but you should not see it if you launch the game from command line (without the editor).

mhilbrunner commented 6 years ago

@endragor Thanks for taking the time for such a detailed (and honest) assessment. I agree nearly on all points, from my experience with both Godot and UE4.

We haven't used Godot's networking, but from what I saw in the code, it's very barebones and not suitable for implementing anything complex.

It's improving a lot in 3.1, and IMO the only big thing missing then is scene replication (so a client joining mid-game gets the current scene state automatically). Besides that, it is fine - should be enough for any small to mid size game, and for larger ones you usually tend to do everything mostly yourself anyway if networking is a core feature, at which point having basically ENet in Godot is as good a starting point as any.

UE4 does have very nice networking and comes with more batteries included, mind if you know how to use it, which is indeed a big if from what I've seen - at least if you are not Epic.

But yes, IMO issues such as this and the lack of batching make Godot a harder sell than it should be.

In my opinion, product-wise, the focus should be on ironing out and iterating on existing features rather than adding new ones. This issue in particular feels more like a bug than a feature request, because noticeable freezes is not what people expect when calling add_child() with anything that has (not already used) materials in it.

This. I believe (and hope) this sentiment is mostly shared by the other Godot devs :)

CoolOppo commented 6 years ago

@endragor, thanks for all your responses. You've been very helpful and I appreciate you taking the time to type all that out. I emailed you more stuff that's on-topic.

now for two versions in a row people can't build a production-ready game without running into this issue. If 3.1 stays there for another ~9 months, it means 1.5 years of not being able to make a non-trivial game without having to jump through hoops.

This sums up my thoughts on it entirely.

CoolOppo commented 6 years ago

@endragor:

By the way, I don't think freezes you see in demo projects are caused by this issue - new things aren't added dynamically in those projects. Or which project did you see it in?

Are you sure about that? I found this issue through #18265, and it was closed as a duplicate of this issue.

you should not see it if you launch the game from command line (without the editor).

I have tried that and the issue is still there. :\

dejaime commented 6 years ago

@CoolOppo By the way, I don't think freezes you see in demo projects are caused by this issue - new things aren't added dynamically in those projects.

Even if the project does not add anything dynamically, it would probably still freeze if the nodes are not initially visible.

Are you sure about that? I found this issue through #18265, and it was closed as a duplicate of this issue.

I guess that is not a demo, the user created that as a minimal reproduction project, I don't know if there are any demos affected by this.


If I may throw my two cents in the discussion, I do love Godot for several of its strong points, some examples:

I also had to drop it before due to some 3D rendering order issues I did report back on version 2.1 over a year ago (the issue is still present on 3.0.6). I believe it is still not ready for 3D yet, that was my experience, it does need more time to mature on that front.

But on the other hand, Godot is by far the best engine I have ever used for 2D, and in there I include even commercial engines, including Unity with which I was stuck for 5 years on my day job. I caught myself the other day thinking on how to convert a 3D project into 2D just so I could use Godot.

I do believe that this issue is a big problem and it should be prioritized over most 3D entries on the roadmap. Still, in light of what I just said before, I do believe it should not be prioritized over other entries in the roadmap, like multithreaded debugger or typed instructions, as those affect all users and the part where I'd consider the engine 100% production ready (2D).

Of course, as many of us here, I can't wait to see Godot head to head with all other 3D engines out there.

endragor commented 6 years ago

Even if the project does not add anything dynamically, it would probably still freeze if the nodes are not initially visible.

No, the freeze happens during add_child(). The shader gets compiled no matter if the node is visible or not, the defining thing is that it's in the scene tree.

It's correct that #18265 is not a demo project, it's a reproduction project for this issue. The demo projects are at https://github.com/godotengine/godot-demo-projects

dejaime commented 6 years ago

Even if the project does not add anything dynamically, it would probably still freeze if the nodes are not initially visible.

No, the freeze happens during add_child(). The shader gets compiled no matter if the node is visible or not, the defining thing is that it's in the scene tree.

I just downloaded the #18265 issue project, and all the meshes are already on the scene hierarchy (no add_child call). I ran the project and it did stutter on every single one of them when they entered the camera for the first time. It worked fine on subsequent runs though, suspecting some sort of driver(?) cache, I changed the diffuse and blend mode randomly and it froze once again. Could you please verify that, I mean, download the minimal project and run it?

CoolOppo commented 6 years ago

I guess that is not a demo, the user created that as a minimal reproduction project, I don't know if there are any demos affected by this.

The 3D material demo freezes for me in the same way as that project.

No, the freeze happens during add_child(). The shader gets compiled no matter if the node is visible or not, the defining thing is that it's in the scene tree.

I think the freeze happens when the shaders get compiled, which can be either after add_child(), or when a previously unused material becomes visible for the first time.

Edit: These could be two separate issues, but I'm assuming they're not, as that other issue was closed as being a duplicate of this.

starry-abyss commented 5 years ago

As it's not mentioned explicitly here, I'm going to add that on GLES2 the issue doesn't occur for me (no freezes noticeable by bare eye) with the example from #18265 (as of 3.1-beta1), while it occurs on GLES3 each time I remove the new files from Nvidia's GLCache: C:\Users\ USERNAME \AppData\Local\NVIDIA\GLCache. I even tried to remove the cache files created by the editor's activity itself (as the editor renders too, and driver caches what it renders), between exiting the editor and running the project standalone. Still good for GLES2, at least on that simple project.

mpue commented 5 years ago

I had a quick look into the code. It's a little bit weird, since glCompileShader is being called from a method inside the Shader class called "get_current_version" which is called from within bind. That causes the problem.As far as I can see, this is a bigger thing and needs some major changes, concerning the shader mechanism. I am going to fix this problem but it takes a few days to get into the code.

Regards.