LCOV - code coverage report
Current view: top level - xenolith/renderer/basic2d/backend/vk - XL2dVkVertexPass.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 394 483 81.6 %
Date: 2024-05-12 00:16:13 Functions: 33 35 94.3 %

          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             : }

Generated by: LCOV version 1.14