Line data Source code
1 : /**
2 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
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 "XL2dVkVertexPass.h"
24 : #include "XLCoreFrameHandle.h"
25 : #include "XLCoreFrameQueue.h"
26 : #include "XLCoreFrameCache.h"
27 : #include "XLDirector.h"
28 : #include "XLVkRenderPass.h"
29 : #include "XLVkTextureSet.h"
30 : #include "XLVkPipeline.h"
31 : #include "XL2dLinearGradient.h"
32 : #include "XL2dFrameContext.h"
33 :
34 : namespace STAPPLER_VERSIONIZED stappler::xenolith::basic2d::vk {
35 :
36 20 : VertexAttachment::~VertexAttachment() { }
37 :
38 10 : bool VertexAttachment::init(AttachmentBuilder &builder, const BufferInfo &info, const AttachmentData *m) {
39 10 : if (BufferAttachment::init(builder, info)) {
40 10 : _materials = m;
41 10 : return true;
42 : }
43 0 : return false;
44 : }
45 :
46 4650 : auto VertexAttachment::makeFrameHandle(const FrameQueue &handle) -> Rc<AttachmentHandle> {
47 9300 : return Rc<VertexAttachmentHandle>::create(this, handle);
48 : }
49 :
50 9300 : VertexAttachmentHandle::~VertexAttachmentHandle() { }
51 :
52 4650 : bool VertexAttachmentHandle::setup(FrameQueue &handle, Function<void(bool)> &&cb) {
53 4650 : if (auto materials = handle.getAttachment((static_cast<VertexAttachment *>(_attachment.get()))->getMaterials())) {
54 4650 : _materials = static_cast<const MaterialAttachmentHandle *>(materials->handle.get());
55 : }
56 4650 : return true;
57 : }
58 :
59 4640 : void VertexAttachmentHandle::submitInput(FrameQueue &q, Rc<core::AttachmentInputData> &&data, Function<void(bool)> &&cb) {
60 4640 : auto d = data.cast<FrameContextHandle2d>();
61 4640 : if (!d || q.isFinalized()) {
62 0 : cb(false);
63 0 : return;
64 : }
65 :
66 4640 : q.getFrame()->waitForDependencies(data->waitDependencies, [this, d = move(d), cb = move(cb)] (FrameHandle &handle, bool success) {
67 4640 : if (!success || !handle.isValidFlag()) {
68 0 : cb(false);
69 0 : return;
70 : }
71 :
72 4640 : auto &cache = handle.getLoop()->getFrameCache();
73 :
74 4640 : _materialSet = _materials->getSet();
75 4640 : _drawStat.cachedFramebuffers = cache->getFramebuffersCount();
76 4640 : _drawStat.cachedImages = cache->getImagesCount();
77 4640 : _drawStat.cachedImageViews = cache->getImageViewsCount();
78 :
79 9280 : handle.performInQueue([this, d = move(d)] (FrameHandle &handle) {
80 4640 : return loadVertexes(handle, d);
81 4640 : }, [cb = move(cb)] (FrameHandle &handle, bool success) {
82 4640 : cb(success);
83 4640 : }, this, "VertexMaterialAttachmentHandle::submitInput");
84 : });
85 4640 : }
86 :
87 4640 : bool VertexAttachmentHandle::empty() const {
88 4640 : return !_indexes || !_vertexes || !_transforms;
89 : }
90 :
91 4640 : Rc<FrameContextHandle2d> VertexAttachmentHandle::popCommands() const {
92 4640 : auto ret = move(_commands);
93 4640 : _commands = nullptr;
94 4640 : return ret;
95 0 : }
96 :
97 : struct VertexMaterialDrawPlan {
98 : struct PlanCommandInfo {
99 : const CmdGeneral *cmd = nullptr;
100 : SpanView<TransformVertexData> vertexes;
101 : Mat4 transform;
102 : const LinearGradientData *gradient = nullptr;
103 : uint32_t gradientVertexOffset = 0;
104 : };
105 :
106 : struct MaterialWritePlan {
107 : const core::Material *material = nullptr;
108 : Rc<core::DataAtlas> atlas;
109 : uint32_t vertexes = 0;
110 : uint32_t indexes = 0;
111 : uint32_t transforms = 0;
112 : Map<StateId, std::forward_list<PlanCommandInfo>> states;
113 : };
114 :
115 : struct WriteTarget {
116 : uint8_t *transform;
117 : uint8_t *vertexes;
118 : uint8_t *indexes;
119 : };
120 :
121 : Extent3 surfaceExtent;
122 : core::SurfaceTransformFlags transform = core::SurfaceTransformFlags::Identity;
123 :
124 : uint32_t excludeVertexes = 0;
125 : uint32_t excludeIndexes = 0;
126 :
127 : Map<SpanView<ZOrder>, float, ZOrderLess> paths;
128 :
129 : // fill write plan
130 : MaterialWritePlan globalWritePlan;
131 :
132 : // write plan for objects, that do depth-write and can be drawn out of order
133 : HashMap<core::MaterialId, MaterialWritePlan> solidWritePlan;
134 :
135 : // write plan for objects without depth-write, that can be drawn out of order
136 : HashMap<core::MaterialId, MaterialWritePlan> surfaceWritePlan;
137 :
138 : // write plan for transparent objects, that should be drawn in order
139 : Map<SpanView<ZOrder>, HashMap<core::MaterialId, MaterialWritePlan>, ZOrderLess> transparentWritePlan;
140 :
141 : std::forward_list<Vector<TransformVertexData>> deferredTmp;
142 :
143 : uint32_t vertexOffset = 0;
144 : uint32_t indexOffset = 0;
145 : uint32_t transtormOffset = 0;
146 :
147 : uint32_t materialVertexes = 0;
148 : uint32_t materialIndexes = 0;
149 : uint32_t transformIdx = 0;
150 :
151 : uint32_t solidCmds = 0;
152 : uint32_t surfaceCmds = 0;
153 : uint32_t transparentCmds = 0;
154 :
155 : Vec2 shadowSize = Vec2(1.0f, 1.0f);
156 :
157 : bool hasGpuSideAtlases = false;
158 :
159 : FrameContextHandle2d *handle = nullptr;
160 :
161 4640 : VertexMaterialDrawPlan(const core::FrameContraints &constraints)
162 4640 : : surfaceExtent{constraints.extent}, transform(constraints.transform) { }
163 :
164 115784 : void emplaceWritePlan(const core::Material *material, HashMap<core::MaterialId, MaterialWritePlan> &writePlan,
165 : const Command *c, const CmdGeneral *cmd, SpanView<TransformVertexData> vertexes) {
166 115784 : auto it = writePlan.find(cmd->material);
167 115784 : if (it == writePlan.end()) {
168 20995 : if (material) {
169 20995 : it = writePlan.emplace(cmd->material, MaterialWritePlan()).first;
170 20995 : it->second.material = material;
171 20995 : if (auto atlas = it->second.material->getAtlas()) {
172 4772 : it->second.atlas = atlas;
173 20995 : }
174 : }
175 : }
176 :
177 115784 : if (it != writePlan.end() && it->second.material) {
178 230814 : for (auto &iit : vertexes) {
179 115030 : globalWritePlan.vertexes += iit.data->data.size();
180 115030 : globalWritePlan.indexes += iit.data->indexes.size();
181 115030 : ++ globalWritePlan.transforms;
182 :
183 115030 : it->second.vertexes += iit.data->data.size();
184 115030 : it->second.indexes += iit.data->indexes.size();
185 115030 : ++ it->second.transforms;
186 :
187 115030 : if ((c->flags & CommandFlags::DoNotCount) != CommandFlags::None) {
188 9280 : excludeVertexes = iit.data->data.size();
189 9280 : excludeIndexes = iit.data->indexes.size();
190 : }
191 : }
192 :
193 115784 : auto iit = it->second.states.find(cmd->state);
194 115784 : if (iit == it->second.states.end()) {
195 21716 : iit = it->second.states.emplace(cmd->state, std::forward_list<PlanCommandInfo>()).first;
196 : }
197 :
198 115784 : auto &plan = iit->second.emplace_front(PlanCommandInfo{cmd, vertexes});
199 :
200 115784 : if (cmd->state != StateIdNone) {
201 3541 : auto state = handle->getState(cmd->state);
202 3541 : if (state) {
203 3541 : auto stateData = dynamic_cast<StateData *>(state->data ? state->data.get() : nullptr);
204 :
205 3541 : if (stateData && stateData->gradient) {
206 370 : plan.transform = stateData->transform;
207 370 : plan.gradient = stateData->gradient.get();
208 370 : plan.gradientVertexOffset = globalWritePlan.vertexes;
209 370 : globalWritePlan.vertexes += stateData->gradient->steps.size() + 2;
210 : }
211 : }
212 : }
213 : }
214 :
215 115784 : auto pathsIt = paths.find(cmd->zPath);
216 115784 : if (pathsIt == paths.end()) {
217 31348 : paths.emplace(cmd->zPath, 0.0f);
218 : }
219 115784 : }
220 :
221 52133 : void pushVertexData(core::MaterialSet *materialSet, const Command *c, const CmdVertexArray *cmd) {
222 52133 : auto material = materialSet->getMaterialById(cmd->material);
223 52133 : if (!material) {
224 0 : return;
225 : }
226 52133 : if (material->getPipeline()->isSolid()) {
227 46472 : emplaceWritePlan(material, solidWritePlan, c, cmd, cmd->vertexes);
228 5661 : } else if (cmd->renderingLevel == RenderingLevel::Surface) {
229 0 : emplaceWritePlan(material, surfaceWritePlan, c, cmd, cmd->vertexes);
230 : } else {
231 5661 : auto v = transparentWritePlan.find(cmd->zPath);
232 5661 : if (v == transparentWritePlan.end()) {
233 5511 : v = transparentWritePlan.emplace(cmd->zPath, HashMap<core::MaterialId, MaterialWritePlan>()).first;
234 : }
235 5661 : emplaceWritePlan(material, v->second, c, cmd, cmd->vertexes);
236 : }
237 : };
238 :
239 79544 : void pushDeferred(core::MaterialSet *materialSet, const Command *c, const CmdDeferred *cmd) {
240 79544 : auto material = materialSet->getMaterialById(cmd->material);
241 79544 : if (!material) {
242 0 : return;
243 : }
244 :
245 79544 : if (!cmd->deferred->isWaitOnReady()) {
246 22038 : if (!cmd->deferred->isReady()) {
247 15893 : return;
248 : }
249 : }
250 :
251 63651 : auto &vertexes = deferredTmp.emplace_front(cmd->deferred->getData().vec<Interface>());
252 :
253 : // apply transforms;
254 63651 : if (cmd->normalized) {
255 75246 : for (auto &it : vertexes) {
256 37623 : auto modelTransform = cmd->modelTransform * it.transform;
257 :
258 37623 : Mat4 newMV;
259 37623 : newMV.m[12] = std::floor(modelTransform.m[12]);
260 37623 : newMV.m[13] = std::floor(modelTransform.m[13]);
261 37623 : newMV.m[14] = std::floor(modelTransform.m[14]);
262 :
263 37623 : const_cast<TransformVertexData &>(it).transform = cmd->viewTransform * newMV;
264 : }
265 : } else {
266 51302 : for (auto &it : vertexes) {
267 25274 : const_cast<TransformVertexData &>(it).transform = cmd->viewTransform * cmd->modelTransform * it.transform;
268 : }
269 : }
270 :
271 63651 : if (cmd->renderingLevel == RenderingLevel::Solid) {
272 19279 : emplaceWritePlan(material, solidWritePlan, c, cmd, vertexes);
273 44372 : } else if (cmd->renderingLevel == RenderingLevel::Surface) {
274 37565 : emplaceWritePlan(material, surfaceWritePlan, c, cmd, vertexes);
275 : } else {
276 6807 : auto v = transparentWritePlan.find(cmd->zPath);
277 6807 : if (v == transparentWritePlan.end()) {
278 1983 : v = transparentWritePlan.emplace(cmd->zPath, HashMap<core::MaterialId, MaterialWritePlan>()).first;
279 : }
280 6807 : emplaceWritePlan(material, v->second, c, cmd, vertexes);
281 : }
282 : }
283 :
284 4640 : void updatePathsDepth() {
285 4640 : float depthScale = 1.0f / float(paths.size() + 1);
286 4640 : float depthOffset = 1.0f - depthScale;
287 35988 : for (auto &it : paths) {
288 31348 : it.second = depthOffset;
289 31348 : depthOffset -= depthScale;
290 : }
291 4640 : }
292 :
293 4640 : void pushInitial(WriteTarget &writeTarget) {
294 4640 : TransformData val;
295 4640 : memcpy(writeTarget.transform, &val, sizeof(TransformData));
296 4640 : transtormOffset += sizeof(TransformData); ++ transformIdx;
297 :
298 4640 : Vector<uint32_t> indexes{ 0, 2, 1, 0, 3, 2, 4, 6, 5, 4, 7, 6 };
299 :
300 : Vector<Vertex> vertexes {
301 : // full screen quad data
302 : Vertex{
303 : Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
304 : Vec4::ONE, Vec2::ZERO, 0, 0
305 : },
306 : Vertex{
307 : Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
308 : Vec4::ONE, Vec2::UNIT_Y, 0, 0
309 : },
310 : Vertex{
311 : Vec4(1.0f, 1.0f, 0.0f, 1.0f),
312 : Vec4::ONE, Vec2::ONE, 0, 0
313 : },
314 : Vertex{
315 : Vec4(1.0f, -1.0f, 0.0f, 1.0f),
316 : Vec4::ONE, Vec2::UNIT_X, 0, 0
317 : },
318 :
319 : // shadow quad data
320 : Vertex{
321 : Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
322 4640 : Vec4::ONE, Vec2(0.0f, 1.0f - shadowSize.y), 0, 0
323 : },
324 : Vertex{
325 : Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
326 : Vec4::ONE, Vec2(0.0f, 1.0f), 0, 0
327 : },
328 : Vertex{
329 : Vec4(1.0f, 1.0f, 0.0f, 1.0f),
330 : Vec4::ONE, Vec2(shadowSize.x, 1.0f), 0, 0
331 : },
332 : Vertex{
333 : Vec4(1.0f, -1.0f, 0.0f, 1.0f),
334 4640 : Vec4::ONE, Vec2(shadowSize.x, 1.0f - shadowSize.y), 0, 0
335 : }
336 4640 : };
337 :
338 4640 : switch (core::getPureTransform(transform)) {
339 0 : case core::SurfaceTransformFlags::Rotate90:
340 0 : vertexes[0].tex = Vec2::UNIT_Y;
341 0 : vertexes[1].tex = Vec2::ONE;
342 0 : vertexes[2].tex = Vec2::UNIT_X;
343 0 : vertexes[3].tex = Vec2::ZERO;
344 0 : vertexes[4].tex = Vec2(0.0f, shadowSize.y);
345 0 : vertexes[5].tex = shadowSize;
346 0 : vertexes[6].tex = Vec2(shadowSize.x, 0.0f);
347 0 : vertexes[7].tex = Vec2::ZERO;
348 0 : break;
349 0 : case core::SurfaceTransformFlags::Rotate180:
350 0 : vertexes[0].tex = Vec2::ONE;
351 0 : vertexes[1].tex = Vec2::UNIT_X;
352 0 : vertexes[2].tex = Vec2::ZERO;
353 0 : vertexes[3].tex = Vec2::UNIT_Y;
354 0 : vertexes[4].tex = shadowSize;
355 0 : vertexes[5].tex = Vec2(shadowSize.x, 0.0f);
356 0 : vertexes[6].tex = Vec2::ZERO;
357 0 : vertexes[7].tex = Vec2(0.0f, shadowSize.y);
358 0 : break;
359 0 : case core::SurfaceTransformFlags::Rotate270:
360 0 : vertexes[0].tex = Vec2::UNIT_X;
361 0 : vertexes[1].tex = Vec2::ZERO;
362 0 : vertexes[2].tex = Vec2::UNIT_Y;
363 0 : vertexes[3].tex = Vec2::ONE;
364 0 : vertexes[4].tex = Vec2(shadowSize.x, 0.0f);
365 0 : vertexes[5].tex = Vec2::ZERO;
366 0 : vertexes[6].tex = Vec2(0.0f, shadowSize.y);
367 0 : vertexes[7].tex = shadowSize;
368 0 : break;
369 4640 : default:
370 4640 : break;
371 : }
372 :
373 4640 : auto target = reinterpret_cast<Vertex *>(writeTarget.vertexes) + vertexOffset;
374 4640 : memcpy(target, vertexes.data(), vertexes.size() * sizeof(Vertex));
375 4640 : memcpy(writeTarget.indexes, indexes.data(), indexes.size() * sizeof(uint32_t));
376 :
377 4640 : vertexOffset += vertexes.size();
378 4640 : indexOffset += indexes.size();
379 4640 : }
380 :
381 : uint32_t rotateObject(uint32_t obj, uint32_t idx) {
382 : auto anchor = (obj >> 16) & 0x3;
383 : return (obj & ~0x30000) | (((anchor + idx) % 4) << 16);
384 : }
385 :
386 : Vec2 rotateVec(const Vec2 &vec) {
387 : switch (core::getPureTransform(transform)) {
388 : case core::SurfaceTransformFlags::Rotate90:
389 : return Vec2(-vec.y, vec.x);
390 : break;
391 : case core::SurfaceTransformFlags::Rotate180:
392 : return Vec2(-vec.x, -vec.y);
393 : break;
394 : case core::SurfaceTransformFlags::Rotate270:
395 : return Vec2(vec.y, -vec.x);
396 : break;
397 : default:
398 : break;
399 : }
400 : return vec;
401 : }
402 :
403 115030 : void pushVertexes(WriteTarget &writeTarget, const core::MaterialId &materialId, const MaterialWritePlan &plan,
404 : const CmdGeneral *cmd, const TransformData &transform, VertexData *vertexes) {
405 115030 : auto target = reinterpret_cast<Vertex *>(writeTarget.vertexes) + vertexOffset;
406 115030 : memcpy(target, vertexes->data.data(), vertexes->data.size() * sizeof(Vertex));
407 :
408 115030 : memcpy(writeTarget.transform + transtormOffset, &transform, sizeof(TransformData));
409 :
410 115030 : size_t idx = 0;
411 115030 : if (plan.atlas) {
412 37623 : auto ext = plan.atlas->getImageExtent();
413 37623 : float atlasScaleX = 1.0f / ext.width;
414 37623 : float atlasScaleY = 1.0f / ext.height;
415 :
416 2760559 : for (; idx < vertexes->data.size(); ++ idx) {
417 2722936 : auto &t = target[idx];
418 2722936 : t.material = transformIdx | transformIdx << 16;
419 :
420 2722936 : if (!hasGpuSideAtlases) {
421 0 : if (auto d = reinterpret_cast<const DataAtlasValue *>(plan.atlas->getObjectByName(t.object))) {
422 0 : t.pos += Vec4(d->pos.x, d->pos.y, 0, 0);
423 0 : t.tex = d->tex;
424 0 : t.object = 0;
425 : } else {
426 : #if DEBUG
427 0 : log::warn("VertexMaterialDrawPlan", "Object not found: ", t.object, " ", string::toUtf8<Interface>(char16_t(t.object)));
428 : #endif
429 0 : auto anchor = font::CharId::getAnchorForChar(t.object);
430 0 : switch (anchor) {
431 0 : case font::CharAnchor::BottomLeft:
432 0 : t.tex = Vec2(1.0f - atlasScaleX, 0.0f);
433 0 : break;
434 0 : case font::CharAnchor::TopLeft:
435 0 : t.tex = Vec2(1.0f - atlasScaleX, 0.0f + atlasScaleY);
436 0 : break;
437 0 : case font::CharAnchor::TopRight:
438 0 : t.tex = Vec2(1.0f, 0.0f + atlasScaleY);
439 0 : break;
440 0 : case font::CharAnchor::BottomRight:
441 0 : t.tex = Vec2(1.0f, 0.0f);
442 0 : break;
443 : }
444 : }
445 : }
446 : }
447 : } else {
448 1364336 : for (; idx < vertexes->data.size(); ++ idx) {
449 1286929 : auto &t = target[idx];
450 1286929 : t.material = transformIdx | transformIdx << 16;
451 : }
452 : }
453 :
454 115030 : auto indexTarget = reinterpret_cast<uint32_t *>(writeTarget.indexes) + indexOffset;
455 :
456 7726426 : for (auto &it : vertexes->indexes) {
457 7611396 : *(indexTarget++) = it + vertexOffset;
458 : }
459 :
460 115030 : vertexOffset += vertexes->data.size();
461 115030 : indexOffset += vertexes->indexes.size();
462 115030 : transtormOffset += sizeof(TransformData);
463 115030 : ++ transformIdx;
464 :
465 115030 : materialVertexes += vertexes->data.size();
466 115030 : materialIndexes += vertexes->indexes.size();
467 115030 : }
468 :
469 16774 : void drawWritePlan(Vector<VertexSpan> &spans, WriteTarget &writeTarget, HashMap<core::MaterialId, MaterialWritePlan> &writePlan) {
470 : // optimize draw order, minimize switching pipeline, textureSet and descriptors
471 16774 : Vector<const Pair<const core::MaterialId, MaterialWritePlan> *> drawOrder;
472 :
473 37769 : for (auto &it : writePlan) {
474 20995 : if (drawOrder.empty()) {
475 16774 : drawOrder.emplace_back(&it);
476 : } else {
477 4221 : auto lb = std::lower_bound(drawOrder.begin(), drawOrder.end(), &it,
478 4398 : [] (const Pair<const core::MaterialId, MaterialWritePlan> *l, const Pair<const core::MaterialId, MaterialWritePlan> *r) {
479 4398 : if (l->second.material->getPipeline() != l->second.material->getPipeline()) {
480 0 : return GraphicPipeline::comparePipelineOrdering(*l->second.material->getPipeline(), *r->second.material->getPipeline());
481 4398 : } else if (l->second.material->getLayoutIndex() != r->second.material->getLayoutIndex()) {
482 0 : return l->second.material->getLayoutIndex() < r->second.material->getLayoutIndex();
483 : } else {
484 4398 : return l->first < r->first;
485 : }
486 : });
487 4221 : if (lb == drawOrder.end()) {
488 677 : drawOrder.emplace_back(&it);
489 : } else {
490 3544 : drawOrder.emplace(lb, &it);
491 : }
492 : }
493 : }
494 :
495 37769 : for (auto &it : drawOrder) {
496 : // split order on states
497 :
498 42711 : for (auto &state : it->second.states) {
499 21716 : materialVertexes = 0;
500 21716 : materialIndexes = 0;
501 :
502 21716 : uint32_t gradientStart = 0;
503 21716 : uint32_t gradientCount = 0;
504 :
505 137500 : for (auto &cmd : state.second) {
506 230814 : for (auto &iit : cmd.vertexes) {
507 115030 : TransformData val(iit.transform);
508 :
509 115030 : auto pathIt = paths.find(cmd.cmd->zPath);
510 115030 : if (pathIt != paths.end()) {
511 115030 : val.offset.z = pathIt->second;
512 : }
513 :
514 115030 : if (cmd.cmd->depthValue > 0.0f) {
515 21242 : auto f16 = halffloat::encode(cmd.cmd->depthValue);
516 21242 : auto value = halffloat::decode(f16);
517 21242 : val.shadow = Vec4(value, value, value, 1.0);
518 : }
519 :
520 115030 : pushVertexes(writeTarget, it->first, it->second, cmd.cmd, val, iit.data.get());
521 : }
522 :
523 115784 : if (cmd.gradient) {
524 370 : auto target = reinterpret_cast<Vertex *>(writeTarget.vertexes) + vertexOffset;
525 :
526 370 : Vec2 start = cmd.transform * cmd.gradient->start;
527 370 : Vec2 end = cmd.transform * cmd.gradient->end;
528 :
529 370 : start.y = surfaceExtent.height - start.y;
530 370 : end.y = surfaceExtent.height - end.y;
531 :
532 370 : Vec2 norm = end - start;
533 :
534 370 : float d = norm.y * norm.y / (norm.x * norm.x + norm.y * norm.y);
535 :
536 370 : Vec2 axisAngle;
537 370 : if (std::abs(norm.y) > std::abs(norm.x)) {
538 155 : axisAngle.x = std::copysign(norm.length(), norm.y);
539 : //axisAngle.y = (norm.x * surfaceExtent.width) / (norm.y * surfaceExtent.height);
540 155 : axisAngle.y = d;
541 : } else {
542 215 : axisAngle.x = std::copysign(norm.length(), norm.x);
543 : //axisAngle.y = (norm.y * surfaceExtent.height) / (norm.x * surfaceExtent.width);
544 215 : axisAngle.y = d;
545 : }
546 :
547 370 : target->pos = Vec4(start, 0.0f, 0.0f);
548 370 : target->tex = axisAngle;
549 370 : ++ target;
550 :
551 370 : target->pos = Vec4(end, 1.0f, 0.0f);
552 370 : target->tex = axisAngle;
553 370 : ++ target;
554 :
555 1850 : for (auto &it : cmd.gradient->steps) {
556 1480 : target->pos = Vec4(math::lerp(start, end, it.value), it.value, it.factor);
557 1480 : target->tex = axisAngle;
558 1480 : target->color = Vec4(it.color.r, it.color.g, it.color.b, it.color.a);
559 1480 : ++ target;
560 : }
561 :
562 370 : gradientStart = vertexOffset;
563 370 : gradientCount = cmd.gradient->steps.size();
564 :
565 370 : vertexOffset += cmd.gradient->steps.size() + 2;
566 : }
567 : }
568 :
569 21716 : spans.emplace_back(VertexSpan({ it->first, materialIndexes, 1, indexOffset - materialIndexes, state.first,
570 : gradientStart, gradientCount}));
571 : }
572 : }
573 16774 : }
574 :
575 4640 : void pushAll(Vector<VertexSpan> &spans, WriteTarget &writeTarget) {
576 4640 : pushInitial(writeTarget);
577 :
578 4640 : uint32_t counter = 0;
579 4640 : drawWritePlan(spans, writeTarget, solidWritePlan);
580 :
581 4640 : solidCmds = spans.size() - counter;
582 4640 : counter = spans.size();
583 :
584 4640 : drawWritePlan(spans, writeTarget, surfaceWritePlan);
585 :
586 4640 : surfaceCmds = spans.size() - counter;
587 4640 : counter = spans.size();
588 :
589 12134 : for (auto &it : transparentWritePlan) {
590 7494 : drawWritePlan(spans, writeTarget, it.second);
591 : }
592 :
593 4640 : transparentCmds = spans.size() - counter;
594 4640 : }
595 : };
596 :
597 4640 : bool VertexAttachmentHandle::loadVertexes(FrameHandle &fhandle, const Rc<FrameContextHandle2d> &commands) {
598 4640 : auto handle = dynamic_cast<DeviceFrameHandle *>(&fhandle);
599 4640 : if (!handle) {
600 0 : return false;
601 : }
602 :
603 4640 : auto t = platform::clock();
604 :
605 4640 : VertexMaterialDrawPlan plan(fhandle.getFrameConstraints());
606 4640 : plan.hasGpuSideAtlases = handle->getAllocator()->getDevice()->hasDynamicIndexedBuffers();
607 4640 : plan.handle = commands;
608 :
609 4640 : auto shadowExtent = commands->lights.getShadowExtent( fhandle.getFrameConstraints().getScreenSize());
610 4640 : auto shadowSize = commands->lights.getShadowSize( fhandle.getFrameConstraints().getScreenSize());
611 :
612 4640 : plan.shadowSize = Vec2(shadowSize.width / float(shadowExtent.width), shadowSize.height / float(shadowExtent.height));
613 :
614 4640 : auto cmd = commands->commands->getFirst();
615 136317 : while (cmd) {
616 131677 : switch (cmd->type) {
617 0 : case CommandType::CommandGroup:
618 0 : break;
619 52133 : case CommandType::VertexArray:
620 52133 : plan.pushVertexData(_materialSet.get(), cmd, reinterpret_cast<const CmdVertexArray *>(cmd->data));
621 52133 : break;
622 79544 : case CommandType::Deferred:
623 79544 : plan.pushDeferred(_materialSet.get(), cmd, reinterpret_cast<const CmdDeferred *>(cmd->data));
624 79544 : break;
625 0 : case CommandType::ShadowArray:
626 : case CommandType::ShadowDeferred:
627 : case CommandType::SdfGroup2D:
628 0 : break;
629 : }
630 131677 : cmd = cmd->next;
631 : }
632 :
633 4640 : if (plan.globalWritePlan.vertexes == 0 || plan.globalWritePlan.indexes == 0) {
634 0 : return true;
635 : }
636 :
637 4640 : plan.updatePathsDepth();
638 :
639 4640 : auto devFrame = static_cast<DeviceFrameHandle *>(handle);
640 :
641 4640 : auto &pool = devFrame->getMemPool(this);
642 :
643 : // create buffers
644 13920 : _indexes = pool->spawn(AllocationUsage::DeviceLocalHostVisible,
645 13920 : BufferInfo(core::BufferUsage::IndexBuffer, (plan.globalWritePlan.indexes + 12) * sizeof(uint32_t)));
646 :
647 13920 : _vertexes = pool->spawn(AllocationUsage::DeviceLocalHostVisible,
648 13920 : BufferInfo(core::BufferUsage::StorageBuffer, (plan.globalWritePlan.vertexes + 8) * sizeof(Vertex)));
649 :
650 13920 : _transforms = pool->spawn(AllocationUsage::DeviceLocalHostVisible,
651 13920 : BufferInfo(core::BufferUsage::StorageBuffer, (plan.globalWritePlan.transforms + 1) * sizeof(TransformData)));
652 :
653 4640 : if (!_vertexes || !_indexes || !_transforms) {
654 0 : return false;
655 : }
656 :
657 9280 : Bytes vertexData, indexData, transformData;
658 :
659 : VertexMaterialDrawPlan::WriteTarget writeTarget;
660 :
661 4640 : if (fhandle.isPersistentMapping()) {
662 4640 : writeTarget.vertexes = _vertexes->getPersistentMappedRegion();
663 4640 : writeTarget.indexes = _indexes->getPersistentMappedRegion();
664 4640 : writeTarget.transform = _transforms->getPersistentMappedRegion();
665 : } else {
666 0 : vertexData.resize(_vertexes->getSize());
667 0 : indexData.resize(_indexes->getSize());
668 0 : transformData.resize(_transforms->getSize());
669 :
670 0 : writeTarget.vertexes = vertexData.data();
671 0 : writeTarget.indexes = indexData.data();
672 0 : writeTarget.transform = transformData.data();
673 : }
674 :
675 : // write initial full screen quad
676 4640 : plan.pushAll(_spans, writeTarget);
677 :
678 4640 : if (fhandle.isPersistentMapping()) {
679 4640 : _vertexes->flushMappedRegion();
680 4640 : _indexes->flushMappedRegion();
681 4640 : _transforms->flushMappedRegion();
682 : } else {
683 0 : _vertexes->setData(vertexData);
684 0 : _indexes->setData(indexData);
685 0 : _transforms->setData(transformData);
686 : }
687 :
688 4640 : _drawStat.vertexes = plan.globalWritePlan.vertexes - plan.excludeVertexes;
689 4640 : _drawStat.triangles = (plan.globalWritePlan.indexes - plan.excludeIndexes) / 3;
690 4640 : _drawStat.zPaths = plan.paths.size();
691 4640 : _drawStat.drawCalls = _spans.size();
692 4640 : _drawStat.materials = _materialSet->getMaterials().size();
693 4640 : _drawStat.solidCmds = plan.solidCmds;
694 4640 : _drawStat.surfaceCmds = plan.surfaceCmds;
695 4640 : _drawStat.transparentCmds = plan.transparentCmds;
696 4640 : _drawStat.vertexInputTime = platform::clock() - t;
697 :
698 4640 : commands->director->pushDrawStat(_drawStat);
699 :
700 4640 : addBufferView(_vertexes);
701 4640 : addBufferView(_transforms);
702 :
703 4640 : _commands = commands;
704 4640 : return true;
705 4640 : }
706 :
707 10 : core::ImageFormat VertexPass::selectDepthFormat(SpanView<core::ImageFormat> formats) {
708 10 : core::ImageFormat ret = core::ImageFormat::Undefined;
709 :
710 10 : uint32_t score = 0;
711 :
712 50 : auto selectWithScore = [&] (core::ImageFormat fmt, uint32_t sc) {
713 50 : if (score < sc) {
714 10 : ret = fmt;
715 10 : score = sc;
716 : }
717 60 : };
718 :
719 70 : for (auto &it : formats) {
720 60 : switch (it) {
721 10 : case core::ImageFormat::D16_UNORM: selectWithScore(it, 12); break;
722 10 : case core::ImageFormat::X8_D24_UNORM_PACK32: selectWithScore(it, 7); break;
723 10 : case core::ImageFormat::D32_SFLOAT: selectWithScore(it, 9); break;
724 10 : case core::ImageFormat::S8_UINT: break;
725 0 : case core::ImageFormat::D16_UNORM_S8_UINT: selectWithScore(it, 11); break;
726 10 : case core::ImageFormat::D24_UNORM_S8_UINT: selectWithScore(it, 10); break;
727 10 : case core::ImageFormat::D32_SFLOAT_S8_UINT: selectWithScore(it, 8); break;
728 0 : default: break;
729 : }
730 : }
731 :
732 10 : return ret;
733 : }
734 :
735 0 : auto VertexPass::makeFrameHandle(const FrameQueue &handle) -> Rc<QueuePassHandle> {
736 0 : return Rc<VertexPassHandle>::create(*this, handle);
737 : }
738 :
739 4640 : bool VertexPassHandle::prepare(FrameQueue &q, Function<void(bool)> &&cb) {
740 4640 : auto pass = static_cast<VertexPass *>(_queuePass.get());
741 :
742 4640 : if (auto materialBuffer = q.getAttachment(pass->getMaterials())) {
743 4640 : _materialBuffer = static_cast<const MaterialAttachmentHandle *>(materialBuffer->handle.get());
744 : }
745 :
746 4640 : if (auto vertexBuffer = q.getAttachment(pass->getVertexes())) {
747 4640 : _vertexBuffer = static_cast<const VertexAttachmentHandle *>(vertexBuffer->handle.get());
748 : }
749 :
750 4640 : return QueuePassHandle::prepare(q, move(cb));
751 : }
752 :
753 4640 : Vector<const CommandBuffer *> VertexPassHandle::doPrepareCommands(FrameHandle &handle) {
754 4640 : auto buf = _pool->recordBuffer(*_device, [&, this] (CommandBuffer &buf) {
755 4640 : auto materials = _materialBuffer->getSet().get();
756 :
757 4640 : Vector<ImageMemoryBarrier> outputImageBarriers;
758 4640 : Vector<BufferMemoryBarrier> outputBufferBarriers;
759 :
760 4640 : doFinalizeTransfer(materials, outputImageBarriers, outputBufferBarriers);
761 :
762 4640 : if (!outputBufferBarriers.empty() && !outputImageBarriers.empty()) {
763 522 : buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
764 : VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
765 : outputBufferBarriers, outputImageBarriers);
766 : }
767 :
768 4640 : prepareRenderPass(buf);
769 :
770 4640 : _data->impl.cast<RenderPass>()->perform(*this, buf, [&, this] {
771 4640 : prepareMaterialCommands(materials, buf);
772 4640 : });
773 :
774 4640 : finalizeRenderPass(buf);
775 4640 : return true;
776 4640 : });
777 :
778 4640 : return Vector<const CommandBuffer *>{buf};
779 : }
780 :
781 0 : void VertexPassHandle::prepareRenderPass(CommandBuffer &) { }
782 :
783 4640 : void VertexPassHandle::prepareMaterialCommands(core::MaterialSet * materials, CommandBuffer &buf) {
784 4640 : auto &fb = getFramebuffer();
785 4640 : auto currentExtent = fb->getExtent();
786 4640 : auto commands = _vertexBuffer->popCommands();
787 4640 : auto pass = static_cast<RenderPass *>(_data->impl.get());
788 :
789 4640 : if (_vertexBuffer->empty() || !_vertexBuffer->getIndexes() || !_vertexBuffer->getVertexes()) {
790 0 : return;
791 : }
792 :
793 4640 : VkViewport viewport{ 0.0f, 0.0f, float(currentExtent.width), float(currentExtent.height), 0.0f, 1.0f };
794 4640 : buf.cmdSetViewport(0, makeSpanView(&viewport, 1));
795 :
796 4640 : VkRect2D scissorRect{ { 0, 0}, { currentExtent.width, currentExtent.height } };
797 4640 : buf.cmdSetScissor(0, makeSpanView(&scissorRect, 1));
798 :
799 : // bind primary descriptors
800 : // default texture set comes with other sets
801 4640 : buf.cmdBindDescriptorSets(pass, 0);
802 :
803 : // bind global indexes
804 4640 : buf.cmdBindIndexBuffer(_vertexBuffer->getIndexes(), 0, VK_INDEX_TYPE_UINT32);
805 :
806 4640 : uint32_t boundTextureSetIndex = maxOf<uint32_t>();
807 4640 : core::GraphicPipeline *boundPipeline = nullptr;
808 :
809 4640 : StateId dynamicStateId = maxOf<StateId>();
810 4640 : DrawStateValues dynamicState;
811 :
812 : //log::verbose("VertexPassHandle", (void *)this, " init");
813 :
814 23388 : auto enableState = [&, this] (uint32_t stateId) {
815 21716 : if (stateId == dynamicStateId) {
816 18232 : return;
817 : }
818 :
819 3484 : auto state = commands->getState(stateId);
820 : //log::verbose("VertexPassHandle", (void *)this, " enable state: ", stateId, " ", (void *)state);
821 3484 : if (!state) {
822 1662 : if (dynamicState.isScissorEnabled()) {
823 1662 : dynamicState.enabled &= ~(core::DynamicState::Scissor);
824 1662 : VkRect2D scissorRect{ { 0, 0}, { currentExtent.width, currentExtent.height } };
825 1662 : buf.cmdSetScissor(0, makeSpanView(&scissorRect, 1));
826 : }
827 : } else {
828 1822 : if (state->isScissorEnabled()) {
829 1822 : if (dynamicState.isScissorEnabled()) {
830 160 : if (dynamicState.scissor != state->scissor) {
831 10 : auto scissorRect = rotateScissor(_constraints, state->scissor);
832 10 : buf.cmdSetScissor(0, makeSpanView(&scissorRect, 1));
833 10 : dynamicState.scissor = state->scissor;
834 : }
835 : } else {
836 1662 : dynamicState.enabled |= core::DynamicState::Scissor;
837 1662 : auto scissorRect = rotateScissor(_constraints, state->scissor);
838 1662 : buf.cmdSetScissor(0, makeSpanView(&scissorRect, 1));
839 1662 : dynamicState.scissor = state->scissor;
840 : }
841 : } else {
842 0 : if (dynamicState.isScissorEnabled()) {
843 0 : dynamicState.enabled &= ~(core::DynamicState::Scissor);
844 0 : VkRect2D scissorRect{ { 0, 0}, { currentExtent.width, currentExtent.height } };
845 0 : buf.cmdSetScissor(0, makeSpanView(&scissorRect, 1));
846 : }
847 : }
848 : }
849 :
850 :
851 3484 : dynamicStateId = stateId;
852 4640 : };
853 :
854 : /*static size_t ctrl = 0;
855 :
856 : size_t i = 0;
857 : size_t min = 0;
858 : size_t max = (ctrl ++) % 12;*/
859 :
860 : struct MaterialData {
861 : uint32_t materialIdx = 0;
862 : uint32_t imageIdx = 0;
863 : uint32_t samplerIdx = 0;
864 : uint32_t gradientOffset = 0;
865 : uint32_t gradientCount = 0;
866 : };
867 :
868 4640 : MaterialData data;
869 :
870 26356 : for (auto &materialVertexSpan : _vertexBuffer->getVertexData()) {
871 : /*if (i < min) {
872 : ++ i;
873 : continue;
874 : }
875 : if (i >= max) {
876 : break;
877 : }*/
878 :
879 : //++ i;
880 21716 : data.materialIdx = materials->getMaterialOrder(materialVertexSpan.material);
881 21716 : const core::Material * material = materials->getMaterialById(materialVertexSpan.material);
882 21716 : if (!material) {
883 0 : continue;
884 : }
885 21716 : data.imageIdx = material->getImages().front().descriptor;
886 21716 : data.samplerIdx = material->getImages().front().sampler;
887 21716 : data.gradientOffset = materialVertexSpan.gradientOffset;
888 21716 : data.gradientCount = materialVertexSpan.gradientCount;
889 :
890 21716 : auto pipeline = material->getPipeline()->pipeline;
891 21716 : auto textureSetIndex = material->getLayoutIndex();
892 :
893 21716 : if (pipeline != boundPipeline) {
894 9280 : buf.cmdBindPipeline(static_cast<GraphicPipeline *>(pipeline.get()));
895 9280 : boundPipeline = pipeline;
896 : }
897 :
898 21716 : if (textureSetIndex != boundTextureSetIndex) {
899 4640 : auto l = materials->getLayout(textureSetIndex);
900 4640 : if (l && l->set) {
901 4640 : auto s = static_cast<TextureSet *>(l->set.get());
902 4640 : auto set = s->getSet();
903 :
904 : // rebind texture set at last index
905 4640 : buf.cmdBindDescriptorSets(static_cast<RenderPass *>(_data->impl.get()), 0, makeSpanView(&set, 1), 1);
906 4640 : boundTextureSetIndex = textureSetIndex;
907 : } else {
908 0 : stappler::log::error("MaterialRenderPassHandle", "Invalid textureSetlayout: ", textureSetIndex);
909 0 : return;
910 : }
911 : }
912 :
913 21716 : enableState(materialVertexSpan.state);
914 :
915 21716 : buf.cmdPushConstants(pass->getPipelineLayout(0),
916 : VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
917 : BytesView(reinterpret_cast<const uint8_t *>(&data), sizeof(MaterialData)));
918 :
919 21716 : buf.cmdDrawIndexed(
920 21716 : materialVertexSpan.indexCount, // indexCount
921 21716 : materialVertexSpan.instanceCount, // instanceCount
922 21716 : materialVertexSpan.firstIndex, // firstIndex
923 : 0, // int32_t vertexOffset
924 : 0 // uint32_t firstInstance
925 : );
926 21716 : }
927 4640 : }
928 :
929 4640 : void VertexPassHandle::finalizeRenderPass(CommandBuffer &) { }
930 :
931 : }
|