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 ©FromTmp = _fontAttachment->getCopyFromTmpBufferData();
603 612 : auto ©FromPersistent = _fontAttachment->getCopyFromPersistentBufferData();
604 612 : auto ©ToPersistent = _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
|