PDA

View Full Version : FBOs and depth peeling



chlorinedreams
10-01-2008, 07:39 PM
Hey, I am attempting to do something similar to depth peeling, but require collection of information from up to 6 peels. In order to not be required to render the whole scene 6 times, I was attempting to sort the depth data in the shader using FBOs. Unfortunately, I am not getting the results expected, essentially it looks like only one peel is getting calculated. It seems as though any attempt to perform read/write operations from/to the FBO data will not work.

Does anyone know if I should be able to read and write to multiple textures bound to an FBO? (I skimmed the FBO doc, and saw nothing, and am afraid that it may be one of those GLSL/FBO/Vendor gray areas).

FWIW. My glsl code posted below to show what I am attempting to do. (And yes I know the depth calculation isn't correct, but they should be relative, and therefore correct enough till I get past this hump).

uniform sampler2D tex0; // << { Depth0, Depth1, Depth2, Depth3 } >>
uniform sampler2D tex1; // << { Depth4, Depth5, Depth6, NULL } >>
uniform sampler2D tex2; // << { NormX0, NormY0, NormX1, NormY1 } >>
uniform sampler2D tex3; // << { NormX2, NormY2, NormX3, NormY3 } >>
uniform sampler2D tex4; // << { NormX4, NormY4, NormX4, NormY4 } >>
uniform sampler2D tex5; // << { Mater0, Mater1, Mater2, Mater3 } >>
uniform sampler2D tex6; // << { Mater4, Mater5, Mater6, NULL } >>

// Physical properties fields
uniform int Material;
varying vec3 Normal3;
varying vec4 Coords;

void main( void )
{
float CameraFarClipDistance = 100.0;
float CameraNearClipDistance = 0.5;

float Depth = length( Coords.xyz ) / CameraFarClipDistance;

vec4 TexData0 = texture2D( tex0, gl_TexCoord[0].st );
vec4 TexData1 = texture2D( tex1, gl_TexCoord[0].st );
vec4 TexData2 = texture2D( tex2, gl_TexCoord[0].st );
vec4 TexData3 = texture2D( tex3, gl_TexCoord[0].st );
vec4 TexData4 = texture2D( tex4, gl_TexCoord[0].st );
ivec4 TexData5 = texture2D( tex5, gl_TexCoord[0].st );
ivec4 TexData6 = texture2D( tex6, gl_TexCoord[0].st );

float NormX = Normal3.x;
float NormY = Normal3.y;

float Epsilon = 1.0/CameraFarClipDistance;

if( (Depth < TexData0.x) || (TexData0.x < Epsilon ) )
{
// Replacing the 0th slot
vec4 TexData00 = vec4( Depth, TexData0.xyz );
vec4 TexData01 = vec4( TexData0.w, TexData1.x, TexData1.y, 0.0 );

vec4 TexData02 = vec4( NormX, NormY, TexData2.xy );
vec4 TexData03 = vec4( TexData2.zw, TexData3.xy );
vec4 TexData04 = vec4( TexData3.zw, TexData4.xy );

ivec4 TexData05 = vec4( Material, TexData5.xyz );
ivec4 TexData06 = vec4( TexData5.w, TexData6.x, TexData6.y, 0 );

gl_FragData[0] = TexData00;
gl_FragData[1] = TexData01;
gl_FragData[2] = TexData02;
gl_FragData[3] = TexData03;
gl_FragData[4] = TexData04;
gl_FragData[5] = TexData05;
gl_FragData[6] = TexData06;
}
else if( (Depth < TexData0.y) || (TexData0.y < Epsilon) )
{
// Replacing the 1st slot
vec4 TexData00 = vec4( TexData0.x, Depth, TexData0.yz );
vec4 TexData01 = vec4( TexData0.w, TexData1.x, TexData1.y, 0.0 );

vec4 TexData02 = vec4( TexData2.xy, NormX, NormY );
vec4 TexData03 = vec4( TexData2.zw, TexData3.xy );
vec4 TexData04 = vec4( TexData3.zw, TexData4.xy );

ivec4 TexData05 = vec4( TexData5.x, Material, TexData5.yz );
ivec4 TexData06 = vec4( TexData5.w, TexData6.x, TexData6.y, 0 );

gl_FragData[0] = TexData00;
gl_FragData[1] = TexData01;
gl_FragData[2] = TexData02;
gl_FragData[3] = TexData03;
gl_FragData[4] = TexData04;
gl_FragData[5] = TexData05;
gl_FragData[6] = TexData06;
}
else if( (Depth < TexData0.z) || (TexData0.y < Epsilon) )
{
// Replacing the 2nd slot
vec4 TexData00 = vec4( TexData0.xy, Depth, TexData0.z );
vec4 TexData01 = vec4( TexData0.w, TexData1.x, TexData1.y, 0.0 );

vec4 TexData03 = vec4( NormX, NormY, TexData3.xy );
vec4 TexData04 = vec4( TexData3.zw, TexData4.xy );

ivec4 TexData05 = vec4( TexData5.xy, Material, TexData5.z );
ivec4 TexData06 = vec4( TexData5.w, TexData6.x, TexData6.y, 0 );

gl_FragData[0] = TexData00;
gl_FragData[1] = TexData01;
gl_FragData[3] = TexData03;
gl_FragData[4] = TexData04;
gl_FragData[5] = TexData05;
gl_FragData[6] = TexData06;
}
else if( (Depth < TexData0.w) || (TexData0.w < Epsilon) )
{
// Replacing the 3rd slot
vec4 TexData00 = vec4( TexData0.xyz, Depth );
vec4 TexData01 = vec4( TexData0.w, TexData1.x, TexData1.y, 0.0 );

vec4 TexData03 = vec4( TexData3.xy, NormX, NormY );
vec4 TexData04 = vec4( TexData3.zw, TexData4.xy );

ivec4 TexData05 = vec4( TexData5.xyz, Material );
ivec4 TexData06 = vec4( TexData5.w, TexData6.x, TexData6.y, 0 );

gl_FragData[0] = TexData00;
gl_FragData[1] = TexData01;
gl_FragData[3] = TexData03;
gl_FragData[4] = TexData04;
gl_FragData[5] = TexData05;
gl_FragData[6] = TexData06;
}
else if( (Depth < TexData1.x) || (TexData1.x < Epsilon) )
{
// Replacing the 4th slot
vec4 TexData01 = vec4( Depth, TexData1.x, TexData1.y, 0.0 );

vec4 TexData04 = vec4( NormX, NormY, TexData4.xy );

ivec4 TexData06 = vec4( Material, TexData6.x, TexData6.y, 0 );

gl_FragData[1] = TexData01;
gl_FragData[4] = TexData04;
gl_FragData[6] = TexData06;
}
else if( (Depth < TexData1.y) || (TexData1.y < Epsilon) )
{
// Replacing the 5th slot
vec4 TexData01 = vec4( TexData1.x, Depth, TexData1.y, 0.0 );

vec4 TexData04 = vec4( TexData4.xy, NormX, NormY );

ivec4 TexData06 = vec4( TexData6.x, Material, TexData6.y, 0 );

gl_FragData[1] = TexData01;
gl_FragData[4] = TexData04;
gl_FragData[6] = TexData06;
}
else if( (Depth < TexData1.z) || (TexData1.z < Epsilon) )
{
// Replacing the 6th slot
vec4 TexData01 = vec4( TexData1.x, TexData1.y, Depth, 0.0 );

ivec4 TexData06 = vec4( TexData6.x, TexData6.y, Material, 0 );

gl_FragData[1] = TexData01;
gl_FragData[6] = TexData06;
}
else
{
discard;
}
}

A. Masserann
10-03-2008, 12:53 PM
It is theorically not possible to read and write buffers/textures at the same time since it could lead to strange behaviours.

I've heard that it is possible on some cards but it is non-standard.

You'll have to use separate depth textures ...

Timothy Farrar
10-04-2008, 11:13 AM
If you want to read from a texture which is also bound to a framebuffer, there are many factors which make this non-standard. First, framebuffer writes are most likely delayed in the output merger stage (ROP) do to write combined caching. Second, after framebuffer blocks/cachelines get written back to memory, one would have to force invalidate the texture cache hierarchy in order to actually fetch results written to the framebuffer. Third, the framebuffer might be stored with compression or in a separate memory space (say like the 360s EDRAM), and would actually require a separate resolve to memory before a texture fetch could work.

So while you might be able to get away with this sort of thing now on some hardware, with some specific framebuffer types, if you wait long enough before reading, and in between do enough texture fetches to manually effectively evict texture cache lines which are of memory previously written, this sort of thing really isn't portable, and might not even work on future hardware (what if they add framebuffer compression for 16bit/channel formats?)...