godotengine / godot

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

CPUParticles2D cause error in CanvasShaderGLES2 on Raspberry Pi #27407

Closed hiulit closed 5 years ago

hiulit commented 5 years ago

Godot version: 3.1-stable

OS/device including version: Debian (Raspbian) Stretch / Raspberry Pi 3 Model B

Issue description: I have a GLES2 project with no shaders (that I'm aware of). The only "special" thing is some CPUParticles2D. I exported the project using https://github.com/efornara/frt (an export "platform" for Raspberry Pi) and when I launch it, these errors appear (and the CPUParticles2D don't show up)

ERROR: _display_error_with_code: CanvasShaderGLES2: Program linking failed:
ERROR:LINK-4 (link time, line -1) Too many attribute values
    At: drivers/gles2/shader_gles2.cpp:129.
ERROR: get_current_version: Method/Function Failed, returning: _null
    At: drivers/gles2/shader_gles2.cpp:414.
ERROR: bind: Condition ' fversion' is true. returned: false
    At: drivers/gles2/shader_gles2.cpp:88.
ERROR: _get_uniform: Condition ' fversion' is true. returned -1
    At: drivers/gles2/shader_gles2.h:254.

Steps to reproduce: Open the test-rpi.zip below in a Raspberry Pi 3 Model B and run the following command:

cd test-rpi/
sudo chmod +x frt_094_310_pi2.bin # To give permissions to the file, if needed.
./frt_094_310_pi2.bin

I've also added the source code of the project, just in case it could be needed.

Minimal reproduction project:

test-rpi.zip project-source-code.zip

clayjohn commented 5 years ago

Im guessing your hardware just doesnt fully support opengl. Based on your error, it looks like the integrated GPU cant handle the number of attributes passed into each vertex of the canvasitem shader. GLES2 is made to be compatible with extremely low end hardware, but it has its limits.

efornara commented 5 years ago

I can pretty much confirm that the problem is the shader complexity exceeding what the hardware allows.

I already had the vc4 enabled, so I also tried it on a plain godot/x11 (i.e. no frt). The error is different, but the problem is the same.

At: drivers/gles2/rasterizer_gles2.cpp:134.
ERROR: _gl_debug_print: GL ERROR: Source: OpenGL    Type: Error ID: 2   Severity: High  Message: GL_INVALID_VALUE in glBindAttribLocation(8 >= 8)
At: drivers/gles2/rasterizer_gles2.cpp:134.
ERROR: _gl_debug_print: GL ERROR: Source: OpenGL    Type: Error ID: 2   Severity: High  Message: GL_INVALID_VALUE in glBindAttribLocation(9 >= 8)
At: drivers/gles2/rasterizer_gles2.cpp:134.
ERROR: _gl_debug_print: GL ERROR: Source: OpenGL    Type: Error ID: 2   Severity: High  Message: GL_INVALID_VALUE in glBindAttribLocation(10 >= 8)
At: drivers/gles2/rasterizer_gles2.cpp:134.
ERROR: _gl_debug_print: GL ERROR: Source: OpenGL    Type: Error ID: 2   Severity: High  Message: GL_INVALID_VALUE in glBindAttribLocation(11 >= 8)
At: drivers/gles2/rasterizer_gles2.cpp:134.
ERROR: _gl_debug_print: GL ERROR: Source: OpenGL    Type: Error ID: 2   Severity: High  Message: GL_INVALID_VALUE in glBindAttribLocation(12 >= 8)

See the attachment for the result of

glxinfo -l

glxinfo.txt

I think the relevant line is:

GL_MAX_VERTEX_ATTRIBS_ARB = 8

If you really want to support that effect on the Raspberry Pi, you might want to consider baking it into a sprite.

hiulit commented 5 years ago

So you are saying that CPUParticled2D won't work on the Raspberry Pi?

Because I don't have any other shader.

hiulit commented 5 years ago

I tried the project on a VM running PIXEL and these erros don't show up. I don't know if that information is relevant though.

efornara commented 5 years ago

If by VM you mean an x86_64 / i386 emulator, I don't think that's relevant.

IIRC, particles used to work on godot 2.1 (explosions in the 2d platformer are particles, right?). Given the name, I was expecting "CPU" particles to just use the "normal" canvas shader and not to require anything special on the GPU side. Maybe someone more experienced can look at your CPUParticled2D node and see if you can disable some unneeded flags, and this might help.

I can only confirm that when I tried your my-game.pck on an Intel GPU I was seeing the particles (when the character landed, I think), and on a Raspberry Pi I wasn't seeing them.

efornara commented 5 years ago

I wouldn't bet on anyone suggesting a way out of it with some flags. I had a quick look at the engine code. Godot 2.1 was indeed using normal canvas item, while godot 3.1 looks like is using a different method (multimesh).

The problem seems to also affect some other old hardware: https://github.com/godotengine/godot/issues/26472 It has been tagged for 3.2. Unfortunately, this problem might not affect that many GPUs (e.g. Mali 400 should be immune: I think it supports 16 attributes).

So, yes, unless I have misunderstood the engine code, your best option is probably to bake the effect into a sprite.

hiulit commented 5 years ago

Ok, it's good to know that's planned for 3.2. Let's hope it can fix it for the Raspberry Pi 🤞 @efornara I also assumed that CPUParticles2D would be better optimized for lower powered machines. Meanwhile, I'll have to forget about using particles in my game.

hiulit commented 5 years ago

In case it helps someone figure these issues out, here's my particles scene:

[gd_scene load_steps=2 format=2]

[sub_resource type="Gradient" id=1]
offsets = PoolRealArray( 0.00514139, 1 )
colors = PoolColorArray( 1, 0.860509, 0.564516, 1, 1, 1, 1, 0 )

[node name="Dust" type="CPUParticles2D"]
position = Vector2( -2, 15 )
rotation = -1.5708
emitting = false
amount = 20
lifetime = 0.45
one_shot = true
speed_scale = 2.0
explosiveness = 0.7
local_coords = false
emission_shape = 2
emission_rect_extents = Vector2( 1, 6 )
gravity = Vector2( 0, 0 )
initial_velocity = 10.0
initial_velocity_random = 1.0
angular_velocity = 1.4013e-44
scale_amount = 5.0
scale_amount_random = 1.0
color_ramp = SubResource( 1 )
clayjohn commented 5 years ago

CPUParticles do not use shaders to update. They only use a shader to render the particles themselves. It is the same shader used to render every other canvas item. However, CPUParticles use more vertex attributes in order to pass in per-particle information. It is unlikely that in future updates this will be changed.

The only possibility is that if, in the future, someone updates CPUParticles to have the option to disable per-vertex colors and custom data. Regular Particles have this option. Maybe disabling them will be enough to make it run on your hardware.

efornara commented 5 years ago

To elaborate a bit on what @clayjohn has written, and to check if I did read the engine code correctly, this seems to be the culprit:

https://github.com/godotengine/godot/blob/3.1-stable/drivers/gles2/shaders/canvas.glsl#L29-L38

#ifdef USE_INSTANCING

attribute highp vec4 instance_xform0; //attrib:8
attribute highp vec4 instance_xform1; //attrib:9
attribute highp vec4 instance_xform2; //attrib:10
attribute highp vec4 instance_color; //attrib:11

#ifdef USE_INSTANCE_CUSTOM
attribute highp vec4 instance_custom_data; //attrib:12
#endif

USE_INSTANCING seems to be unconditionally enabled if you are using TYPE_MULTIMESH:

https://github.com/godotengine/godot/blob/3.1-stable/drivers/gles2/rasterizer_canvas_gles2.cpp#L978

state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCING, true);

And the CPUParticle2D seems to be using it. See NOTIFICATION_DRAW in:

https://github.com/godotengine/godot/blob/3.1-stable/scene/2d/cpu_particles_2d.cpp#L992

VS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid, normrid);
clayjohn commented 5 years ago

@efornara yep. Those are the per-particle information I was talking about. All three of those xforms are needed (they describe the particle transformation), but instance_color and instance_custom could likely be disabled.

efornara commented 5 years ago

@clayjohn

On the other hand, making instance_color and instance_custom optional won't be enough to make it run on hardware with GL_MAX_VERTEX_ATTRIBS_ARB = 8. Probably the only common platform to have this limitation is the Raspberry Pi / VideoCore IV. The tablet mentioned in https://github.com/godotengine/godot/issues/26472 is quite old and unlikely to be wildly used. Again, (un)fortunately I don't think that the Mali-4xx family has this problem.

The only obvious (at least to me) way to fix this (i.e. bring the vertex attribute count down to 8) is either 1) rewrite GPUParticles2D to use TYPE_RECT, like godot 2.1 does, degrading performance for the vast majority of platforms 2) rewrite GPUParticles2D to have two code paths (TYPE_RECT and TYPE_MULTIMESH) and select at run-time which one to use, making the code more complex.

I guess what I am trying to say is this: Is this issue really likely to be fixed? Or it makes more sense to close it as wontfix?

hiulit commented 5 years ago

Just my two cents:

I think, if possible, it would be best to try and fix this issue. The Raspberry Pi is the 'single board computer' most sold around the world. It's cheap and lots of people have one or even more than one at home. If Godot games could be played on it, it could bring more people to know/use Godot.

We could also try, for example, to ship some games on RetroPie (one of the most used 'OS' to play games on the Raspberry Pi. I've even already begun to create a script to install Godot on it.

If there is any chance to fix it for 3.2, or even 4.0 it would be amazing. Otherwise, it would be a good a idea to state somewhere that, although using GLES2 (and CPUParticles instead of GPUParticles) it won't make your game able to be played on a Raspberry Pi. Because I think, at least that was my understanding, that enabling GLES2 would make that happen.

clayjohn commented 5 years ago

@hiulit this isnt really a matter of "fixing an issue" its a matter of whether the core devs want to support such low-end hardware. There is a trade-off involved in doing so. If they rewrite CPUParticles to run on such low-end hardware, all users will incur a performance cost (limiting the usefulness of CPUParticles for all users).

In my opinion, i think making it clear in documentation that not all hardware will necessarily support all features would be a good idea. Speaking of which, i dont think Godot officially supporrs raspberry PIs to begin with.

On a personal note, i dont think particles are a good idea for a game intended to be run on the PI in the first place. Even with 2.1 era particles you will likely run into performance issues after only a few dozen particles. In which case, you would be better off baking your animation into a sprite. Or not having fancy VFX at all. You cant expect to have everything on a $20 computer.

efornara commented 5 years ago

I think the official line is something like:

Godot doesn't support the Raspberry Pi, but it should work, check the community.

Yes, it should be better documented what works and what doesn't. The fact is that I don't know it myself yet. To be honest, there are not many 3.0/3.1 demos around that target low-end hardware. The only demo that I have tried is the 2D platformer. It worked. Particles didn't work, but then I grepped the source and... it was using Particles2D, so it wasn't supposed to work.

In this regard, this looks very promising and it would be nice if it can be made to scale down to the Raspberry Pi: https://twitter.com/reduzio/status/1110400672258678784

I would say that taking a godot game, especially a 3.0/3.1 one, and expecting it to run on a Raspberry Pi is setting yourself up for disappointment. It is the other way around: if you want to write a game for the Raspberry Pi, godot is valid tool to do so.

As for Raspberry Pi / RetroPie and spreading Godot in that area, I believe that it could be done. I think what is really needed is a few nice games worth playing and other developers would follow. Yours looks very promising, @hiulit :wink:

hiulit commented 5 years ago

I think it would be a good idea to support low-end hardware, at least the latest Raspberry Pi.

I really don't know how much development would involve what @efornara said:

The only obvious (at least to me) way to fix this (i.e. bring the vertex attribute count down to 8) is either 1) rewrite GPUParticles2D to use TYPE_RECT, like godot 2.1 does, degrading performance for the vast majority of platforms 2) rewrite GPUParticles2D to have two code paths (TYPE_RECT and TYPE_MULTIMESH) and select at run-time which one to use, making the code more complex.

But it may be worth to take it into account and see if it would be doable. Or try to apply that to CPUParticles2D.

I understand that having fancy VFX is not supported on these low-end hardware, but in that case I misunderstood the coming back of GLES2 and the CPUParticles2D information. I though it would make it available for low-end hardware.

If it won't be supported, I would suggest making it clear somewhere prominent (if it's not already the case). Going even further, having documentation for what to use/not use to create games for low-end hardware would be very appreciated. I could even help create it.

If it support for low-end hardware (aka the Raspberry Pi) ever comes true, it would mean that Godot would be the first (I think) high-end game engine to support exports for that kind of hardware. And that could be great marketing for indie developers and for gamers. As I said, RetroPie, for example, could be a great source of free marketing for Godot.

That's my other 2 cents on the matter :P

P.S Thanks @efornara. I think now I have to rethink the game, because I was gonna have a fistful of particles there, hehe!

clayjohn commented 5 years ago

Could start thinking about this again with the release of the new PI... https://www.raspberrypi.org/blog/raspberry-pi-4-on-sale-now-from-35/

Supports OpenGL ES 3.0 out of box, dual monitor support, up to 4k resolution. And still very cheap.

clayjohn commented 5 years ago

Just noticed there is already a thread dedicated to Raspberry Pi support. All discussion here should be continued there. https://github.com/godotengine/godot/issues/2671

Closing this thread as Godot currently does not support Raspberry PI and there are no plans to reduce the rendering capabilities of Godot in order to support such low-end hardware