<FORWARD>
struct FragmentListNode
{
    uint    next;
    float   depth;
    uint    color;
};

#define FL_NODE_LIST_NULL (0x0U)

float FL_PackDepthAndCoverage( float depth, uint coverage )
{
    return as_type<float>( (as_type<uint>( depth ) & 0xFFFFFFF0U) | coverage );
}

void FL_UnpackDepthAndCoverage( float packedDepthCovg, thread float& depth, thread uint& coverage )
{
    uint uiPackedDepthCovg = as_type<uint>( packedDepthCovg );
    depth = as_type<float>( uiPackedDepthCovg & 0xFFFFFFF0U );
    coverage = uiPackedDepthCovg & 0xFUL;
}


float4 FL_UnpackColor( uint packedInput )
{
    float4 unpackedOutput;
    uint4 p = uint4((packedInput & 0xFFU),
                    (packedInput >> 8U) & 0xFFU,
                    (packedInput >> 16U) & 0xFFU,
                    (packedInput >> 24U));

    unpackedOutput = ((float4)p) / 255;
    return unpackedOutput;
}

static constant uint mMaxListNodes = 10000000;

uint FL_PackColor( float4 unpackedInput )
{
    uint4 u = (uint4)(saturate( unpackedInput ) * 255 + 0.5);
    uint  packedOutput = (u.w << 24UL) | (u.z << 16UL) | (u.y << 8UL) | u.x;
    return packedOutput;
}

bool FL_AllocNode( device atomic_uint& nextNodeCounter, thread uint& newNodeAddress1D )
{
 // alloc a new node
    newNodeAddress1D = atomic_fetch_add_explicit( &nextNodeCounter, 1, memory_order_relaxed );

    // running out of memory?
    return newNodeAddress1D <= mMaxListNodes;
}

</FORWARD>

<FRAGMENT>
<ARGUMENTS>device atomic_uint* firstNodeIndex [[buffer(5)]], device FragmentListNode* nodeList [[buffer(3)]], device atomic_uint& nextNodeCounter [[buffer(4)]], constant uint& viewWidth [[buffer(6)]], depth2d<float> depthTexture [[texture(7)]]</ARGUMENTS>
<BODY>
//Process transparent pixel if it's depth is less than opaque pass depth
ushort2 pixelCoord = ushort2( IN.position.x, IN.position.y );
if( IN.position.z < depthTexture.read( pixelCoord ) )
{
	uint newNodeIndex;
	if( FL_AllocNode( nextNodeCounter, newNodeIndex) )
	{
		FragmentListNode node;
		node.color = FL_PackColor( OUT );
		node.depth = FL_PackDepthAndCoverage( IN.position.z, 0xfU );

		uint pixelIndex = pixelCoord.x + pixelCoord.y * viewWidth;
		
		// Insert a new node at the head of the list
		uint prevAddress = atomic_exchange_explicit( &firstNodeIndex[pixelIndex], newNodeIndex, memory_order_relaxed );
		node.next = prevAddress;
		nodeList[newNodeIndex] = node;
	}
}
</BODY>
</FRAGMENT>
