summaryrefslogtreecommitdiff
path: root/graphics/asymptote/base/shaders/sum3.glsl
blob: 4ee5203060b20d785ea1440b02b7e3411f2c70ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
layout(local_size_x=LOCALSIZE) in;

const uint groupSize=LOCALSIZE*BLOCKSIZE;

uniform uint final;

layout(binding=0, std430) buffer offsetBuffer
{
  uint maxDepth;
  uint offset[];
};

layout(binding=2, std430) buffer countBuffer
{
  uint maxSize;
  uint count[];
};

layout(binding=3, std430) buffer globalSumBuffer
{
  uint globalSum[];
};

layout(binding=8, std430) buffer feedbackBuffer
{
  uint size;
  uint fragments;
};

shared uint shuffle[groupSize+LOCALSIZE-1u];
shared uint groupSum[LOCALSIZE+1u];

void main()
{
  uint id=gl_LocalInvocationID.x;

// avoid bank conflicts and coalesce global memory accesses
  uint dataOffset=gl_WorkGroupID.x*groupSize+id;
  uint shuffleOffset=id/BLOCKSIZE+id;
  const uint stride=LOCALSIZE/BLOCKSIZE+LOCALSIZE;
  for(uint i=0u; i < BLOCKSIZE; i++)
    shuffle[shuffleOffset+i*stride]=count[dataOffset+i*LOCALSIZE];

  barrier();

  uint Offset=id*BLOCKSIZE+id;
  uint stop=Offset+BLOCKSIZE;

  uint sum=0u;
  for(uint i=Offset; i < stop; ++i)
    shuffle[i]=sum += shuffle[i];

  if(id == 0u)
    groupSum[0u]=0u;
  groupSum[id+1u]=sum;
  barrier();

  // Apply Hillis-Steele algorithm over all sums in workgroup
  for(uint shift=1u; shift < LOCALSIZE; shift *= 2u) {
    uint read;
    if(shift <= id)
      read=groupSum[id]+groupSum[id-shift];
    barrier();
    if(shift <= id)
      groupSum[id]=read;
    barrier();
  }

  uint groupOffset=globalSum[gl_WorkGroupID.x];
  for(uint i=0u; i < BLOCKSIZE; ++i)
    offset[dataOffset+i*LOCALSIZE]=shuffle[shuffleOffset+i*stride]+
      groupSum[(i*LOCALSIZE+id)/BLOCKSIZE]+groupOffset;

  uint diff=final-dataOffset;
  if(diff < groupSize && diff % LOCALSIZE == 0) {
    size=maxDepth;
    maxDepth=0u;
    fragments=offset[final+1u]=offset[final];
  }
}