PDA

View Full Version : strange multitexture problems



dronus
09-29-2005, 01:05 PM
Hello.

I discovered some strange probs with multitexturing.

my setup:
-NO vertex shader (fixed function default)
-simple texture mixing in fragment shader
-only one tex-coord for both textures
-rendering unlit to fullscreen-quad
-all textures generated BEFORE any mutli-texture commands (eg all in stage GL_TEXTURE0)
-one texture is rendered as FrameBuffer before in a complex pass (which works completely on his own).

for debug, i split the two textures into different rgb channels, coloring one image yellow, the other blue:


uniform sampler2D Image;
uniform sampler2D Image2;
varying vec4 gl_TexCoord[];
void main(void){
vec2 tc=vec2(gl_TexCoord[0]);
gl_FragColor = vec4(texture2D(Image,vec2(gl_TexCoord[0])).xy,texture2D(Image2,vec2(gl_TexCoord[0])).x,1.0);
}

i allways fill in both sampler2D uniforms from GL constant by Image=0, Image2=1.

now following happens:

-if i do nothing multitexure commands in GL, only a yellow "Image" renders. correct.

-if i bind a second texture, preceded by glActiveTexture(GL_TEXTURE0+1), i only see it, "Image2", tinted blue. NOT correct. Both textures should appear mixed.

-if i now exchange the sample-bindings; eg. Image=1; Image2=0 then only the new texture is rendered, now yellow. simple. so switched back.

-now for the very strange, hurray..
if i switch to glActiveTexture(GL_TEXTURE0+1) while my whole mainloop which renders to the FrameBuffer and therefore "Image", all my texures on objects are gone (correct)but now the mixing works! i see a yellow AND blue "Image", "Image2" result, both textures mixed, like i wanted, with one exception: all parts rendered with the texture bound to "Image2" inside the "Image"-creating FramBuffer draw pass now vanish.
cool, eh?

smoking on this for two days now.

sorry for no c-code and no use of cool gl debuggers, its coded in java.

any ideas?
(maybe "no fixed function with fragment shaders AND multitexture, please!!" or some strange limitations known?)

many thanks & greets
Paul

dronus
09-29-2005, 02:05 PM
Arf..

Bothering you all with this crap i just go very experimental to salve my conscience...

with results!

i got it working finally with a "great" difference:
-Image2=1 is bound first introducing "multitexturing".
-FrameBuffer Image=0 is now bound as second texture but on stage GL_TEXTURE0

against my presumptions the actual active stage while creation of texture seems not relevant

maybe some fault concerning multitexturing like gl "as long i dont know its multi-textured, i made some things easier. if it is switched on, i get aware of." while just forget some small relations to fragment progs.

thx much for anyone thought about it
&greetings
Paul

sqrt[-1]
09-29-2005, 11:23 PM
FYI: you can use GLIntercept (http://glintercept.nutty.org) to debug such problems with java. Just put the openGL32.dll in the javaw.exe directory and take a XML frame grab.

From here you can see what textures are bound where on each render call.

def
09-30-2005, 04:40 AM
After your framebuffer is rendered you need to do glActiveTexture(GL_TEXTURE0); then you have to bind your texture you want to copy to, and then you call glCopyTexSubImage2D().
After that you call glActiveTexture(GL_TEXTURE1) and bind your second texture.

This works for me for multitexturing with 7 textures and ARB_fragment program, no vertex program. This shouldn't be different with GLSL.

Indeed, the texture stage is just an "index" where the bound texture is referenced to. (non-technically speaking)

I hope I'm not repeating just what you are already doing... :rolleyes:

dronus
09-30-2005, 08:42 AM
no, you don't. but it doesn't apply either because i'm using a real FBO FrameBufferObject which is capable of rendering directly to the texture, no need for CopySubPixel.

and, as i stated before, the problem is solved for now. but some invesitgation is allways good, as irrational behaveiour is not what i like :-)

i really hope i made some stupid bug and eliminated it without noticing so.

thanks you all
Paul

Ferenzzy
10-11-2005, 12:25 PM
Same problem for me but no solution yet. Perhaps somebody can tell me why to following doesn't work, i.e. the samplers always access the texture on GL_TEXTURE0.

Vertex shader:


void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
}Fragment shader:


uniform sampler2D tex;
uniform sampler2D old;

void main()
{
vec4 color = texture2D(tex, gl_TexCoord[0].st);
vec4 base = texture2D(old, gl_TexCoord[0].st);
gl_FragColor = base + color;
}Setup:


glGenTextures(3, texFloat);

glBindTexture(GL_TEXTURE_2D, texFloat[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, 4, 4, 0,
GL_RED, GL_FLOAT, matrix);

glBindTexture(GL_TEXTURE_2D, texFloat[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, 4, 4, 0,
GL_RED, GL_FLOAT, matrix2);

glBindTexture(GL_TEXTURE_2D, texFloat[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, 4, 4, 0,
GL_RED, GL_FLOAT, out);

glGenFramebuffers(1, &gp_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, gp_framebuffer);

glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, texFloat[2], 0);

glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);

glClampColor(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE);
glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE);
glClampColor(GL_CLAMP_READ_COLOR_ARB, GL_FALSE);

vert_sh = glCreateShader(GL_VERTEX_SHADER);
frag_sh = glCreateShader(GL_FRAGMENT_SHADER);

glShaderSource(vert_sh, 1, &vert_src, NULL);
glShaderSource(frag_sh, 1, &frag_src, NULL);

glCompileShader(vert_sh);
glCompileShader(frag_sh);

prog = glCreateProgram();

glAttachShader(prog, vert_sh);
glAttachShader(prog, frag_sh);

glLinkProgram(prog);

location[0] = glGetUniformLocation(prog, "tex");
location[1] = glGetUniformLocation(prog, "old");

glUniform1i(location[0], GL_TEXTURE0);
glUniform1i(location[1], GL_TEXTURE1);

glUseProgram(prog);Inside display callback:


glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texFloat[0]);

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texFloat[1]);

glBegin(GL_QUADS);

glMultiTexCoord2f(GL_TEXTURE0, 0.0, 0.0);
glVertex2f(0, 0);

glMultiTexCoord2f(GL_TEXTURE0, 1.0, 0.0);
glVertex2f(4, 0);

glMultiTexCoord2f(GL_TEXTURE0, 1.0, 1.0);
glVertex2f(4, 4);

glMultiTexCoord2f(GL_TEXTURE0, 0.0, 1.0);
glVertex2f(0, 4);

glEnd();Thanks for your help!

V-man
10-11-2005, 03:20 PM
This is wrong.



glUniform1i(location[0], GL_TEXTURE0);
glUniform1i(location[1], GL_TEXTURE1);
This is right.

glUniform1i(location[0], 0);
glUniform1i(location[1], 1);

Are you using calling glGetError at all?
You can solve most problems that way.

Ferenzzy
10-12-2005, 12:06 AM
Thanks for your help! I did not include any debug code but there is plenty of them in the original code.

Replacing GL_TEXTUREi with i wherever it occurs has the follwong effect: now only the texture bound to unit 1 works, texture bound to unit 0 does not work.

Replacing them only in the call to glUniform has no effect, i.e. same as if I use the symbolic constants.

So can anyone explain the meaning of the constants GL_TEXTUREi. According to the spec and the programming guide they refer to texture image unit i.

Thanks

Zulfiqar Malik
10-12-2005, 01:59 AM
GL_TEXTUREi refers to the i-th texture stage. Its quite simple really ... bind a texture to a particular stage using a combination of glActiveTexture(...) and glBindTexture(...) (Note: that by default i-th stage is not enabled so you must enable it using glEnable(...)). Furthermore, note that you must pass the stage index to glUniform1i(...) and not the logical GL_TEXTUREi constant(s).



uniform sampler2D tex;
uniform sampler2D old;

void main()
{
vec4 color = texture2D(tex, gl_TexCoord[0].st);
vec4 base = texture2D(old, gl_TexCoord[0].st);
gl_FragColor = base + color;
}
If you are trying to replicate the default modulating behavior then do
gl_FragColor = base * color;

Hope this helps.

Zulfiqar Malik
10-12-2005, 02:02 AM
@dronus - An optimization note. Swizzles are free (i.e. gl_TexCoord[0].xy) whereas casting is not! A compiler might optimize it, but one is better off doing something oneself, rather than depending on a compiler. Try to use swizzles whenever possible and they do get used quite a lot.

V-man
10-12-2005, 02:50 AM
Originally posted by Zulfiqar Malik:
Note: that by default i-th stage is not enabled so you must enable it using glEnable(...)No he doesn't because they are ignored. He is using shaders.

If you are using the fixed pipe, then you must enable the correct target and it's best to disable the others.
For example, enable GL_TEXTURE_2D and disable GL_TEXTURE_CUBE_MAP (if this was enabled before).

Ferenzzy
10-12-2005, 03:11 AM
V-man: You were absolutely correct! While loading uniforms the GL_TEXTUREi are not allowed. One has to use 0, 1, ...

I overlooked one line in the GL 2.0 spec. It reads "To load values into the uniform variables of the programm object that is CURRENTLY IN USE..." Placing the glUniform commands right after glUseProgram fixes this problem.

Thanks for your help!

dronus
10-12-2005, 04:07 AM
also it seems that the stages are expected "stacked", so just using stage 1, disabling/not using stage 0 is not what the driver like... sometimes.
gl specs sais nothing about that, but driver makers maybe think so.

and i have to enable the stages because im just using fragment, no vertex shading, so fixed-func vertex shader need to know about textures are there, eg. for pass and interpolate the tex coords etc. i think.

thanks to you all
Paul

Relic
10-12-2005, 05:17 AM
If you use a fragment program of any kind you don't need to enable any texture unit, because fragment programs work on texture image units. The fragment program knows which one to use, you told it by setting the samplers.
(I think I wrote this at least ten times on this forum now. ;) )

Mind the difference between
GL_MAX_TEXTURE_UNITS (fixed pipe, normally 4)
GL_MAX_TEXTURE_IMAGE_UNITS (programmable fragment pipe, normally 16(!))
GL_MAX_TEXTURE_COORDS (vertex attribute slots for MultiTexCoords, normally 8)
GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS (programmable vertex pipeline, normally 0 (ATI) or 4 (GeForce 6+7)

Note that the direct relation between texture coordinate attribute locations and texture units only exists for the fixed pipe. In the programmable pipeline you can calculate whatever you want and use as texture coordinate, that is why you don't need 16 texture coordinate attributes for 16 texture image units.

Relic
10-12-2005, 05:29 AM
Originally posted by Ferenzzy:
V-man: You were absolutely correct! While loading uniforms the GL_TEXTUREi are not allowed. One has to use 0, 1, ...
Major bug in your code: You must load the uniforms after you called glUseProgram()!
There is no program parameter in the glUniform() function so it can only be used on the currently active program.

kingjosh
10-12-2005, 08:49 AM
@dronus - An optimization note. Swizzles are free (i.e. gl_TexCoord[0].xy) whereas casting is not! A compiler might optimize it, but one is better off doing something oneself, rather than depending on a compiler. Try to use swizzles whenever possible and they do get used quite a lot. I would have to disagree with you - you've given advice that applies to a specific chip manufacturer. It is better to code naturally for all architectures and allow the compiler(s) to optimize. This is one of the advantages of GLSL! By catering to specific architecture limitations, your shader may run faster right now on that hardware at the cost of maintainability and possible performance degredation (relative to other hardware) as compiler(s) reach maturity.

Zulfiqar Malik
10-12-2005, 08:29 PM
Originally posted by kingjosh

I would have to disagree with you - you've given advice that applies to a specific chip manufacturer. It is better to code naturally for all architectures and allow the compiler(s) to optimize. This is one of the advantages of GLSL! By catering to specific architecture limitations, your shader may run faster right now on that hardware at the cost of maintainability and possible performance degredation (relative to other hardware) as compiler(s) reach maturity.

In case you don't know, swizzles are a part of the language and not some "add-on" feature provided by nVidia/ATi (or whatever manufacturer you are talking about). Swizzles were there in assembely as well. They have been a part of shaders ever since programmable hardware was introduced (dunno about the very early register combiners, but they were nVidia specific anyways!).

@V-man & Relic: Thanks for correcting me. I did know that texture stages don't need to be enabled while using fragment shaders, but its a practice i often follow because i usually provide fixed function fallbacks whenever possible.

kingjosh
10-13-2005, 08:47 AM
I'm aware that swizzles are part of the language, lol. I certainly didn't mean to infer they weren't. I was referring to "Swizzles are free (i.e. gl_TexCoord[0].xy) whereas casting is not!" which is a blanket statement you'd made that may not apply to all hardware. Some compilers may be smart enough to realize these are equivalent and optimize accordingly. My point was it shouldn't matter whether one uses a swizzle or vec2 constructor. The compiler should be able to parse both and write equivalent instructions to the GPU.

Tomy
10-17-2005, 03:01 AM
Hola,

I just wanted to note that I have experienced this multistrange multitexture problem for a couple of days now.. After a lot of trial and error , I followed you and swaped the order of binding the textures, and... it worked fine... :eek:

Thank you Dronus for sharing your wonderful experience.. and lets hope we have an explanation for such shader behaviour soon :cool: