5

System: Android 4.03, OpenGL ES 2.0

Problem: When glAttachShader is invoked after the first frame has already been rendered with another program / shader, some devices (Galaxy S3) crash with a "GL_INVALID_VALUE" error (no further details are available in the error stack). Other devices (Asus eee TF101) are perfectly fine with that. The error does not always occur and sometimes it's also a "GL_INVALID_ENUM" instead. If I force all shaders to be compiled right at the first call to onDrawFrame, it works on all (my) devices.

Questions: Are there states in which the openGL(ES) machine is incapable of compiling a shader? Is it possible that bound buffers, textures or enabled attribute arrays interfere with attaching a shader to a program? If so, what is the ideal state one must ensure before attaching shaders and linking the program? Is it even valid to compile shaders after other objects have already been rendered with other shaders?

Background: I'm developing an Android library that will allow me to use openGL graphics in a more object oriented way (using objects like "scene", "material", "model" etc.), utlimatively to write games easily. The scenes, models etc. are created in a thread different to the GL context. Only when onDrawFrame encounters one of these objects it will do the buffer object binding, texture binding and shader compilation, within the right thread. I would like to avoid to compile all shaders at the beginning of my code. The shader source is assembled depending on the requirements of the material, the model and the scene (eg: Material: include bump-mapping, Model: include matrix-palette-skimming, scene: include fog). When a model is removed from a scene, I'm going to delete the shader again - and if I add another model, the new shader should be compiled ad-hoc.

At this point I'm trying to be as concise as possible without posting code - you can imagine that extracting the relevant parts from this library is difficult.

Jan_K
  • 51
  • 6

2 Answers2

2

It is perfectly valid to compile during rendering although is discouraged as the driver needs to take resources (CPU) for that. Some driver states my trigger a shader recompile at the driver side as some states are injected into the shader. It wise to reorganize your drawing calls into chunks sharing the same driver state (preferred by shader program as is one of the most expensive operations done by the driver).

TIP: Be sure to "use" all variables, uniforms and attribs declared into your shader, otherwise, the Mali driver removes them during compile and when you try to get an uniform location, an attrib location and son on, the drivers returns GL_INVALID_VALUE.

Hope that helps.

Trax
  • 1,890
  • 12
  • 15
  • That sounds interesting - did I get that right that the driver will automatically recompile shaders when certain states / events are triggered, even if they have been compiled before? Where can I learn more about this behaviour? – Jan_K Jan 22 '13 at 16:15
  • That's is transparent to you, but understanding the implications is a key for good performance. Check for example Tegra documentation here: http://docs.nvidia.com/tegra/data/Optimize_OpenGL_ES_2_0_Performance_for_Tegra.html – Trax Jan 22 '13 at 16:31
  • AMD provides a Windows executable called MakeBinaryShader.exe, which compiles text shaders into binary. AMD also provides a library-based interface, BinaryShader.lib, which provides functions that you can call into to compile your shaders directly from within an application. Imagination Technologies also provides its own binary shader compilation tool called PVRUniSCo along with an editor called PVRUniSCo Editor. – Patt Mehta Jan 22 '13 at 16:55
  • 1
    It's a catch-22 for me. Accepting that what I'm doing is valid wont solve my problem, assuming that what I'm doing is wrong will turn 200KB of code into digital waste. Before I accept your response I'll try to create some *postable* code that should pinpoint the problem. Will be back! – Jan_K Jan 22 '13 at 18:25
  • Even I wanted to create a library, and create the shader binaries offline, but I could only manage obj parsers using Perl that work offline. GPU processing can be saved significantly if there was an easy way to compile shaders offline. If it's 200KB do not throw it away :D – Patt Mehta Jan 22 '13 at 22:03
0

If you copy the BasicGLSurfaceView sample code that comes with the Android development kit to start your project, then the first call to

checkGlError

is after attaching the vertex shader. However, you might have used an invalid value or enum a lot earlier or in a different location in your code. But this will only be picked up by this call, after glAttachShader.

In my case I deleted a texture which was still linked as render target for a framebuffer. My older Android device which runs slower compiled the shader before deleting, my newer device somehow managed to call

glFramebufferTexture2D

before compiling the shader. The whole thing somehow links to queueEvent and my poor understanding of thread-safety.

Thanks for your efforts, TraxNet and Prateek Nina.

Jan_K
  • 51
  • 6