Line data Source code
1 : /**
2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef XENOLITH_BACKEND_VKGUI_XLVKVIEW_H_
25 : #define XENOLITH_BACKEND_VKGUI_XLVKVIEW_H_
26 :
27 : #include "XLVk.h"
28 : #include "XLView.h"
29 : #include "XLVkSwapchain.h"
30 :
31 : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
32 :
33 : class View : public xenolith::View {
34 : public:
35 : struct EngineOptions {
36 : // on some systems, we can not acquire next image until queue operations on previous image is finished
37 : // on this system, we wait on last swapchain pass fence before acquire swapchain image
38 : // swapchain-independent passes is not affected by this option
39 : bool waitOnSwapchainPassFence = false;
40 :
41 : // by default, we use vkAcquireNextImageKHR in lockfree manner, but in some cases blocking variant
42 : // is more preferable. If this option is set, vkAcquireNextImageKHR called with UIN64_MAX timeout
43 : // be careful not to block whole view's thread operation on this
44 : bool acquireImageImmediately = false;
45 :
46 : // Использовать внешний сигнал вертикальной синхронизации (система должна поддерживать)
47 : // В этом режиме готовые к презентации кадры ожидают сигнала, прежде, чем отправиться
48 : // Также, по сигналу система запрашиваает новый буфер для отрисовки следующего кадра
49 : // Если система не успела подготовить новый кадр - обновление пропускается
50 : bool followDisplayLink = false;
51 :
52 : // По умолчанию, FrameEmitter допускает только один кадр определенной RenderQueue в процессе отправки
53 : // (между vkQueueSubmit и освобождением соответсвующей VkFence). Исключение составляют проходы, помеченные как асинхронные
54 : // Если отключить это ограничение, единственным ограничением между vkQueueSubmit останутся внутренние примитивы синхронизации
55 : // В ряде случаев, неограниченная отправка буферов может привести к некорректной работе vkQueueSubmit и блокированию треда на
56 : // этой функции. Рекомендуется сохранять это ограничение. а для полной загрузки GPU использовать асинхронные пре- и пост-проходы
57 : bool enableFrameEmitterBarrier = false;
58 :
59 : // Использовать внеэкранный рендеринг для подготовки изображений. В этом режиме презентация нового изображения выполняется
60 : // строго синхронно (см. presentImmediate)
61 : bool renderImageOffscreen = false;
62 :
63 : // Не использовать переключение потоков для вывода изображения. Вместо этого, блокироваться на ожидании очереди в текущем потоке
64 : bool presentImmediate = false;
65 :
66 : // Запускать следующий кадр только по запросу либо наличию действий в процессе
67 : bool renderOnDemand = true;
68 : };
69 :
70 : virtual ~View();
71 :
72 : virtual bool init(Application &, const Device &, ViewInfo &&);
73 :
74 : virtual void threadInit() override;
75 : virtual void threadDispose() override;
76 :
77 : virtual void update(bool displayLink) override;
78 : virtual void close() override;
79 :
80 : virtual void run() override;
81 : virtual void runWithQueue(const Rc<RenderQueue> &) override;
82 :
83 : virtual void onAdded(Device &);
84 : virtual void onRemoved();
85 :
86 : virtual void deprecateSwapchain(bool fast = false) override;
87 :
88 : virtual bool present(Rc<ImageStorage> &&) override;
89 : virtual bool presentImmediate(Rc<ImageStorage> &&, Function<void(bool)> &&scheduleCb) override;
90 : virtual void invalidateTarget(Rc<ImageStorage> &&) override;
91 :
92 : virtual Rc<Ref> getSwapchainHandle() const override;
93 :
94 : virtual void captureImage(StringView, const Rc<core::ImageObject> &image, AttachmentLayout l) const override;
95 : virtual void captureImage(Function<void(const ImageInfoData &info, BytesView view)> &&,
96 : const Rc<core::ImageObject> &image, AttachmentLayout l) const override;
97 :
98 : void scheduleFence(Rc<Fence> &&);
99 :
100 0 : virtual uint64_t getUpdateInterval() const { return 0; }
101 :
102 : virtual void mapWindow();
103 :
104 : vk::Device *getDevice() const { return _device; }
105 :
106 : virtual void setReadyForNextFrame() override;
107 :
108 : virtual void setRenderOnDemand(bool value) override;
109 : virtual bool isRenderOnDemand() const override;
110 :
111 : protected:
112 : using xenolith::View::init;
113 :
114 : #if SP_REF_DEBUG
115 : virtual bool isRetainTrackerEnabled() const override {
116 : return false;
117 : }
118 : #endif
119 :
120 : enum ScheduleImageMode {
121 : AcquireSwapchainImageAsync,
122 : AcquireSwapchainImageImmediate,
123 : AcquireOffscreenImage,
124 : };
125 :
126 : struct FrameTimeInfo {
127 : uint64_t dt;
128 : uint64_t avg;
129 : uint64_t clock;
130 : };
131 :
132 : virtual bool pollInput(bool frameReady);
133 :
134 : virtual core::SurfaceInfo getSurfaceOptions() const;
135 :
136 : void invalidate();
137 :
138 : void scheduleNextImage(uint64_t windowOffset, bool immediately);
139 :
140 : // Начать подготовку нового изображения для презентации
141 : // Создает объект кадра и начинает сбор данных для его рисования
142 : // Создает объект изображения и начинает цикл его захвата
143 : // Если режим acquireImageImmediately - блокирует поток до успешного захвата изображения
144 : // windowOffset - интервал от текущего момента. когда предполагается презентовать изображение
145 : // Служит для ограничения частоты кадров
146 : void scheduleSwapchainImage(uint64_t windowOffset, ScheduleImageMode);
147 :
148 : // Попытаться захватить изображение для отрисовки кадра. Если задан флаг immediate
149 : // или включен режим followDisplayLink - блокирует поток до успешного захвата
150 : // В противном случае, если захват не удался - необходимо поробовать позже
151 : bool acquireScheduledImageImmediate(const Rc<SwapchainImage> &);
152 : bool acquireScheduledImage();
153 :
154 : void scheduleImage(Rc<SwapchainImage> &&);
155 : void onSwapchainImageReady(Rc<SwapchainHandle::SwapchainAcquiredImage> &&);
156 :
157 : virtual bool recreateSwapchain(core::PresentMode);
158 : virtual bool createSwapchain(const core::SurfaceInfo &, core::SwapchainConfig &&cfg, core::PresentMode presentMode);
159 :
160 : bool isImagePresentable(const core::ImageObject &image, VkFilter &filter) const;
161 :
162 : // Презентует отложенное подготовленное (кадр завершён) изображение
163 : void runScheduledPresent(Rc<SwapchainImage> &&);
164 :
165 : virtual void presentWithQueue(DeviceQueue &, Rc<ImageStorage> &&);
166 : void invalidateSwapchainImage(Rc<ImageStorage> &&);
167 :
168 : FrameTimeInfo updateFrameInterval();
169 :
170 : void waitForFences(uint64_t min);
171 :
172 : virtual void finalize();
173 :
174 : void updateFences();
175 :
176 : void clearImages();
177 :
178 : virtual void schedulePresent(SwapchainImage *, uint64_t);
179 :
180 : EngineOptions _options;
181 :
182 : bool _readyForNextFrame = false;
183 : bool _blockSwapchainRecreation = false;
184 : bool _swapchainInvalidated = false;
185 : uint64_t _refId = 0;
186 : uint64_t _framesInProgress = 0;
187 : uint64_t _fenceOrder = 0;
188 : uint64_t _frameOrder = 0;
189 : uint64_t _onDemandOrder = 1;
190 : uint64_t _scheduledTime = 0;
191 : uint64_t _nextPresentWindow = 0;
192 : Rc<Surface> _surface;
193 : Rc<Instance> _instance;
194 : Rc<Device> _device;
195 : Rc<SwapchainHandle> _swapchain;
196 : String _threadName;
197 :
198 : Rc<core::ImageStorage> _initImage;
199 : Vector<Rc<Fence>> _fences;
200 :
201 : Vector<Rc<SwapchainImage>> _fenceImages;
202 : std::deque<Rc<SwapchainImage>> _scheduledImages;
203 : Vector<Rc<SwapchainImage>> _scheduledPresent;
204 : Set<SwapchainHandle::SwapchainAcquiredImage *> _requestedSwapchainImage;
205 : std::deque<Rc<SwapchainHandle::SwapchainAcquiredImage>> _swapchainImages;
206 : };
207 :
208 : }
209 :
210 : #endif /* XENOLITH_BACKEND_VKGUI_XLVKVIEW_H_ */
|