OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
drawclusters.cpp
Go to the documentation of this file.
1#include "drawclusters.h"
2#include "shaders.h"
3
6
7using namespace Tempest;
8
10 scratch.header.reserve(1024);
11 scratch.patch .reserve(1024);
12 }
13
16
17uint32_t DrawClusters::alloc(const PackedMesh::Cluster* cx, size_t firstMeshlet, size_t meshletCount, uint16_t bucketId, uint16_t commandId) {
18 if(commandId==uint16_t(-1))
19 return uint32_t(-1);
20
21 const auto ret = implAlloc(meshletCount);
22 for(size_t i=0; i<meshletCount; ++i) {
23 Cluster c;
24 c.pos = cx[i].pos;
25 c.r = cx[i].r;
26 c.bucketId = bucketId;
27 c.commandId = commandId;
28 c.firstMeshlet = uint32_t(firstMeshlet + i);
29 c.meshletCount = 1;
30 c.instanceId = uint32_t(-1);
31
32 clusters[ret+i] = c;
33 }
34
35 clustersDurty.resize((clusters.size() + 32 - 1)/32);
36 markClusters(ret, meshletCount);
37 return uint32_t(ret);
38 }
39
40uint32_t DrawClusters::alloc(const Bucket& bucket, size_t firstMeshlet, size_t meshletCount, uint16_t bucketId, uint16_t commandId) {
41 const auto ret = implAlloc(1);
42
43 Cluster& c = clusters[ret];
44 if(bucket.staticMesh!=nullptr)
45 c.r = bucket.staticMesh->bbox.rConservative + bucket.mat.waveMaxAmplitude; else
46 c.r = bucket.animMesh->bbox.rConservative;
47 c.bucketId = bucketId;
48 c.commandId = commandId;
49 c.firstMeshlet = uint32_t(firstMeshlet);
50 c.meshletCount = uint32_t(meshletCount);
51 c.instanceId = uint32_t(-1);
52
53 clustersDurty.resize((clusters.size() + 32 - 1)/32);
54 markClusters(ret, 1);
55 return uint32_t(ret);
56 }
57
58void DrawClusters::free(uint32_t id, uint32_t numCluster) {
59 for(size_t i=0; i<numCluster; ++i) {
60 clusters[id + i] = Cluster();
61 clusters[id + i].r = -1;
62 clusters[id + i].meshletCount = 0;
63 markClusters(id + i);
64 }
65
66 Range r = {id, id+numCluster};
67 auto at = std::lower_bound(freeList.begin(),freeList.end(),r,[](const Range& l, const Range& r){
68 return l.begin<r.begin;
69 });
70 at = freeList.insert(at,r);
71 auto next = at+1;
72 if(next!=freeList.end() && at->end==next->begin) {
73 next->begin = at->begin;
74 at = freeList.erase(at);
75 }
76 if(at!=freeList.begin() && at->begin==(at-1)->end) {
77 auto prev = (at-1);
78 prev->end = at->end;
79 at = freeList.erase(at);
80 }
81 }
82
83bool DrawClusters::commit(Encoder<CommandBuffer>& cmd, uint8_t fId) {
84 if(!clustersDurtyBit)
85 return false;
86 clustersDurtyBit = false;
87
88 std::atomic_thread_fence(std::memory_order_acquire);
89 size_t csize = clusters.size()*sizeof(clusters[0]);
90 csize = (csize + 0xFFF) & size_t(~0xFFF);
91
92 auto& device = Resources::device();
93 if(clustersGpu.byteSize() == csize) {
94 patchClusters(cmd, fId);
95 return false;
96 }
97
98 Resources::recycle(std::move(clustersGpu));
99 clustersGpu = device.ssbo(Tempest::Uninitialized, csize);
100 clustersGpu.update(clusters);
101 std::fill(clustersDurty.begin(), clustersDurty.end(), 0x0);
102 return true;
103 }
104
105size_t DrawClusters::implAlloc(size_t count) {
106 size_t bestFit = size_t(-1), bfDiff = size_t(-1);
107 for(size_t i=0; i<freeList.size(); ++i) {
108 auto f = freeList[i];
109 auto sz = (f.end - f.begin);
110 if(sz==count) {
111 freeList.erase(freeList.begin()+int(i));
112 return f.begin;
113 }
114 if(sz<count)
115 continue;
116 if(sz-count < bfDiff)
117 bestFit = i;
118 }
119
120 if(bestFit != size_t(-1)) {
121 auto& f = freeList[bestFit];
122 f.end -= count;
123 return f.end;
124 }
125
126 size_t ret = clusters.size();
127 clusters.resize(clusters.size() + count);
128 return ret;
129 }
130
131void DrawClusters::patchClusters(Encoder<CommandBuffer>& cmd, uint8_t fId) {
132 std::vector<uint32_t>& header = scratch.header;
133 std::vector<Cluster>& patch = scratch.patch;
134
135 header.clear();
136 patch.clear();
137
138 for(size_t i=0; i<clustersDurty.size(); ++i) {
139 if(clustersDurty[i]==0x0)
140 continue;
141 const uint32_t mask = clustersDurty[i];
142 clustersDurty[i] = 0x0;
143
144 for(size_t r=0; r<32; ++r) {
145 if((mask & (1u<<r))==0)
146 continue;
147 size_t idx = i*32 + r;
148 if(idx>=clusters.size())
149 continue;
150 patch.push_back(clusters[idx]);
151 header.push_back(uint32_t(idx));
152 }
153 }
154
155 if(header.empty())
156 return;
157
158 auto& device = Resources::device();
159 auto& p = this->patch[fId];
160
161 if(header.size()*sizeof(header[0]) < p.indices.byteSize()) {
162 p.indices.update(header);
163 } else {
164 p.indices = device.ssbo(BufferHeap::Upload, header);
165 }
166
167 if(patch.size()*sizeof(patch[0]) < p.data.byteSize()) {
168 p.data.update(patch);
169 } else {
170 p.data = device.ssbo(BufferHeap::Upload, patch);
171 }
172
173 const uint32_t count = uint32_t(header.size());
174 cmd.setFramebuffer({});
175 cmd.setBinding(0, clustersGpu);
176 cmd.setBinding(1, p.data);
177 cmd.setBinding(2, p.indices);
178 cmd.setPushData(count);
179 cmd.setPipeline(Shaders::inst().clusterPatch);
180 cmd.dispatchThreads(count);
181 }
182
183void DrawClusters::markClusters(size_t id, size_t count) {
184 for(size_t i=0; i<count; ++i) {
185 static_assert(sizeof(std::atomic<uint32_t>)==sizeof(uint32_t));
186 auto& bits = clustersDurty[id/32];
187 reinterpret_cast<std::atomic<uint32_t>&>(bits).fetch_or(1u << (id%32), std::memory_order_relaxed);
188 id++;
189 }
190 clustersDurtyBit.store(true);
191 }
Bounds bbox
Definition animmesh.h:28
float rConservative
Definition bounds.h:24
bool commit(Tempest::Encoder< Tempest::CommandBuffer > &cmd, uint8_t fId)
uint32_t alloc(const PackedMesh::Cluster *cluster, size_t firstMeshlet, size_t meshletCount, uint16_t bucketId, uint16_t commandId)
void free(uint32_t id, uint32_t numCluster)
void markClusters(size_t id, size_t count=1)
float waveMaxAmplitude
Definition material.h:35
static Tempest::Device & device()
Definition resources.h:83
static void recycle(Tempest::DescriptorArray &&arr)
static Shaders & inst()
Definition shaders.cpp:39
Bounds bbox
Definition staticmesh.h:56
const StaticMesh * staticMesh
Definition drawbuckets.h:16
const AnimMesh * animMesh
Definition drawbuckets.h:17
Tempest::Vec3 pos
Definition packedmesh.h:41