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; }