layout(binding=0, std430) buffer offsetBuffer { uint offset[]; }; #ifdef GPUINDEXING uniform uint elements; uniform uint offset2; uniform uint m1; uniform uint m2; uniform uint r; layout(binding=2, std430) buffer localSumBuffer { uint localSum[]; }; layout(binding=3, std430) buffer globalSumBuffer { uint globalSum[]; }; #define count offset #else layout(binding=2, std430) buffer countBuffer { uint count[]; }; #endif 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 { uint maxSize; 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 uint size=count[element]; #ifndef GPUCOMPRESS if(size == 0u) { if(OpaqueDepth != 0.0) opaqueDepth[pixel]=0.0; discard; } #endif outColor=OpaqueDepth != 0.0 ? opaqueColor[pixel] : background; #ifdef GPUINDEXING uint p=element < r*(m1+1u) ? element/(m1+1u) : (element-r)/m1; uint listIndex=localSum[p]+localSum[offset2+p/m2]+globalSum[p/(m2*m2)]+ offset[elements+element]; #else 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(maxSize,size); #ifndef GPUINDEXING count[0]=maxSize; #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; }