Increase number of texture units

Started by AeroShark333, July 29, 2020, 06:55:13 PM

Previous topic - Next topic

AeroShark333

I received a crash from an user with the following stacktrace:
java.lang.RuntimeException:
  at com.threed.jpct.Logger.log (Logger.java:206)
  at com.threed.jpct.GL20.checkError (GL20.java:163)
  at com.threed.jpct.GL20.glGenBuffers (GL20.java:1385)
  at com.threed.jpct.CompiledInstance.compileToVBO (CompiledInstance.java:1478)
  at com.threed.jpct.CompiledInstance.render (CompiledInstance.java:606)
  at com.threed.jpct.GLRenderer.drawWireframe (GLRenderer.java:2552)
  at com.threed.jpct.World.draw (World.java:1424)
  at com.threed.jpct.World.drawWireframe (World.java:1132)
  at com.aeroshark333.artofearthify.lw.ArtOfEarthify$34.run (ArtOfEarthify.java:1492)
  at com.aeroshark333.artofearthify.utils.WorkerThread$2.run (WorkerThread.java:46)
  at com.aeroshark333.artofearthify.lw.ArtOfEarthify.onDrawFrame (ArtOfEarthify.java:1681)
  at com.aeroshark333.artofearthify.lw.LiveWallpaperRenderer.onDrawFrame (LiveWallpaperRenderer.java:73)
  at android.opengl.GLSurfaceView$GLThread.guardedRun (GLSurfaceView.java:1553)
  at android.opengl.GLSurfaceView$GLThread.run (GLSurfaceView.java:1253)

Any idea what this could be? I've only received this once so maybe it could be ignored...

PS: The question is unrelated to the original thread but I thought the topic title suited... so...

PPS: Although jPCT has Config.maxTextureLayers, the hard limit seems to be 4. Would it be possible to increase this value to 8 (or arbitrary)? Or assign these extra textures using a hack or something? I'd like to be able to access 8 textures in my fragment shader in a single pass

EgonOlsen

No idea what that error should be. Something isn't quite right with the gl state for some reason. I would ignore it for now.

And yes, 4 is a hard coded limit. I looked into expanding it once, but decided against it for reasons that I can't remember anymore. Must have been a technical limitation of some kind. There's no way to hack around it, I'm afraid.

AeroShark333

#2
Quote from: EgonOlsen on August 01, 2020, 06:10:42 PM
No idea what that error should be. Something isn't quite right with the gl state for some reason. I would ignore it for now.
Okay, thank you

Quote from: EgonOlsen on August 01, 2020, 06:10:42 PMAnd yes, 4 is a hard coded limit. I looked into expanding it once, but decided against it for reasons that I can't remember anymore. Must have been a technical limitation of some kind. There's no way to hack around it, I'm afraid.
I found this post (Reply #1) for a possible reason why: http://www.jpct.net/forum2/index.php?topic=3371.0
Another possible reason I could think of: the minimum amount of vertex attributes is used up.

But I still think it should be possible to increase the limit to at least 8; especially modern devices (I think actually old ones too) should support this.
It is true that vertex shaders have very limited textures to access (minimum of 0).
Though, usually I believe textures are only accessed in the fragment shader (so there should be no problem at all considering the limit for the amount of vertex shader textures).
The amount of textures that can be accessed in the fragment shader is at least 8.

To fix the vertex attributes being used up: merge variables into one bigger variable.
Currently there's 4 texture attributes for the texture coordinates (as seen in: http://www.jpct.net/jpct-ae/doc/com/threed/jpct/GLSLShader.html)
However, these are all vec2's, while they could be vec4's.
4 vec4's could potentially hold texture coordinates for 8 texture stages.
Example:
//VERTEX SHADER
...
attribute vec4 texture01;
...
void main(){
    ...
    vec2 texture0 = texture01.xy;
    vec2 texture1 = texture01.zw;
    ...
}


According to the OpenGLES2 spec: https://www.khronos.org/registry/OpenGL/specs/es/2.0/es_cm_spec_2.0.pdf (page 66 of documentation; page 71 of PDF)





StateMinimum value
MAX VERTEX TEXTURE IMAGE UNITS0
MAX TEXTURE IMAGE UNITS8
MAX VERTEX ATTRIBS8

I suppose it'd be a quite a challenge to be rewriting this so I'm not sure if it's too much to ask for.
I'd have wanted to give it a shot if jPCT-AE was open-source but yeah...
Otherwise, would it be possible to add something more hacky so I'd still be able to bind these textures to the Object3D (and its GLSLShader) from stage 5 to 8?
A TextureBindingHook or something for additional texture stages, something like:
TextureInfo blah ... // first 4 textures go here
obj.setTexture(blah);

obj.setTextureBindingHook(new TextureBindingHook(){
    @Override
    public void beforeFinishedBinding(){
        Texture tex = fifthTex;
        int stage = 5;
        String variableName = "textureUnit4";
        methodToBind(tex, stage, variableName);
    }
});

(Additional texture coordinates attributes I don't really need; but only being able to access the textures in the fragment shader)

EgonOlsen

#3
I briefly looked into it. Most of the code is prepared to deal with more texture units already (or at least it looks to be; I've never actually tried it). There are few parts that have a hardcoded "4" but these are easy to change. I'll write myself a test case and see what happens if I bump it up to 8 (at least) when I find the time to do so. I guess I have to modify some parts, because the hard limit given by the constant in TextureInfo is a bad idea anyway, but if I remove it, I might have problems with memory usage. We'll see...

AeroShark333

Okay, thank you for looking into it :)
I'd be interested in hearing the results.

I'm not entirely sure what you meant with the memory usage thing..? I believe it'd be possible to test it with one single texture assigned to 8 texture layers too. (Not really useful in practice but I guess it's easiest to test)


EgonOlsen

Haven't tried it yet. I'm busy with other stuff ATM, but I'll come to it eventually.

AeroShark333

Quote from: EgonOlsen on August 11, 2020, 03:50:45 PM
Haven't tried it yet. I'm busy with other stuff ATM, but I'll come to it eventually.
Oh okay, take your time ;)
Also, good luck :D

I'm really curious to hear the results so excuse me being a little impatient

EgonOlsen

I gave it a try, it seems to work. For now, I've increased the limit to 8. It would be better to make it more flexible and to get rid of that constant in TextureInfo, but I can't be bothered right now. The default shaders still support up to 4 units only, because the code they are using to add each layer is rather messy for compatibility reasons and I don't want to fiddle around with that ATM. So for more than 4 units, you have to use your own shader code to support it properly.

Anyway, here's the new version: https://jpct.de/download/beta/jpct_ae.jar

Here's an hacky example that uses up to 8 units: https://jpct.de/download/beta/MixingExample.zip

And this is how it looks like (or should look like...). The upper cube uses 4 units, the lower one 1 and the one in the middle uses 8.


AeroShark333

After looking at the example, I tried it myself with the updated version.
The example seemed pretty straightforward for how it'd work with 8 texture layers.

I suppose because the default shaders use an 'unwrapped' for loop, it'd be annoying to change it all.

Anyway, as expected, it works like a charm for my use case! :D
Thank you so much for your time and effort!

EgonOlsen

Quote from: AeroShark333 on August 24, 2020, 11:11:19 AM
I suppose because the default shaders use an 'unwrapped' for loop, it'd be annoying to change it all.
Yes, I had to do that because using the index from a loop didn't work. I can't remember if in general or only on some devices (more likely), but that's how it is now.

AeroShark333

Quote from: EgonOlsen on August 24, 2020, 05:25:43 PM
Quote from: AeroShark333 on August 24, 2020, 11:11:19 AM
I suppose because the default shaders use an 'unwrapped' for loop, it'd be annoying to change it all.
Yes, I had to do that because using the index from a loop didn't work. I can't remember if in general or only on some devices (more likely), but that's how it is now.
Actually I believe it is generally like that. GLSL doesn't seem to allow non-constant variables for accessing arrays or something. I believe some devices might support it because they've added the support but overall generally not.

MichaelJPCT

can you use while loop?
int i=lightcount; while (i>0) { do something; i--; }
i never used a loop though.
using variable in array seems fine for me. i did something like this:
int i=int(position.x); position.x=uniform[i*3+1];

AeroShark333

#13
Quote from: MichaelJPCT on August 25, 2020, 08:41:18 PM
can you use while loop?
int i=lightcount; while (i>0) { do something; i--; }
i never used a loop though.
using variable in array seems fine for me. i did something like this:
int i=int(position.x); position.x=uniform[i*3+1];
I don't think that'd work for the general case.
Especially the "uniform[i*3+1]" part probably would not work.
That's because "i*3+1" is not a constant variable but a dynamically assigned one.
The reason why it might work for your device(s) is probably because of what I mentioned in my previous post. I believe more and more devices these days do support it, though. However, still not always... (It could be a driver bug too but I'm not sure why this is an issue for some devices). I have had report crashes in the past on the Google Play Store Console when I used a for-loop and accessed a variable in an array using a non-constant variable.

I believe one of the better solutions can be found here (under Edit2): https://stackoverflow.com/questions/16039515/glsl-for-loop-array-index