Line data Source code
1 : /**
2 : Copyright (c) 2021-2022 Roman Katuntsev <sbkarr@stappler.org>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "XLVkMaterialCompiler.h"
24 : #include "XLVkObject.h"
25 : #include "XLVkQueuePass.h"
26 : #include "XLVkDeviceQueue.h"
27 : #include "XLCoreFrameRequest.h"
28 : #include "XLCoreFrameQueue.h"
29 :
30 : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
31 :
32 : class MaterialCompilationAttachment : public core::GenericAttachment {
33 : public:
34 : virtual ~MaterialCompilationAttachment();
35 :
36 : virtual Rc<AttachmentHandle> makeFrameHandle(const FrameQueue &) override;
37 : };
38 :
39 : class MaterialCompilationAttachmentHandle : public core::AttachmentHandle {
40 : public:
41 : virtual ~MaterialCompilationAttachmentHandle();
42 :
43 : virtual bool setup(FrameQueue &handle, Function<void(bool)> &&) override;
44 : virtual void submitInput(FrameQueue &, Rc<core::AttachmentInputData> &&, Function<void(bool)> &&) override;
45 :
46 4772 : virtual const Rc<core::MaterialInputData> &getInputData() const { return _inputData; }
47 1193 : virtual const Rc<core::MaterialSet> &getOriginalSet() const { return _originalSet; }
48 :
49 : protected:
50 : Rc<core::MaterialInputData> _inputData;
51 : Rc<core::MaterialSet> _originalSet;
52 : };
53 :
54 : class MaterialCompilationRenderPass : public QueuePass {
55 : public:
56 : virtual ~MaterialCompilationRenderPass();
57 :
58 : virtual bool init(QueuePassBuilder &, const AttachmentData *);
59 :
60 : virtual Rc<QueuePassHandle> makeFrameHandle(const FrameQueue &) override;
61 :
62 1193 : const AttachmentData *getMaterialAttachment() const { return _materialAttachment; }
63 :
64 : protected:
65 : using QueuePass::init;
66 :
67 : const AttachmentData *_materialAttachment = nullptr;
68 : };
69 :
70 : class MaterialCompilationPassHandle : public QueuePassHandle {
71 : public:
72 : virtual ~MaterialCompilationPassHandle();
73 :
74 : virtual bool prepare(FrameQueue &, Function<void(bool)> &&) override;
75 : virtual void finalize(FrameQueue &, bool successful) override;
76 :
77 : protected:
78 : virtual Vector<const CommandBuffer *> doPrepareCommands(FrameHandle &) override;
79 : virtual void doSubmitted(FrameHandle &, Function<void(bool)> &&, bool, Rc<Fence> &&) override;
80 : virtual void doComplete(FrameQueue &, Function<void(bool)> &&, bool) override;
81 :
82 : Rc<core::MaterialSet> _outputData;
83 : MaterialCompilationAttachmentHandle *_materialAttachment;
84 : };
85 :
86 84 : MaterialCompiler::~MaterialCompiler() { }
87 :
88 42 : bool MaterialCompiler::init() {
89 : using namespace core;
90 :
91 42 : Queue::Builder builder("MaterialCompiler");
92 :
93 84 : auto attachment = builder.addAttachemnt("MaterialAttachment", [&] (AttachmentBuilder &attachmentBuilder) -> Rc<Attachment> {
94 42 : attachmentBuilder.defineAsInput();
95 42 : attachmentBuilder.defineAsOutput();
96 84 : return Rc<MaterialCompilationAttachment>::create(attachmentBuilder);
97 42 : });
98 :
99 42 : builder.addPass("MaterialRenderPass", PassType::Transfer, RenderOrdering(0), [&] (QueuePassBuilder &passBuilder) -> Rc<core::QueuePass> {
100 84 : return Rc<MaterialCompilationRenderPass>::create(passBuilder, attachment);
101 : });
102 :
103 42 : if (core::Queue::init(move(builder))) {
104 42 : _attachment = attachment;
105 42 : return true;
106 : }
107 0 : return false;
108 42 : }
109 :
110 1193 : bool MaterialCompiler::inProgress(const MaterialAttachment *a) const {
111 1193 : auto it = _inProgress.find(a);
112 1193 : if (it != _inProgress.end()) {
113 0 : return true;
114 : }
115 1193 : return false;
116 : }
117 :
118 1193 : void MaterialCompiler::setInProgress(const MaterialAttachment *a) {
119 1193 : _inProgress.emplace(a);
120 1193 : }
121 :
122 1193 : void MaterialCompiler::dropInProgress(const MaterialAttachment *a) {
123 1193 : _inProgress.erase(a);
124 1193 : }
125 :
126 0 : bool MaterialCompiler::hasRequest(const MaterialAttachment *a) const {
127 0 : auto it = _requests.find(a);
128 0 : if (it != _requests.end()) {
129 0 : return true;
130 : }
131 0 : return false;
132 : }
133 :
134 0 : void MaterialCompiler::appendRequest(const MaterialAttachment *a, Rc<MaterialInputData> &&req,
135 : Vector<Rc<core::DependencyEvent>> &&deps) {
136 0 : auto it = _requests.find(a);
137 0 : if (it == _requests.end()) {
138 0 : it = _requests.emplace(a, MaterialRequest()).first;
139 : }
140 :
141 0 : for (auto &rem : req->materialsToRemove) {
142 0 : auto m = it->second.materials.find(rem);
143 0 : if (m != it->second.materials.end()) {
144 0 : it->second.materials.erase(m);
145 : }
146 :
147 0 : auto d = it->second.dynamic.find(rem);
148 0 : if (d != it->second.dynamic.end()) {
149 0 : it->second.dynamic.erase(d);
150 : }
151 :
152 0 : it->second.remove.emplace(rem);
153 : }
154 :
155 0 : for (auto &rem : req->dynamicMaterialsToUpdate) {
156 0 : it->second.dynamic.emplace(rem);
157 : }
158 :
159 0 : for (auto &m : req->materialsToAddOrUpdate) {
160 0 : auto materialId = m->getId();
161 0 : auto iit = it->second.materials.find(materialId);
162 0 : if (iit == it->second.materials.end()) {
163 0 : it->second.materials.emplace(materialId, move(m));
164 : } else {
165 0 : iit->second = move(m);
166 : }
167 0 : auto v = it->second.remove.find(materialId);
168 0 : if (v != it->second.remove.end()) {
169 0 : it->second.remove.erase(v);
170 : }
171 : }
172 :
173 0 : if (it->second.deps.empty()) {
174 0 : it->second.deps = move(deps);
175 : } else {
176 0 : for (auto &iit : deps) {
177 0 : it->second.deps.emplace_back(move(iit));
178 : }
179 : }
180 :
181 0 : if (it->second.callback) {
182 0 : it->second.callback = [cb = move(it->second.callback), cb2 = move(req->callback)] {
183 0 : cb();
184 0 : cb2();
185 0 : };
186 : } else {
187 0 : it->second.callback = move(req->callback);
188 : }
189 0 : }
190 :
191 0 : void MaterialCompiler::clearRequests() {
192 0 : _requests.clear();
193 0 : }
194 :
195 1193 : auto MaterialCompiler::makeRequest(Rc<MaterialInputData> &&input, Vector<Rc<core::DependencyEvent>> &&deps) -> Rc<FrameRequest> {
196 1193 : auto req = Rc<FrameRequest>::create(this);
197 1193 : req->addInput(_attachment, move(input));
198 1193 : req->addSignalDependencies(move(deps));
199 1193 : return req;
200 0 : }
201 :
202 1193 : void MaterialCompiler::runMaterialCompilationFrame(core::Loop &loop, Rc<MaterialInputData> &&req,
203 : Vector<Rc<core::DependencyEvent>> &&deps) {
204 1193 : auto targetAttachment = req->attachment;
205 :
206 1193 : auto h = loop.makeFrame(makeRequest(move(req), move(deps)), 0);
207 1193 : h->setCompleteCallback([this, targetAttachment] (FrameHandle &handle) {
208 1193 : auto reqIt = _requests.find(targetAttachment);
209 1193 : if (reqIt != _requests.end()) {
210 0 : if (handle.getLoop()->isRunning()) {
211 0 : auto deps = move(reqIt->second.deps);
212 0 : Rc<MaterialInputData> req = Rc<MaterialInputData>::alloc();
213 0 : req->attachment = targetAttachment;
214 0 : req->materialsToAddOrUpdate.reserve(reqIt->second.materials.size());
215 0 : for (auto &m : reqIt->second.materials) {
216 0 : req->materialsToAddOrUpdate.emplace_back(m.second);
217 : }
218 0 : req->materialsToRemove.reserve(reqIt->second.remove.size());
219 0 : for (auto &m : reqIt->second.remove) {
220 0 : req->materialsToRemove.emplace_back(m);
221 : }
222 0 : req->dynamicMaterialsToUpdate.reserve(reqIt->second.dynamic.size());
223 0 : for (auto &m : reqIt->second.dynamic) {
224 0 : req->dynamicMaterialsToUpdate.emplace_back(m);
225 : }
226 0 : req->callback = move(reqIt->second.callback);
227 0 : _requests.erase(reqIt);
228 :
229 0 : runMaterialCompilationFrame(*handle.getLoop(), move(req), Vector<Rc<core::DependencyEvent>>(deps));
230 0 : } else {
231 0 : clearRequests();
232 0 : dropInProgress(targetAttachment);
233 : }
234 : } else {
235 1193 : dropInProgress(targetAttachment);
236 : }
237 1193 : });
238 1193 : h->update(true);
239 1193 : }
240 :
241 84 : MaterialCompilationAttachment::~MaterialCompilationAttachment() { }
242 :
243 1193 : auto MaterialCompilationAttachment::makeFrameHandle(const FrameQueue &handle) -> Rc<AttachmentHandle> {
244 2386 : return Rc<MaterialCompilationAttachmentHandle>::create(this, handle);
245 : }
246 :
247 2386 : MaterialCompilationAttachmentHandle::~MaterialCompilationAttachmentHandle() { }
248 :
249 1193 : bool MaterialCompilationAttachmentHandle::setup(FrameQueue &handle, Function<void(bool)> &&cb) {
250 1193 : return true;
251 : }
252 :
253 1193 : void MaterialCompilationAttachmentHandle::submitInput(FrameQueue &q, Rc<core::AttachmentInputData> &&data, Function<void(bool)> &&cb) {
254 1193 : auto d = data.cast<core::MaterialInputData>();
255 1193 : if (!d || q.isFinalized()) {
256 0 : cb(false);
257 : }
258 :
259 1193 : q.getFrame()->waitForDependencies(data->waitDependencies, [this, d = move(d), cb = move(cb)] (FrameHandle &handle, bool success) {
260 1193 : handle.performOnGlThread([this, d = move(d), cb = move(cb)] (FrameHandle &handle) {
261 1193 : _inputData = d;
262 1193 : _originalSet = _inputData->attachment->getMaterials();
263 1193 : cb(true);
264 1193 : }, this, true, "MaterialCompilationAttachmentHandle::submitInput");
265 1193 : });
266 1193 : }
267 :
268 84 : MaterialCompilationRenderPass::~MaterialCompilationRenderPass() { }
269 :
270 42 : bool MaterialCompilationRenderPass::init(QueuePassBuilder &passBuilder, const AttachmentData *attachment) {
271 42 : passBuilder.addAttachment(attachment);
272 :
273 42 : if (!QueuePass::init(passBuilder)) {
274 0 : return false;
275 : }
276 :
277 42 : _queueOps = QueueOperations::Transfer;
278 42 : _materialAttachment = attachment;
279 42 : return true;
280 : }
281 :
282 1193 : auto MaterialCompilationRenderPass::makeFrameHandle(const FrameQueue &handle) -> Rc<QueuePassHandle> {
283 2386 : return Rc<MaterialCompilationPassHandle>::create(*this, handle);
284 : }
285 :
286 2386 : MaterialCompilationPassHandle::~MaterialCompilationPassHandle() { }
287 :
288 1193 : bool MaterialCompilationPassHandle::prepare(FrameQueue &frame, Function<void(bool)> &&cb) {
289 1193 : if (auto a = frame.getAttachment(static_cast<MaterialCompilationRenderPass *>(_queuePass.get())->getMaterialAttachment())) {
290 1193 : _materialAttachment = static_cast<MaterialCompilationAttachmentHandle *>(a->handle.get());
291 : }
292 :
293 1193 : auto &originalData = _materialAttachment->getOriginalSet();
294 1193 : auto &inputData = _materialAttachment->getInputData();
295 1193 : _outputData = inputData->attachment->cloneSet(originalData);
296 :
297 1193 : return QueuePassHandle::prepare(frame, move(cb));
298 : }
299 :
300 1193 : void MaterialCompilationPassHandle::finalize(FrameQueue &handle, bool successful) {
301 1193 : QueuePassHandle::finalize(handle, successful);
302 1193 : }
303 :
304 1193 : Vector<const CommandBuffer *> MaterialCompilationPassHandle::doPrepareCommands(FrameHandle &handle) {
305 1193 : auto layout = _device->getTextureSetLayout();
306 :
307 1193 : auto &inputData = _materialAttachment->getInputData();
308 1193 : auto buffers = updateMaterials(handle, _outputData, inputData->materialsToAddOrUpdate,
309 2386 : inputData->dynamicMaterialsToUpdate, inputData->materialsToRemove);
310 1193 : if (!buffers.targetBuffer) {
311 0 : return Vector<const CommandBuffer *>();
312 : }
313 :
314 1193 : QueueOperations ops = QueueOperations::None;
315 2386 : for (auto &it : inputData->attachment->getRenderPasses()) {
316 1193 : ops |= static_cast<vk::QueuePass *>(it->pass.get())->getQueueOps();
317 1193 : }
318 :
319 1193 : auto q = _device->getQueueFamily(ops);
320 1193 : if (!q) {
321 0 : return Vector<const CommandBuffer *>();
322 : }
323 :
324 1193 : VkPipelineStageFlags targetStages = 0;
325 1193 : if ((_pool->getClass() & QueueOperations::Graphics) != QueueOperations::None) {
326 0 : targetStages |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
327 : }
328 1193 : if ((_pool->getClass() & QueueOperations::Compute) != QueueOperations::None) {
329 0 : targetStages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
330 : }
331 1193 : if (!targetStages) {
332 1193 : targetStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
333 : }
334 :
335 1193 : auto buf = _pool->recordBuffer(*_device, [&, this] (CommandBuffer &buf) {
336 1193 : buf.cmdCopyBuffer(buffers.stagingBuffer, buffers.targetBuffer);
337 :
338 1193 : if (q->index == _pool->getFamilyIdx()) {
339 0 : BufferMemoryBarrier bufferBarrier(buffers.targetBuffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
340 0 : buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, targetStages, 0, makeSpanView(&bufferBarrier, 1));
341 : } else {
342 : BufferMemoryBarrier bufferBarrier(buffers.targetBuffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
343 1193 : QueueFamilyTransfer{_pool->getFamilyIdx(), q->index}, 0, VK_WHOLE_SIZE);
344 1193 : buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, targetStages, 0, makeSpanView(&bufferBarrier, 1));
345 1193 : buffers.targetBuffer->setPendingBarrier(bufferBarrier);
346 : }
347 1193 : return true;
348 : });
349 :
350 1193 : if (buf) {
351 1193 : auto tmpBuffer = new Rc<Buffer>(move(buffers.targetBuffer));
352 1193 : auto tmpOrder = new HashMap<core::MaterialId, uint32_t>(move(buffers.ordering));
353 1193 : handle.performOnGlThread([data = _outputData, tmpBuffer, tmpOrder] (FrameHandle &) {
354 1193 : data->setBuffer(move(*tmpBuffer), move(*tmpOrder));
355 1193 : delete tmpBuffer;
356 1193 : delete tmpOrder;
357 1193 : }, nullptr, true, "MaterialCompilationRenderPassHandle::doPrepareCommands");
358 1193 : return Vector<const CommandBuffer *>{buf};
359 : }
360 0 : return Vector<const CommandBuffer *>();
361 1193 : }
362 :
363 1193 : void MaterialCompilationPassHandle::doSubmitted(FrameHandle &frame, Function<void(bool)> &&func, bool success, Rc<Fence> &&fence) {
364 1193 : if (success) {
365 1193 : _materialAttachment->getInputData()->attachment->setMaterials(_outputData);
366 : }
367 :
368 1193 : QueuePassHandle::doSubmitted(frame, move(func), success, move(fence));
369 1193 : frame.signalDependencies(success);
370 1193 : }
371 :
372 1193 : void MaterialCompilationPassHandle::doComplete(FrameQueue &queue, Function<void(bool)> &&func, bool success) {
373 1193 : if (auto &cb = _materialAttachment->getInputData()->callback) {
374 127 : cb();
375 : }
376 :
377 1193 : QueuePassHandle::doComplete(queue, move(func), success);
378 1193 : }
379 :
380 : }
|