LCOV - code coverage report
Current view: top level - xenolith/font/backend/vk - XLVkFontQueue.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 353 414 85.3 %
Date: 2024-05-12 00:16:13 Functions: 53 58 91.4 %

          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 "XLVkFontQueue.h"
      24             : #include "XLFontExtension.h"
      25             : #include "XLCoreFrameQueue.h"
      26             : #include "XLFontDeferredRequest.h"
      27             : #include "SPFontEmplace.h"
      28             : 
      29             : #if MODULE_XENOLITH_BACKEND_VK
      30             : 
      31             : #include "XLVkAllocator.h"
      32             : 
      33             : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
      34             : 
      35             : struct RenderFontCharTextureData {
      36             :         int16_t x = 0;
      37             :         int16_t y = 0;
      38             :         uint16_t width = 0;
      39             :         uint16_t height = 0;
      40             : };
      41             : 
      42             : struct RenderFontCharPersistentData {
      43             :         RenderFontCharTextureData texture;
      44             :         uint32_t objectId;
      45             :         uint32_t bufferIdx;
      46             :         uint32_t offset;
      47             : };
      48             : 
      49             : struct RenderFontPersistentBufferUserdata : public Ref {
      50             :         Rc<DeviceMemoryPool> mempool;
      51             :         Vector<Rc<Buffer>> buffers;
      52             :         HashMap<uint32_t, RenderFontCharPersistentData> chars;
      53             : };
      54             : 
      55             : class FontAttachment : public core::GenericAttachment {
      56             : public:
      57             :         virtual ~FontAttachment();
      58             : 
      59             :         virtual Rc<AttachmentHandle> makeFrameHandle(const FrameQueue &) override;
      60             : };
      61             : 
      62             : class FontAttachmentHandle : public core::AttachmentHandle {
      63             : public:
      64             :         virtual ~FontAttachmentHandle();
      65             : 
      66             :         virtual bool setup(FrameQueue &, Function<void(bool)> &&) override;
      67             :         virtual void submitInput(FrameQueue &, Rc<core::AttachmentInputData> &&, Function<void(bool)> &&) override;
      68             : 
      69         612 :         Extent2 getImageExtent() const { return _imageExtent; }
      70        1224 :         const Rc<font::RenderFontInput> &getInput() const { return _input; }
      71         659 :         const Rc<Buffer> &getTmpBuffer() const { return _frontBuffer; }
      72         188 :         const Rc<Buffer> &getPersistentTargetBuffer() const { return _persistentTargetBuffer; }
      73        1224 :         const Rc<core::DataAtlas> &getAtlas() const { return _atlas; }
      74         612 :         const Rc<RenderFontPersistentBufferUserdata> &getUserdata() const { return _userdata; }
      75         612 :         const Vector<VkBufferImageCopy> &getCopyFromTmpBufferData() const { return _copyFromTmpBufferData; }
      76         612 :         const Map<Buffer *, Vector<VkBufferImageCopy>> &getCopyFromPersistentBufferData() const { return _copyFromPersistentBufferData; }
      77         612 :         const Vector<VkBufferCopy> &getCopyToPersistentBufferData() const { return _copyToPersistentBufferData; }
      78             : 
      79             : protected:
      80             :         void doSubmitInput(FrameHandle &, Function<void(bool)> &&cb, Rc<font::RenderFontInput> &&d);
      81             :         void writeAtlasData(FrameHandle &, bool underlinePersistent);
      82             : 
      83             :         uint32_t nextBufferOffset(size_t blockSize);
      84             :         uint32_t nextPersistentTransferOffset(size_t blockSize);
      85             : 
      86             :         bool addPersistentCopy(uint16_t fontId, char16_t c);
      87             :         void pushCopyTexture(uint32_t reqIdx, const font::CharTexture &texData);
      88             :         void pushAtlasTexture(core::DataAtlas *, VkBufferImageCopy &);
      89             : 
      90             :         Rc<font::RenderFontInput> _input;
      91             :         Rc<RenderFontPersistentBufferUserdata> _userdata;
      92             :         uint32_t _counter = 0;
      93             :         VkDeviceSize _bufferSize = 0;
      94             :         VkDeviceSize _optimalRowAlignment = 1;
      95             :         VkDeviceSize _optimalTextureAlignment = 1;
      96             :         std::atomic<uint32_t> _bufferOffset = 0;
      97             :         std::atomic<uint32_t> _persistentOffset = 0;
      98             :         std::atomic<uint32_t> _copyFromTmpOffset = 0;
      99             :         std::atomic<uint32_t> _copyToPersistentOffset = 0;
     100             :         std::atomic<uint32_t> _textureTargetOffset = 0;
     101             :         Rc<Buffer> _frontBuffer;
     102             :         Rc<Buffer> _persistentTargetBuffer;
     103             :         Rc<core::DataAtlas> _atlas;
     104             :         Vector<VkBufferImageCopy> _copyFromTmpBufferData;
     105             :         Map<Buffer *, Vector<VkBufferImageCopy>> _copyFromPersistentBufferData;
     106             :         Vector<VkBufferCopy> _copyToPersistentBufferData;
     107             :         Vector<RenderFontCharPersistentData> _copyPersistentCharData;
     108             :         Vector<RenderFontCharTextureData> _textureTarget;
     109             :         Extent2 _imageExtent;
     110             :         Mutex _mutex;
     111             :         Function<void(bool)> _onInput;
     112             : };
     113             : 
     114             : class FontRenderPass : public QueuePass {
     115             : public:
     116             :         virtual ~FontRenderPass();
     117             : 
     118             :         virtual bool init(QueuePassBuilder &passBuilder, const AttachmentData *attachment);
     119             : 
     120             :         virtual Rc<QueuePassHandle> makeFrameHandle(const FrameQueue &) override;
     121             : 
     122         612 :         const AttachmentData *getRenderFontAttachment() const { return _fontAttachment; }
     123             : 
     124             : protected:
     125             :         using QueuePass::init;
     126             : 
     127             :         const AttachmentData *_fontAttachment;
     128             : };
     129             : 
     130             : class FontRenderPassHandle : public QueuePassHandle {
     131             : public:
     132             :         virtual ~FontRenderPassHandle();
     133             : 
     134             :         virtual bool init(QueuePass &, const FrameQueue &) override;
     135             : 
     136             :         virtual QueueOperations getQueueOps() const override;
     137             : 
     138             :         virtual bool prepare(FrameQueue &, Function<void(bool)> &&) override;
     139             :         virtual void finalize(FrameQueue &, bool successful)  override;
     140             : 
     141             : protected:
     142             :         virtual Vector<const CommandBuffer *> doPrepareCommands(FrameHandle &) override;
     143             : 
     144             :         virtual void doSubmitted(FrameHandle &, Function<void(bool)> &&, bool, Rc<Fence> &&) override;
     145             :         virtual void doComplete(FrameQueue &, Function<void(bool)> &&, bool) override;
     146             : 
     147             :         FontAttachmentHandle *_fontAttachment = nullptr;
     148             :         QueueOperations _queueOps = QueueOperations::None;
     149             :         Rc<Image> _targetImage;
     150             :         Rc<Buffer> _targetAtlasIndex;
     151             :         Rc<Buffer> _targetAtlasData;
     152             :         Rc<Buffer> _outBuffer;
     153             : };
     154             : 
     155          48 : FontQueue::~FontQueue() { }
     156             : 
     157          24 : bool FontQueue::init(StringView name) {
     158             :         using namespace core;
     159          24 :         Queue::Builder builder(name);
     160             : 
     161          48 :         auto attachment = builder.addAttachemnt("RenderFontQueueAttachment", [] (AttachmentBuilder &attachmentBuilder) -> Rc<Attachment> {
     162          24 :                 attachmentBuilder.defineAsInput();
     163          24 :                 attachmentBuilder.defineAsOutput();
     164          48 :                 return Rc<FontAttachment>::create(attachmentBuilder);
     165          24 :         });
     166             : 
     167          24 :         builder.addPass("RenderFontQueuePass", PassType::Transfer, RenderOrdering(0), [&] (QueuePassBuilder &passBuilder) -> Rc<core::QueuePass> {
     168          48 :                 return Rc<FontRenderPass>::create(passBuilder, attachment);
     169             :         });
     170             : 
     171          24 :         if (Queue::init(move(builder))) {
     172          24 :                 _attachment = attachment;
     173          24 :                 return true;
     174             :         }
     175           0 :         return false;
     176          24 : }
     177             : 
     178          48 : FontAttachment::~FontAttachment() { }
     179             : 
     180         612 : auto FontAttachment::makeFrameHandle(const FrameQueue &handle) -> Rc<AttachmentHandle> {
     181        1224 :         return Rc<FontAttachmentHandle>::create(this, handle);
     182             : }
     183             : 
     184        1224 : FontAttachmentHandle::~FontAttachmentHandle() { }
     185             : 
     186         612 : bool FontAttachmentHandle::setup(FrameQueue &handle, Function<void(bool)> &&) {
     187         612 :         auto dev = static_cast<Device *>(handle.getFrame()->getDevice());
     188         612 :         _optimalTextureAlignment = std::max(dev->getInfo().properties.device10.properties.limits.optimalBufferCopyOffsetAlignment, VkDeviceSize(4));
     189         612 :         _optimalRowAlignment = std::max(dev->getInfo().properties.device10.properties.limits.optimalBufferCopyRowPitchAlignment, VkDeviceSize(4));
     190         612 :         return true;
     191             : }
     192             : 
     193         612 : static Extent2 FontAttachmentHandle_buildTextureData(Vector<SpanView<VkBufferImageCopy>> requests) {
     194         612 :         memory::vector<VkBufferImageCopy *> layoutData; layoutData.reserve(requests.size());
     195             : 
     196         612 :         float totalSquare = 0.0f;
     197             : 
     198        1824 :         for (auto &v : requests) {
     199      103493 :                 for (auto &d : v) {
     200      102281 :                         auto it = std::lower_bound(layoutData.begin(), layoutData.end(), &d,
     201      627668 :                                         [] (const VkBufferImageCopy * l, const VkBufferImageCopy * r) -> bool {
     202      627668 :                                 if (l->imageExtent.height == r->imageExtent.height && l->imageExtent.width == r->imageExtent.width) {
     203       66103 :                                         return l->bufferImageHeight < r->bufferImageHeight;
     204      561565 :                                 } else if (l->imageExtent.height == r->imageExtent.height) {
     205      176467 :                                         return l->imageExtent.width > r->imageExtent.width;
     206             :                                 } else {
     207      385098 :                                         return l->imageExtent.height > r->imageExtent.height;
     208             :                                 }
     209      102281 :                         });
     210      102281 :                         layoutData.emplace(it, const_cast<VkBufferImageCopy *>(&d));
     211      102281 :                         totalSquare += d.imageExtent.width * d.imageExtent.height;
     212             :                 }
     213             :         }
     214             : 
     215         612 :         font::EmplaceCharInterface iface({
     216           0 :                 [] (void *ptr) -> uint16_t { return (reinterpret_cast<VkBufferImageCopy *>(ptr))->imageOffset.x; }, // x
     217           0 :                 [] (void *ptr) -> uint16_t { return (reinterpret_cast<VkBufferImageCopy *>(ptr))->imageOffset.y; }, // y
     218     5095291 :                 [] (void *ptr) -> uint16_t { return (reinterpret_cast<VkBufferImageCopy *>(ptr))->imageExtent.width; }, // width
     219     5095291 :                 [] (void *ptr) -> uint16_t { return (reinterpret_cast<VkBufferImageCopy *>(ptr))->imageExtent.height; }, // height
     220      102281 :                 [] (void *ptr, uint16_t value) { (reinterpret_cast<VkBufferImageCopy *>(ptr))->imageOffset.x = value; }, // x
     221      102281 :                 [] (void *ptr, uint16_t value) { (reinterpret_cast<VkBufferImageCopy *>(ptr))->imageOffset.y = value; }, // y
     222      102281 :                 [] (void *ptr, uint16_t value) { }, // tex
     223             :         });
     224             : 
     225         612 :         auto span = makeSpanView(reinterpret_cast<void **>(layoutData.data()), layoutData.size());
     226             : 
     227        1224 :         return font::emplaceChars(iface, span, totalSquare);
     228         612 : }
     229             : 
     230         612 : void FontAttachmentHandle::submitInput(FrameQueue &q, Rc<core::AttachmentInputData> &&data, Function<void(bool)> &&cb) {
     231         612 :         auto d = data.cast<font::RenderFontInput>();
     232         612 :         if (!d || q.isFinalized()) {
     233           0 :                 cb(false);
     234           0 :                 return;
     235             :         }
     236             : 
     237         612 :         q.getFrame()->waitForDependencies(data->waitDependencies, [this, cb = move(cb), d = move(d)] (FrameHandle &handle, bool success) mutable {
     238         612 :                 handle.performInQueue([this, cb = move(cb), d = move(d)] (FrameHandle &handle) mutable -> bool {
     239         612 :                         doSubmitInput(handle, move(cb), move(d));
     240         612 :                         return true;
     241             :                 }, nullptr, "RenderFontAttachmentHandle::submitInput");
     242         612 :         });
     243         612 : }
     244             : 
     245         612 : void FontAttachmentHandle::doSubmitInput(FrameHandle &handle, Function<void(bool)> &&cb, Rc<font::RenderFontInput> &&d) {
     246         612 :         _counter = d->requests.size();
     247         612 :         _input = d;
     248         612 :         if (auto instance = d->image->getInstance()) {
     249         612 :                 if (auto ud = instance->userdata.cast<RenderFontPersistentBufferUserdata>()) {
     250         600 :                         _userdata = ud;
     251         612 :                 }
     252         612 :         }
     253             : 
     254             :         // process persistent chars
     255         612 :         bool underlinePersistent = false;
     256         612 :         uint32_t totalCount = 0;
     257        3814 :         for (auto &it : _input->requests) {
     258        3202 :                 totalCount += it.chars.size();
     259             :         }
     260             : 
     261         612 :         _textureTarget.resize(totalCount + 1); // used in addPersistentCopy
     262             : 
     263         612 :         uint32_t extraPersistent = 0;
     264         612 :         uint32_t processedPersistent = 0;
     265         612 :         if (_userdata) {
     266        3790 :                 for (auto &it : _input->requests) {
     267        3190 :                         if (it.persistent) {
     268       19580 :                                 for (auto &c : it.chars) {
     269       18968 :                                         if (addPersistentCopy(it.object->getId(), c)) {
     270       18476 :                                                 ++ processedPersistent;
     271       18476 :                                                 c = 0;
     272             :                                         } else {
     273         492 :                                                 ++ extraPersistent;
     274             :                                         }
     275             :                                 }
     276             :                         }
     277             :                 }
     278             : 
     279         600 :                 if (addPersistentCopy(font::CharId::SourceMax, 0)) {
     280         600 :                         underlinePersistent = true;
     281             :                 }
     282             :         } else {
     283          24 :                 for (auto &it : _input->requests) {
     284          12 :                         if (it.persistent) {
     285          12 :                                 extraPersistent += it.chars.size();
     286             :                         }
     287             :                 }
     288             : 
     289          12 :                 underlinePersistent = false;
     290             :         }
     291             : 
     292         612 :         _onInput = move(cb); // see RenderFontAttachmentHandle::writeAtlasData
     293             : 
     294         612 :         if (processedPersistent == totalCount && underlinePersistent) {
     295             :                 // no need to transfer extra chars
     296           0 :                 writeAtlasData(handle, underlinePersistent);
     297           0 :                 return;
     298             :         }
     299             : 
     300         612 :         auto frame = static_cast<DeviceFrameHandle *>(&handle);
     301         612 :         auto &memPool = frame->getMemPool(&handle);
     302             : 
     303        1836 :         _frontBuffer = memPool->spawn(AllocationUsage::HostTransitionSource, core::BufferInfo(
     304           0 :                 core::ForceBufferUsage(core::BufferUsage::TransferSrc),
     305         612 :                 size_t(Allocator::PageSize * 2)
     306         612 :         ));
     307             : 
     308         612 :         _copyFromTmpBufferData.resize(totalCount - processedPersistent + (underlinePersistent ? 0 : 1));
     309             : 
     310         612 :         if (extraPersistent > 0 || !underlinePersistent) {
     311          47 :                 _copyToPersistentBufferData.resize(extraPersistent + (underlinePersistent ? 0 : 1));
     312          47 :                 _copyPersistentCharData.resize(extraPersistent + (underlinePersistent ? 0 : 1));
     313             : 
     314          47 :                 if (!_userdata) {
     315          12 :                         _userdata = Rc<RenderFontPersistentBufferUserdata>::alloc();
     316          12 :                         _userdata->mempool = Rc<DeviceMemoryPool>::create(memPool->getAllocator(), false);
     317          24 :                         _userdata->buffers.emplace_back(_userdata->mempool->spawn(AllocationUsage::DeviceLocal, core::BufferInfo(
     318          12 :                                         core::ForceBufferUsage(core::BufferUsage::TransferSrc | core::BufferUsage::TransferDst),
     319          12 :                                         size_t(Allocator::PageSize * 2)
     320             :                                 )));
     321          12 :                         _persistentTargetBuffer = _userdata->buffers.back();
     322             :                 } else {
     323          35 :                         auto tmp = move(_userdata);
     324          35 :                         _userdata = Rc<RenderFontPersistentBufferUserdata>::alloc();
     325          35 :                         _userdata->mempool = tmp->mempool;
     326          35 :                         _userdata->chars = tmp->chars;
     327          35 :                         _userdata->buffers = tmp->buffers;
     328             : 
     329          35 :                         if (!_userdata->buffers.empty()) {
     330          35 :                                 _persistentTargetBuffer = _userdata->buffers.back();
     331             :                         }
     332          35 :                 }
     333             :         }
     334             : 
     335         612 :         font::DeferredRequest::runFontRenderer(*_input->queue, _input->ext, _input->requests, [this] (uint32_t reqIdx, const font::CharTexture &texData) {
     336       81414 :                 pushCopyTexture(reqIdx, texData);
     337        1224 :         }, [this, handle = Rc<FrameHandle>(&handle), underlinePersistent] {
     338         612 :                 writeAtlasData(*handle, underlinePersistent);
     339             :                 // std::cout << "RenderFontAttachmentHandle::submitInput: " << platform::device::_clock(platform::device::ClockType::Monotonic) - handle->getTimeStart() << "\n";
     340         612 :         });
     341             : }
     342             : 
     343         612 : void FontAttachmentHandle::writeAtlasData(FrameHandle &handle, bool underlinePersistent) {
     344         612 :         Vector<SpanView<VkBufferImageCopy>> commands;
     345         612 :         if (!underlinePersistent) {
     346             :                 // write single white pixel for underlines
     347          12 :                 uint32_t offset = _frontBuffer->reserveBlock(1, _optimalTextureAlignment);
     348          12 :                 if (offset + 1 <= Allocator::PageSize * 2) {
     349          12 :                         uint8_t whiteColor = 255;
     350          12 :                         _frontBuffer->setData(BytesView(&whiteColor, 1), offset);
     351          12 :                         auto objectId = font::CharId::getCharId(font::CharId::SourceMax, char16_t(0), font::CharAnchor::BottomLeft);
     352          12 :                         auto texOffset = _textureTargetOffset.fetch_add(1);
     353          12 :                         _copyFromTmpBufferData[_copyFromTmpBufferData.size() - 1] = VkBufferImageCopy({
     354          12 :                                 VkDeviceSize(offset),
     355             :                                 uint32_t(texOffset),
     356             :                                 uint32_t(objectId),
     357             :                                 VkImageSubresourceLayers({VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}),
     358             :                                 VkOffset3D({0, 0, 0}),
     359             :                                 VkExtent3D({1, 1, 1})
     360             :                         });
     361             : 
     362          12 :                         auto targetOffset = _persistentTargetBuffer->reserveBlock(1, _optimalTextureAlignment);
     363          12 :                         _textureTarget[texOffset] = RenderFontCharTextureData{0, 0, 1, 1};
     364          12 :                         _copyToPersistentBufferData[_copyToPersistentBufferData.size() - 1] = VkBufferCopy({
     365          12 :                                 offset, targetOffset, 1
     366             :                         });
     367          12 :                         _copyPersistentCharData[_copyPersistentCharData.size() - 1] = RenderFontCharPersistentData{
     368             :                                 RenderFontCharTextureData{0, 0, 1, 1},
     369             :                                 objectId, 0, uint32_t(targetOffset)
     370             :                         };
     371             :                 }
     372             :         }
     373             : 
     374             :         // fill new persistent chars
     375        1380 :         for (auto &it : _copyPersistentCharData) {
     376         768 :                 it.bufferIdx = _userdata->buffers.size() - 1;
     377         768 :                 auto cIt = _userdata->chars.find(it.objectId);
     378         768 :                 if (cIt == _userdata->chars.end()) {
     379         768 :                         _userdata->chars.emplace(it.objectId, it);
     380             :                 } else {
     381           0 :                         cIt->second = it;
     382             :                 }
     383             :         }
     384             : 
     385         612 :         auto pool = memory::pool::create(memory::pool::acquire());
     386         612 :         memory::pool::push(pool);
     387             : 
     388             :         // TODO - use GPU rectangle placement
     389         612 :         commands.emplace_back(_copyFromTmpBufferData);
     390        1212 :         for (auto &it : _copyFromPersistentBufferData) {
     391         600 :                 commands.emplace_back(it.second);
     392             :         }
     393             : 
     394         612 :         _imageExtent = FontAttachmentHandle_buildTextureData(commands);
     395             : 
     396           0 :         auto atlas = Rc<core::DataAtlas>::create(core::DataAtlas::ImageAtlas,
     397         612 :                         _copyFromTmpBufferData.size() * 4, sizeof(font::FontAtlasValue), _imageExtent);
     398             : 
     399        1824 :         for (auto &c : commands) {
     400      103493 :                 for (auto &it : c) {
     401      102281 :                         pushAtlasTexture(atlas, const_cast<VkBufferImageCopy &>(it));
     402             :                 }
     403             :         }
     404             : 
     405         612 :         atlas->compile();
     406         612 :         _atlas = move(atlas);
     407             : 
     408         612 :         memory::pool::pop();
     409         612 :         memory::pool::destroy(pool);
     410             : 
     411         612 :         handle.performOnGlThread([this] (FrameHandle &handle) {
     412         612 :                 _onInput(true);
     413         612 :                 _onInput = nullptr;
     414         612 :         }, this, false, "RenderFontAttachmentHandle::writeAtlasData");
     415         612 : }
     416             : 
     417           0 : uint32_t FontAttachmentHandle::nextBufferOffset(size_t blockSize) {
     418           0 :         auto alignedSize = math::align(uint64_t(blockSize), _optimalTextureAlignment);
     419           0 :         return _bufferOffset.fetch_add(alignedSize);
     420             : }
     421             : 
     422           0 : uint32_t FontAttachmentHandle::nextPersistentTransferOffset(size_t blockSize) {
     423           0 :         auto alignedSize = math::align(uint64_t(blockSize), _optimalTextureAlignment);
     424           0 :         return _persistentOffset.fetch_add(alignedSize);
     425             : }
     426             : 
     427       19568 : bool FontAttachmentHandle::addPersistentCopy(uint16_t fontId, char16_t c) {
     428       19568 :         auto objId = font::CharId::getCharId(fontId, c, font::CharAnchor::BottomLeft);
     429       19568 :         auto it = _userdata->chars.find(objId);
     430       19568 :         if (it != _userdata->chars.end()) {
     431       19076 :                 auto &buf = _userdata->buffers[it->second.bufferIdx];
     432       19076 :                 auto bufIt = _copyFromPersistentBufferData.find(buf.get());
     433       19076 :                 if (bufIt == _copyFromPersistentBufferData.end()) {
     434         600 :                         bufIt = _copyFromPersistentBufferData.emplace(buf, Vector<VkBufferImageCopy>()).first;
     435             :                 }
     436             : 
     437       19076 :                 auto texTarget = _textureTargetOffset.fetch_add(1);
     438       19076 :                 bufIt->second.emplace_back(VkBufferImageCopy{
     439       19076 :                         VkDeviceSize(it->second.offset),
     440             :                         uint32_t(texTarget),
     441             :                         uint32_t(objId),
     442             :                         VkImageSubresourceLayers({VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}),
     443             :                         VkOffset3D({0, 0, 0}),
     444       19076 :                         VkExtent3D({it->second.texture.width, it->second.texture.height, 1})
     445             :                 });
     446             : 
     447       19076 :                 _textureTarget[texTarget] = it->second.texture;
     448       19076 :                 return true;
     449             :         }
     450         492 :         return false;
     451             : }
     452             : 
     453       81334 : void FontAttachmentHandle::pushCopyTexture(uint32_t reqIdx, const font::CharTexture &texData) {
     454       81334 :         if (texData.width != texData.bitmapWidth || texData.height != texData.bitmapRows) {
     455           0 :                 log::error("FontAttachmentHandle", "Invalid size: ", texData.width, ";", texData.height,
     456           0 :                                 " vs. ", texData.bitmapWidth, ";", texData.bitmapRows, "\n");
     457             :         }
     458             : 
     459       81341 :         auto size = texData.bitmapRows * std::abs(texData.pitch);
     460       81341 :         uint32_t offset = _frontBuffer->reserveBlock(size, _optimalTextureAlignment);
     461       81795 :         if (offset + size > Allocator::PageSize * 2) {
     462           0 :                 return;
     463             :         }
     464             : 
     465       81795 :         auto ptr = texData.bitmap;
     466       81795 :         if (texData.pitch >= 0) {
     467       81795 :                 _frontBuffer->setData(BytesView(ptr, texData.pitch * texData.bitmapRows), offset);
     468             :         } else {
     469           0 :                 for (size_t i = 0; i < texData.bitmapRows; ++ i) {
     470           0 :                         _frontBuffer->setData(BytesView(ptr, -texData.pitch), offset + i * (-texData.pitch));
     471           0 :                         ptr += texData.pitch;
     472             :                 }
     473             :         }
     474             : 
     475       83064 :         auto objectId = font::CharId::getCharId(texData.fontID, texData.charID, font::CharAnchor::BottomLeft);
     476       83020 :         auto texOffset = _textureTargetOffset.fetch_add(1);
     477      166040 :         _copyFromTmpBufferData[_copyFromTmpOffset.fetch_add(1)] = VkBufferImageCopy({
     478       82980 :                 VkDeviceSize(offset),
     479             :                 uint32_t(texOffset),
     480             :                 uint32_t(objectId),
     481             :                 VkImageSubresourceLayers({VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}),
     482             :                 VkOffset3D({0, 0, 0}),
     483       82980 :                 VkExtent3D({texData.bitmapWidth, texData.bitmapRows, 1})
     484             :         });
     485       82980 :         _textureTarget[texOffset] = RenderFontCharTextureData{texData.x, texData.y, texData.width, texData.height};
     486             : 
     487       82841 :         if (_input->requests[reqIdx].persistent) {
     488         755 :                 auto targetIdx = _copyToPersistentOffset.fetch_add(1);
     489         755 :                 auto targetOffset = _persistentTargetBuffer->reserveBlock(size, _optimalTextureAlignment);
     490         754 :                 _copyToPersistentBufferData[targetIdx] = VkBufferCopy({
     491         751 :                         offset, targetOffset, VkDeviceSize(size)
     492             :                 });
     493         751 :                 _copyPersistentCharData[targetIdx] = RenderFontCharPersistentData{
     494         746 :                         RenderFontCharTextureData{texData.x, texData.y, texData.width, texData.height},
     495             :                         objectId, 0, uint32_t(targetOffset)
     496             :                 };
     497             :         }
     498             : }
     499             : 
     500      102281 : void FontAttachmentHandle::pushAtlasTexture(core::DataAtlas *atlas, VkBufferImageCopy &d) {
     501      102281 :         font::FontAtlasValue data[4];
     502             : 
     503      102281 :         auto texOffset = d.bufferRowLength;
     504      102281 :         auto id = d.bufferImageHeight;
     505      102281 :         d.bufferImageHeight = 0;
     506      102281 :         d.bufferRowLength = 0;
     507             : 
     508      102281 :         auto &tex = _textureTarget[texOffset];
     509             : 
     510      102281 :         const float x = float(d.imageOffset.x);
     511      102281 :         const float y = float(d.imageOffset.y);
     512      102281 :         const float w = float(d.imageExtent.width);
     513      102281 :         const float h = float(d.imageExtent.height);
     514             : 
     515      102281 :         data[0].pos = Vec2(tex.x, -tex.y);
     516      102281 :         data[0].tex = Vec2(x / _imageExtent.width, y / _imageExtent.height);
     517             : 
     518      102281 :         data[1].pos = Vec2(tex.x, -tex.y - tex.height);
     519      102281 :         data[1].tex = Vec2(x / _imageExtent.width, (y + h) / _imageExtent.height);
     520             : 
     521      102281 :         data[2].pos = Vec2(tex.x + tex.width, -tex.y - tex.height);
     522      102281 :         data[2].tex = Vec2((x + w) / _imageExtent.width, (y + h) / _imageExtent.height);
     523             : 
     524      102281 :         data[3].pos = Vec2(tex.x + tex.width, -tex.y);
     525      102281 :         data[3].tex = Vec2((x + w) / _imageExtent.width, y / _imageExtent.height);
     526             : 
     527      102281 :         atlas->addObject(font::CharId::rebindCharId(id, font::CharAnchor::BottomLeft), &data[0]);
     528      102281 :         atlas->addObject(font::CharId::rebindCharId(id, font::CharAnchor::TopLeft), &data[1]);
     529      102281 :         atlas->addObject(font::CharId::rebindCharId(id, font::CharAnchor::TopRight), &data[2]);
     530      102281 :         atlas->addObject(font::CharId::rebindCharId(id, font::CharAnchor::BottomRight), &data[3]);
     531      102281 : }
     532             : 
     533          48 : FontRenderPass::~FontRenderPass() { }
     534             : 
     535          24 : bool FontRenderPass::init(QueuePassBuilder &passBuilder, const AttachmentData *attachment) {
     536          24 :         passBuilder.addAttachment(attachment);
     537             : 
     538          24 :         if (!QueuePass::init(passBuilder)) {
     539           0 :                 return false;
     540             :         }
     541          24 :         _fontAttachment = attachment;
     542          24 :         return true;
     543             : }
     544             : 
     545         612 : auto FontRenderPass::makeFrameHandle(const FrameQueue &handle) -> Rc<QueuePassHandle> {
     546        1224 :         return Rc<FontRenderPassHandle>::create(*this, handle);
     547             : }
     548             : 
     549        1224 : FontRenderPassHandle::~FontRenderPassHandle() { }
     550             : 
     551         612 : bool FontRenderPassHandle::init(QueuePass &pass, const FrameQueue &handle) {
     552         612 :         if (!QueuePassHandle::init(pass, handle)) {
     553           0 :                 return false;
     554             :         }
     555             : 
     556         612 :         _queueOps = static_cast<vk::QueuePass *>(_queuePass.get())->getQueueOps();
     557             : 
     558         612 :         auto dev = static_cast<Device *>(handle.getFrame()->getDevice());
     559         612 :         auto q = dev->getQueueFamily(_queueOps);
     560         612 :         if (q->transferGranularity.width > 1 || q->transferGranularity.height > 1) {
     561           0 :                 _queueOps = QueueOperations::Graphics;
     562           0 :                 for (auto &it : dev->getQueueFamilies()) {
     563           0 :                         if (it.index != q->index) {
     564           0 :                                 switch (it.preferred) {
     565           0 :                                 case QueueOperations::Compute:
     566             :                                 case QueueOperations::Transfer:
     567             :                                 case QueueOperations::Graphics:
     568           0 :                                         if ((it.transferGranularity.width == 1 || it.transferGranularity.height == 1) && toInt(_queueOps) < toInt(it.preferred)) {
     569           0 :                                                 _queueOps = it.preferred;
     570             :                                         }
     571           0 :                                         break;
     572           0 :                                 default:
     573           0 :                                         break;
     574             :                                 }
     575             :                         }
     576             :                 }
     577             :         }
     578             : 
     579         612 :         return true;
     580             : }
     581             : 
     582        1836 : QueueOperations FontRenderPassHandle::getQueueOps() const {
     583        1836 :         return _queueOps;
     584             : }
     585             : 
     586             : 
     587         612 : bool FontRenderPassHandle::prepare(FrameQueue &handle, Function<void(bool)> &&cb) {
     588         612 :         if (auto a = handle.getAttachment(static_cast<FontRenderPass *>(_queuePass.get())->getRenderFontAttachment())) {
     589         612 :                 _fontAttachment = static_cast<FontAttachmentHandle *>(a->handle.get());
     590             :         }
     591         612 :         return QueuePassHandle::prepare(handle, move(cb));
     592             : }
     593             : 
     594         612 : void FontRenderPassHandle::finalize(FrameQueue &handle, bool successful) {
     595         612 :         QueuePassHandle::finalize(handle, successful);
     596         612 : }
     597             : 
     598         612 : Vector<const CommandBuffer *> FontRenderPassHandle::doPrepareCommands(FrameHandle &handle) {
     599         612 :         Vector<VkCommandBuffer> ret;
     600             : 
     601         612 :         auto &input = _fontAttachment->getInput();
     602         612 :         auto &copyFromTmp = _fontAttachment->getCopyFromTmpBufferData();
     603         612 :         auto &copyFromPersistent = _fontAttachment->getCopyFromPersistentBufferData();
     604         612 :         auto &copyToPersistent = _fontAttachment->getCopyToPersistentBufferData();
     605             : 
     606         612 :         auto &masterImage = input->image;
     607         612 :         auto instance = masterImage->getInstance();
     608         612 :         if (!instance) {
     609           0 :                 return Vector<const CommandBuffer *>();
     610             :         }
     611             : 
     612         612 :         auto atlas = _fontAttachment->getAtlas();
     613             : 
     614         612 :         core::ImageInfo info = masterImage->getInfo();
     615             : 
     616         612 :         info.format = core::ImageFormat::R8_UNORM;
     617         612 :         info.extent = _fontAttachment->getImageExtent();
     618             : 
     619         612 :         auto allocator = _device->getAllocator();
     620             : 
     621         612 :         if (_device->hasDynamicIndexedBuffers()) {
     622         612 :                 _targetImage = allocator->preallocate(info, false, instance->data.image->getIndex());
     623         612 :                 _targetAtlasIndex = allocator->preallocate(core::BufferInfo(atlas->getIndexData().size(), core::BufferUsage::StorageBuffer));
     624         612 :                 _targetAtlasData = allocator->preallocate(core::BufferInfo(atlas->getData().size(), core::BufferUsage::StorageBuffer));
     625             : 
     626             :                 Rc<Buffer> atlasBuffers[] = {
     627         612 :                         _targetAtlasIndex,
     628         612 :                         _targetAtlasData
     629        1836 :                 };
     630             : 
     631         612 :                 allocator->emplaceObjects(AllocationUsage::DeviceLocal, makeSpanView(&_targetImage, 1), makeSpanView(atlasBuffers, 2));
     632        1836 :         } else {
     633           0 :                 _targetImage = allocator->spawnPersistent(AllocationUsage::DeviceLocal, info, false, instance->data.image->getIndex());
     634             :         }
     635             : 
     636         612 :         auto frame = static_cast<DeviceFrameHandle *>(&handle);
     637         612 :         auto &memPool = frame->getMemPool(&handle);
     638             : 
     639         612 :         Rc<Buffer> stageAtlasIndex, stageAtlasData;
     640             : 
     641         612 :         if (_targetAtlasIndex && _targetAtlasData) {
     642        1836 :                 stageAtlasIndex = memPool->spawn(AllocationUsage::HostTransitionSource,
     643        1836 :                                 core::BufferInfo(atlas->getIndexData().size(), core::ForceBufferUsage(core::BufferUsage::TransferSrc)));
     644        1836 :                 stageAtlasData = memPool->spawn(AllocationUsage::HostTransitionSource,
     645        1836 :                                 core::BufferInfo(atlas->getData().size(), core::ForceBufferUsage(core::BufferUsage::TransferSrc)));
     646             : 
     647         612 :                 stageAtlasIndex->setData(atlas->getIndexData());
     648         612 :                 stageAtlasData->setData(atlas->getData());
     649             :         }
     650             : 
     651         612 :         auto buf = _pool->recordBuffer(*_device, [&, this] (CommandBuffer &buf) {
     652         612 :                 Vector<BufferMemoryBarrier> persistentBarriers;
     653        1212 :                 for (auto &it : copyFromPersistent) {
     654         600 :                         if (auto b = it.first->getPendingBarrier()) {
     655          47 :                                 persistentBarriers.emplace_back(*b);
     656          47 :                                 it.first->dropPendingBarrier();
     657             :                         }
     658             :                 }
     659             : 
     660             :                 ImageMemoryBarrier inputBarrier(_targetImage,
     661             :                         0, VK_ACCESS_TRANSFER_WRITE_BIT,
     662         612 :                         VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
     663             : 
     664         612 :                 buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
     665         612 :                                 persistentBarriers, makeSpanView(&inputBarrier, 1));
     666             : 
     667             :                 // copy from temporary buffer
     668         612 :                 if (!copyFromTmp.empty()) {
     669         612 :                         buf.cmdCopyBufferToImage(_fontAttachment->getTmpBuffer(), _targetImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copyFromTmp);
     670             :                 }
     671             : 
     672             :                 // copy from persistent buffers
     673        1212 :                 for (auto &it : copyFromPersistent) {
     674         600 :                         buf.cmdCopyBufferToImage(it.first, _targetImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, it.second);
     675             :                 }
     676             : 
     677         612 :                 if (!copyToPersistent.empty()) {
     678          47 :                         buf.cmdCopyBuffer(_fontAttachment->getTmpBuffer(), _fontAttachment->getPersistentTargetBuffer(), copyToPersistent);
     679         141 :                         _fontAttachment->getPersistentTargetBuffer()->setPendingBarrier(BufferMemoryBarrier(_fontAttachment->getPersistentTargetBuffer(),
     680             :                                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
     681          47 :                                 QueueFamilyTransfer(), 0, _fontAttachment->getPersistentTargetBuffer()->getReservedSize()
     682          47 :                         ));
     683             :                 }
     684             : 
     685         612 :                 if (_targetAtlasIndex && _targetAtlasData) {
     686         612 :                         buf.cmdCopyBuffer(stageAtlasIndex, _targetAtlasIndex);
     687         612 :                         buf.cmdCopyBuffer(stageAtlasData, _targetAtlasData);
     688             :                 }
     689             : 
     690         612 :                 auto sourceLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
     691         612 :                 if (auto q = _device->getQueueFamily(getQueueOperations(info.type))) {
     692         612 :                         uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
     693         612 :                         uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
     694             : 
     695         612 :                         if (q->index != _pool->getFamilyIdx()) {
     696         612 :                                 srcQueueFamilyIndex = _pool->getFamilyIdx();
     697         612 :                                 dstQueueFamilyIndex = q->index;
     698             :                         }
     699             : 
     700         612 :                         if (input->output) {
     701           0 :                                 auto extent = _targetImage->getInfo().extent;
     702           0 :                                 auto &frame = static_cast<DeviceFrameHandle &>(handle);
     703           0 :                                 auto memPool = frame.getMemPool(&handle);
     704             : 
     705           0 :                                 _outBuffer = memPool->spawn(AllocationUsage::HostTransitionDestination, core::BufferInfo(
     706           0 :                                         core::ForceBufferUsage(core::BufferUsage::TransferDst),
     707           0 :                                         size_t(extent.width * extent.height * extent.depth),
     708           0 :                                         core::PassType::Transfer
     709           0 :                                 ));
     710             : 
     711             :                                 ImageMemoryBarrier reverseBarrier(_targetImage,
     712             :                                         VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
     713           0 :                                         sourceLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
     714           0 :                                 buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, makeSpanView(&reverseBarrier, 1));
     715             : 
     716           0 :                                 sourceLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
     717           0 :                                 buf.cmdCopyImageToBuffer(_targetImage, sourceLayout, _outBuffer, 0);
     718             : 
     719             :                                 BufferMemoryBarrier bufferOutBarrier(_outBuffer,
     720           0 :                                         VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
     721             : 
     722           0 :                                 buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, makeSpanView(&bufferOutBarrier, 1));
     723           0 :                         }
     724             : 
     725             :                         ImageMemoryBarrier outputBarrier(_targetImage,
     726             :                                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     727             :                                 sourceLayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
     728         612 :                                 QueueFamilyTransfer{srcQueueFamilyIndex, dstQueueFamilyIndex});
     729             : 
     730         612 :                         VkPipelineStageFlags targetOps = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
     731             :                                         | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
     732             : 
     733         612 :                         auto ops = getQueueOps();
     734         612 :                         switch (ops) {
     735         612 :                         case QueueOperations::Transfer:
     736         612 :                                 targetOps = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
     737         612 :                                 break;
     738           0 :                         case QueueOperations::Compute:
     739           0 :                                 targetOps = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
     740           0 :                                 break;
     741           0 :                         default:
     742           0 :                                 break;
     743             :                         }
     744             : 
     745         612 :                         if (q->index != _pool->getFamilyIdx()) {
     746         612 :                                 _targetImage->setPendingBarrier(outputBarrier);
     747             :                         }
     748             : 
     749         612 :                         if (_targetAtlasIndex && _targetAtlasData) {
     750             :                                 BufferMemoryBarrier outputBufferBarrier[] = {
     751             :                                         BufferMemoryBarrier(_targetAtlasIndex,
     752             :                                                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     753         612 :                                                 QueueFamilyTransfer{srcQueueFamilyIndex, dstQueueFamilyIndex}, 0, _targetAtlasIndex->getSize()),
     754             :                                         BufferMemoryBarrier(_targetAtlasData,
     755             :                                                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
     756         612 :                                                 QueueFamilyTransfer{srcQueueFamilyIndex, dstQueueFamilyIndex}, 0, _targetAtlasData->getSize()),
     757         612 :                                 };
     758             : 
     759         612 :                                 if (q->index != _pool->getFamilyIdx()) {
     760         612 :                                         _targetAtlasIndex->setPendingBarrier(outputBufferBarrier[0]);
     761         612 :                                         _targetAtlasData->setPendingBarrier(outputBufferBarrier[1]);
     762             :                                 }
     763             : 
     764         612 :                                 buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, targetOps, 0,
     765        1224 :                                                 makeSpanView(outputBufferBarrier, 2), makeSpanView(&outputBarrier, 1));
     766             :                         } else {
     767           0 :                                 buf.cmdPipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, targetOps, 0,
     768           0 :                                                 makeSpanView(&outputBarrier, 1));
     769             :                         }
     770             :                 }
     771         612 :                 return true;
     772         612 :         });
     773             : 
     774         612 :         return Vector<const CommandBuffer *>{buf};
     775         612 : }
     776             : 
     777         612 : void FontRenderPassHandle::doSubmitted(FrameHandle &frame, Function<void(bool)> &&func, bool success, Rc<Fence> &&fence) {
     778         612 :         if (success) {
     779         612 :                 auto &input = _fontAttachment->getInput();
     780             : 
     781         612 :                 auto atlas = _fontAttachment->getAtlas();
     782         612 :                 if (_device->hasDynamicIndexedBuffers()) {
     783         612 :                         atlas->setIndexBuffer(_targetAtlasIndex);
     784         612 :                         atlas->setDataBuffer(_targetAtlasData);
     785             :                 }
     786             : 
     787         612 :                 auto &sig = frame.getSignalDependencies();
     788             : 
     789        1224 :                 input->image->updateInstance(*frame.getLoop(), _targetImage, move(atlas),
     790        1224 :                                 Rc<Ref>(_fontAttachment->getUserdata()), sig);
     791             : 
     792         612 :                 if (input->output) {
     793           0 :                         _outBuffer->map([&, this] (uint8_t *ptr, VkDeviceSize size) {
     794           0 :                                 input->output(_targetImage->getInfo(), BytesView(ptr, size));
     795           0 :                         });
     796             :                 }
     797         612 :         }
     798             : 
     799         612 :         vk::QueuePassHandle::doSubmitted(frame, move(func), success, move(fence));
     800         612 :         frame.signalDependencies(success);
     801         612 : }
     802             : 
     803         612 : void FontRenderPassHandle::doComplete(FrameQueue &queue, Function<void(bool)> &&func, bool success) {
     804         612 :         QueuePassHandle::doComplete(queue, move(func), success);
     805         612 : }
     806             : 
     807             : }
     808             : 
     809             : #endif

Generated by: LCOV version 1.14