ATI_fragment_shader dependant texture read

Hi,

Using the GL_ATI_fragment_shader extension, is it allowed to do that :

glBeginFragmentShaderATI();

// Pass 1
glPassTexCoordATI(GL_REG_0_ATI, GL_TEXTURE0_ARB, GL_SWIZZLE_STR_ATI);
glSampleMapATI(GL_REG_1_ATI, GL_TEXTURE1_ARB, GL_SWIZZLE_STR_ATI);

// r2 = texcoord0 + offset_given_by_color_of_texture1
glColorFragmentOp2ATI(GL_ADD_ATI, GL_REG_2_ATI, GL_NONE, GL_NONE,
GL_REG_0_ATI, GL_NONE, GL_NONE,
GL_REG_1_ATI, GL_NONE, GL_NONE);

// Pass 2
glSampleMapATI(GL_REG_0_ATI, GL_REG_2_ATI, GL_SWIZZLE_STR_ATI);

// final_rgb = texture0(offset) * primary
glColorFragmentOp3ATI(GL_MUL_ATI, GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
GL_REG_0_ATI, GL_NONE, GL_NONE,
GL_PRIMARY_COLOR_ARB, GL_NONE, GL_NONE);

// final_alpha = 1
glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_SATURATE_BIT_ATI,
GL_ZERO, GL_NONE, GL_COMP_BIT_ATI);

glEndFragmentShaderATI();

The idea is to get a sample color from texture1 and use it as a texture coordinate offset for texture0.
This does not work with Radeon8500 and Radeon9700, so I would like if it is an allowed operation or if I’m mis-using the functionality.

Such effect is possible with the ATI_texture_envmap_bumpmap extension, so I think the hardware is capable of doing it in a fragment shader.

Anyway, the spec does not mention that such operation is forbidden for eg odd/even texture units as it is for ATI_texture_envmap_bumpmap.

BTW, texture0 and texture1 are 2D textures here.

TIA

You need to use glPassTexCoordATI in the beginning of phase 2 to get the register contents from the first phase into the second phase. The exact details are outlined in the extension spec.

Btw, PassTexCoord is always a nop, so it won’t cost you any performance to do this.

In the second pass I do only need register #0, so there’s no need for me to pass register #1. Anyway, I’ve already tried it ! It was one of the first things I tried. Unfortunately, there was no difference at all.

Originally posted by zeckensack:
Btw, PassTexCoord is always a nop, so it won’t cost you any performance to do this.

I thought only the first PassTexCoord or SampleMap of each pass was “free”.
I’ve read the spec again :
“The first instructions specified in each pass of a shader are “free”
instructions in that they don’t count against the 8 instructions
available in each pass.”
… and now noticed differently why there was an ‘s’ in the end of ‘instructions’. I thought the ‘s’ was meant to show that two pass would yield two free instructions, but in fact it’s more than that. Well, you’re right. Thanks for clarifying that point

Sorry, I didn’t look hard enough hrmpf.

In fact, I now think your fragment shader code is perfectly right.

Let me restate what I see:
You have a base map bound to GL_TEXTURE0_ARB
You have an offset map bound to GL_TEXTURE1_ARB

You sample the base map with the coords resulting from the sum of the interpolated base map coords and the offset map sample.
Then you modulate with primary fragment color and set alpha to fully opaque.

Looks right.

Originally posted by vincoof:
I thought only the first PassTexCoord or SampleMap of each pass was “free”.
I’ve read the spec again :
“The first instructions specified in each pass of a shader are “free”
instructions in that they don’t count against the 8 instructions
available in each pass.”
… and now noticed differently why there was an ‘s’ in the end of ‘instructions’. I thought the ‘s’ was meant to show that two pass would yield two free instructions, but in fact it’s more than that. Well, you’re right. Thanks for clarifying that point

Huh?
Do you mean this was it? Now I’m confused …

The code looks correct to me at first glance. Are you getting any gl errors from specifying the program? Also, how is the output wrong?

-Evan

One other question, you do realize that the values fetched in the first pass will be 0-1, and as a result will always be moving things positively by up to a full texture width?

Also, have you tried rendering just the offset texture to make sure it is complete? (correct mipmap filter and so on) If it isn’t complete, I would expect bad results.

-Evan

You sample the base map with the coords resulting from the sum of the interpolated base map coords and the offset map sample.
Then you modulate with primary fragment color and set alpha to fully opaque.

That is exactly that.

Do you mean this was it? Now I’m confused …

I don’t mean I corrected my problem. I meant you showed me that all PassTexCoord and SampleMap counted for “free”, whereas I thought that “only the first instruction of each pass counted for free”.

Are you getting any gl errors from specifying the program? Also, how is the output wrong?

No gl error at all.
The output looks like there is a constant offset. I forgot to tell that this offset texture is sphere mapped (ie texture1 is using GL_SPHERE_MAP). Can it be a problem ?

One other question, you do realize that the values fetched in the first pass will be 0-1, and as a result will always be moving things positively by up to a full texture width?

Yes I know. Originally I used a complex offset (more “clever”) and because it didn’t work I tried with that simple shader and the result is the same : a constant offset is applied. Now I prefer posting the simple shader which is more clear, but I can post the complex shader if you want.

Also, have you tried rendering just the offset texture to make sure it is complete?

It is complete. I know because I can “see” the offset texture on my surface when I replace the second pass with :

// Pass 2
glSampleMapATI(GL_REG_0_ATI, GL_REG_2_ATI, GL_SWIZZLE_STR_ATI);
glPassTexCoordATI(GL_REG_1_ATI, GL_REG_1_ATI, GL_SWIZZLE_STR_ATI);

// final_rgb = texture1
glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
GL_REG_1_ATI, GL_NONE, GL_NONE);

// final_alpha = 1
glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_SATURATE_BIT_ATI,
GL_ZERO, GL_NONE, GL_COMP_BIT_ATI);

Thanks so far for all your answers.

[This message has been edited by vincoof (edited 02-12-2003).]

The code looks perfectly fine, i think the problem comes from somewhere else.

I’m aware of some issues when you need a different swizzle parameter for the same texture unit in the first and second phase. Typically, it happens when you use linear tex coords generation to project a water reflection texture to screen space, but it’s not the case here…

Could it be a driver issue ? I got plenty with < catalyst 3.0 drivers, although i must admit i’ve yet to find a bug with the new drivers.

Could it be a precision problem ? You’re not scaling the #1 offset; so basically you can add a value up to 1.0 to the tex coords #0.

Is your texture #0 clamped ?

The offset values, since they are sampled from a color map, are all in the [0;1] range. You cannot get a negative offset; so all your offsets will go in the same “direction”, if you see what i mean, although they shouldn’t be constant. If you want negative offsets, you need to encode your offsets from [-1;1] to [0;1], then remap it to [-1;1] inside the pixel shader after the sampling, using bias and 2x flags.

What else could it be ? Humm… it probably won’t change anything, but try doing your dependant read from the same interpolator than tmu; ie. sample tex0 with reg0 instead of reg2. The code would be modified like that:

// r2 = texcoord0 + offset_given_by_color_of_texture1
glColorFragmentOp2ATI(GL_ADD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,GL_REG_0_ATI, GL_NONE, GL_NONE,GL_REG_1_ATI, GL_NONE, GL_NONE);

// Pass 2
glSampleMapATI(GL_REG_0_ATI, GL_REG_0_ATI, GL_SWIZZLE_STR_ATI);

// final_rgb = texture0(offset) * primary

Hope that helps…

Y.

[This message has been edited by Ysaneya (edited 02-13-2003).]

Could it be a driver issue ? I got plenty with < catalyst 3.0 drivers

I’ve dowloaded the latest driver for Radeon8500 and Radeon9700 and neither of them work. Moreover with Radeon9700 the problem is even worse because the dependant texture read is not performed : instead I see the “texture coordinates” mapped on the surface, ie a mix between red and green colors.

Is your texture #0 clamped ?

No it is set to GL_REPEAT in both S and T coordinates.

The offset values, since they are sampled from a color map, are all in the [0;1] range. You cannot get a negative offset; so all your offsets will go in the same “direction”, if you see what i mean, although they shouldn’t be constant.

I see what you mean, but like I’ve written in my latest post I once used a more “clever” offset that could be negative, scaled, etc but it didn’t work either.

What else could it be ? Humm… it probably won’t change anything, but try doing your dependant read from the same interpolator than tmu; ie. sample tex0 with reg0 instead of reg2.

Already thought of it but still didn’t work

I remembered something about special behaviour of primary color in 2 pass shaders, so I checked the spec,

Taken from ATI_fragment_shader spec:

The <argN> parameter specifies the source argument. The source can
come from REG_x_ATI, CON_x_ATI, ZERO, ONE, PRIMARY_COLOR_ARB, or
SECONDARY_INTERPOLATOR_ATI. Note that in a two-pass shader,
PRIMARY_COLOR_ARB and SECONDARY_INTERPOLATOR_ATI cannot be used in
the first pass of the shader.

Hmm, I just noticed it said “first pass”. So that can’t be the problem…sorry .

Vincoof, i tried your shader and i have the same behavior. I’ll have a closer look this afternoon to see if i can spot the bug… (assuming it’s not a driver bug!).

Y.

Ok, i did some other tests:

  • Sampling tex #1 instead of tex #0 in the second pass works.

  • If you use another tmu #2, on which you bind the same texture than #0, and you sample that one in the second pass, it works too.

To which i conclude: dependant texture reads in the second pass do not work if you passed the texture coordinate of the corresponding interpolator in the first pass.

I don’t think it’s the normal behavior, that’s probably a driver bug. What about sending a report to devrel@ati.com ?

Y.

PH: I wanted to use secondary color in the first pass, but since it’s forbidden I used a different shader. That is a good thing to point out, anyway.

Ysaneya: Wow, you even wrote a program that tests the shader ? Thank you so much for looking into it that deeply !
I tried your tests and both work. I also think the code is correct in either case, so it could be a driver issue.
I’ve written a little program that shows explicitly the problem and I’m about to send it to devrel@ati.com … maybe you would like to take a look at it before ? I can email it.

You can mail it if you want (admin@fl-tw.com) but since i’ve directly cut & pasted your code into mine, i do not expect to see a lot of differences :slight_smile:

I’ve read the specif. twice and i still see no reason why this shader shouldn’t work.

Y.

Sampling tex #1 instead of tex #0 in the second pass works.

Isn’t he sampling from tex #2 ? It’s been a while since I’ve used ATI_fragment_shader but as far as I remember, a line such as

// Pass 2glSampleMapATI(GL_REG_0_ATI, GL_REG_2_ATI, GL_SWIZZLE_STR_ATI);

will use Reg2 to lookup (r,g,b) from tex #2 and store the result in Reg0.

Or does glSampleMapATI(GL_REG_0_ATI, GL_REG_2_ATI, GL_SWIZZLE_STR_ATI);

mean use Reg2 to lookup (r,g,b) from tex #0 and store the result in Reg0 ? The spec is a bit unclear about that, but from looking at some sample code, it seems to be this way.

glSampleMapATI(GL_REG_x_ATI, GL_REG_y_ATI, …) will sample texture #x with coords #y and put the result into reg #x. But i agree the spec. is not very clear; you have to read it many times to understand it…

Y.