layout(binding=0, std430) buffer offsetBuffer
{
uint maxDepth;
uint offset[];
};
layout(binding=2, std430) buffer countBuffer
{
uint maxSize;
uint count[];
};
layout(binding=4, std430) buffer fragmentBuffer
{
vec4 fragment[];
};
layout(binding=5, std430) buffer depthBuffer
{
float depth[];
};
layout(binding=6, std430) buffer opaqueBuffer {
vec4 opaqueColor[];
};
layout(binding=7, std430) buffer opaqueDepthBuffer {
float opaqueDepth[];
};
#ifdef GPUCOMPRESS
layout(binding=1, std430) buffer indexBuffer
{
uint index[];
};
#define INDEX(pixel) index[pixel]
#define COUNT(pixel) index[pixel]
#else
#define INDEX(pixel) pixel
#define COUNT(pixel) count[pixel]
#endif
out vec4 outColor;
uniform uint width;
uniform vec4 background;
vec4 blend(vec4 outColor, vec4 color)
{
return mix(outColor,color,color.a);
}
void main()
{
uint pixel=uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x);
float OpaqueDepth=opaqueDepth[pixel];
uint element=INDEX(pixel);
#ifdef GPUCOMPRESS
if(element == 0u) {
if(OpaqueDepth != 0.0)
opaqueDepth[pixel]=0.0;
discard;
}
#endif
#ifdef GPUINDEXING
uint listIndex=offset[element];
uint size=offset[element+1u]-listIndex;
#else
uint size=count[element];
#endif
#ifndef GPUCOMPRESS
if(size == 0u) {
if(OpaqueDepth != 0.0)
opaqueDepth[pixel]=0.0;
discard;
}
#endif
outColor=OpaqueDepth != 0.0 ? opaqueColor[pixel] : background;
#ifndef GPUINDEXING
uint listIndex=offset[element]-size;
#endif
uint k=0u;
if(OpaqueDepth != 0.0)
while(k < size && depth[listIndex+k] >= OpaqueDepth)
++k;
uint n=size-k;
// Sort the fragments with respect to descending depth
if(n <= ARRAYSIZE) {
if(n == 1)
outColor=blend(outColor,fragment[listIndex+k]);
else if(n > 0) {
struct element {
uint index;
float depth;
};
element E[ARRAYSIZE];
E[0]=element(k,depth[listIndex+k]);
uint i=1u;
while(++k < size) {
float d=depth[listIndex+k];
if(OpaqueDepth != 0.0) {
while(k < size && d >= OpaqueDepth) {
++k;
d=depth[listIndex+k];
}
if(k == size) break;
}
uint j=i;
while(j > 0u && d > E[j-1u].depth) {
E[j]=E[j-1u];
--j;
}
E[j]=element(k,d);
++i;
}
for(uint j=0u; j < i; ++j)
outColor=blend(outColor,fragment[listIndex+E[j].index]);
}
if(OpaqueDepth != 0.0)
opaqueDepth[pixel]=0.0;
} else {
atomicMax(maxDepth,size);
#ifndef GPUINDEXING
maxSize=maxDepth;
#endif
for(uint i=k+1u; i < size; i++) {
vec4 temp=fragment[listIndex+i];
float d=depth[listIndex+i];
uint j=i;
while(j > 0u && d > depth[listIndex+j-1u]) {
fragment[listIndex+j]=fragment[listIndex+j-1u];
depth[listIndex+j]=depth[listIndex+j-1u];
--j;
}
fragment[listIndex+j]=temp;
depth[listIndex+j]=d;
}
uint stop=listIndex+size;
if(OpaqueDepth == 0.0)
for(uint i=listIndex+k; i < stop; i++)
outColor=blend(outColor,fragment[i]);
else {
for(uint i=listIndex+k; i < stop; i++) {
if(depth[i] < OpaqueDepth)
outColor=blend(outColor,fragment[i]);
}
opaqueDepth[pixel]=0.0;
}
}
COUNT(pixel)=0u;
}