PDA

View Full Version : ATI_fragment_shader dependant texture read



vincoof
02-12-2003, 11:02 AM
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

zeckensack
02-12-2003, 11:11 AM
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.

vincoof
02-12-2003, 11:25 AM
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.

vincoof
02-12-2003, 11:36 AM
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 http://www.opengl.org/discussion_boards/ubb/smile.gif

zeckensack
02-12-2003, 11:50 AM
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.

zeckensack
02-12-2003, 11:51 AM
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 http://www.opengl.org/discussion_boards/ubb/smile.gifHuh?
Do you mean this was it? Now I'm confused ... http://www.opengl.org/discussion_boards/ubb/confused.gif

ehart
02-12-2003, 12:11 PM
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

ehart
02-12-2003, 12:18 PM
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

vincoof
02-12-2003, 12:58 PM
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).]

Ysaneya
02-13-2003, 01:08 AM
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).]

vincoof
02-13-2003, 01:35 AM
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 http://www.opengl.org/discussion_boards/ubb/smile.gif but still didn't work http://www.opengl.org/discussion_boards/ubb/frown.gif

PH
02-13-2003, 02:28 AM
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.

PH
02-13-2003, 02:30 AM
Hmm, I just noticed it said "first pass". So that can't be the problem...sorry http://www.opengl.org/discussion_boards/ubb/smile.gif.

Ysaneya
02-13-2003, 03:32 AM
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.

Ysaneya
02-13-2003, 03:59 AM
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.

vincoof
02-13-2003, 04:33 AM
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.

Ysaneya
02-13-2003, 04:53 AM
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 :)

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

Y.

PH
02-13-2003, 05:00 AM
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.

PH
02-13-2003, 05:13 AM
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.

Ysaneya
02-13-2003, 05:21 AM
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.

PH
02-13-2003, 05:30 AM
I just re-read that relevant part of the spec and it seems you could use coords #x to sample texture #y in the first pass as well. Interesting http://www.opengl.org/discussion_boards/ubb/smile.gif. I've always matched textures to texcoords, it's a lot more flexible than I thought.

Edit: Hmmm, no. I think I'll just go read it a couple more times http://www.opengl.org/discussion_boards/ubb/smile.gif.

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

vincoof
02-13-2003, 06:04 AM
I agree this point is not very clear, but once you read it s-l-o-w-l-y you get it.


I just re-read that relevant part of the spec and it seems you could use coords #x to sample texture #y in the first pass as well.
Yes it is possible using :


glSampleMapATI(GL_REG_y_ATI, GL_TEXTURE_x_ARB, ...)

PH
02-13-2003, 06:10 AM
Are you sure ? I read that part of the spec a few more times and it appears that,

glSampleMapATI(GL_REG_x_ATI, GL_TEXTUREy_ARB, GL_SWIZZLE_STR_ATI);

will sample texture #y using coords #y and store the result in reg #x.

Edit: After giving it some some thought, it all does seem clear and logical now.

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

vincoof
02-13-2003, 06:29 AM
I read the spec again and I think I'm right.



The entry point:

void SampleMapATI (uint dst, uint interp, enum swizzle);

specifies that the value present in the texture data bound on the
unit associated with <dst> will be written to that register. A
value for <dst> of REG_x_ATI means that TEXTUREx_ARB will be
sampled, and the result written to REG_x_ATI. The <interp>
parameter specifies which texture coordinate interpolator is used to
sample the map. A value of REG_x_ATI for <interp> in the second
pass of a two-pass shader will do dependent texture read sampling
using the value in register x. Otherwise, specifying TEXTUREx_ARB
will sample the map using the texture coordinates on unit x.


The text "A value for <dst> of REG_x_ATI means that TEXTUREx_ARB will be sampled, and the result written to REG_x_ATI" means that the <dst> register always samples the texture unit which number is defined by the register number.

The text "Otherwise, specifying TEXTUREx_ARB will sample the map using the texture coordinates on unit x" means that the texture coordinates on unit x is used, it does *not* mean that a texel is sampled from unit x.

PH
02-13-2003, 06:38 AM
Ahhh yes, that appears to be correct. You're right, it does say sample the map using texcoords from unit x, where the would mean the texture data bound on the unit associated with <dst>. Crystal clear http://www.opengl.org/discussion_boards/ubb/smile.gif.

Perhaps the ATI driver guys have problems reading the spec too, as your shader should work.

Well, the 8500 is more flexible than I thought. Thanks for the info vincoof and Ysaneya.


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