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 "XLView.h"
24 : #include "XLInputDispatcher.h"
25 :
26 : namespace STAPPLER_VERSIONIZED stappler::xenolith {
27 :
28 : XL_DECLARE_EVENT_CLASS(View, onFrameRate);
29 : XL_DECLARE_EVENT_CLASS(View, onBackground);
30 : XL_DECLARE_EVENT_CLASS(View, onFocus);
31 :
32 21 : View::View() { }
33 :
34 21 : View::~View() {
35 21 : log::debug("xenolith::View", "~View");
36 21 : }
37 :
38 21 : bool View::init(Application &loop, ViewInfo &&info) {
39 21 : _mainLoop = &loop;
40 21 : _glLoop = _mainLoop->getGlLoop();
41 21 : _constraints.extent = Extent2(info.rect.width, info.rect.height);
42 21 : _constraints.density = 1.0f;
43 21 : if (info.density != 0.0f) {
44 21 : _constraints.density = info.density;
45 : }
46 21 : _constraints.contentPadding = info.decoration;
47 21 : _frameEmitter = Rc<FrameEmitter>::create(_glLoop, info.frameInterval);
48 21 : _info = move(info);
49 :
50 21 : log::debug("View", "init");
51 :
52 21 : return true;
53 : }
54 :
55 21 : void View::end() {
56 21 : _running = false;
57 21 : _frameEmitter->invalidate();
58 21 : _mainLoop->performOnMainThread([this, cb = move(_info.onClosed)] () {
59 21 : if (_director) {
60 21 : _director->end();
61 : }
62 21 : cb(*this);
63 21 : }, this);
64 21 : }
65 :
66 428776 : void View::update(bool displayLink) {
67 428776 : Vector<Pair<Function<void()>, Rc<Ref>>> callback;
68 :
69 428776 : _mutex.lock();
70 428776 : callback = move(_callbacks);
71 428776 : _callbacks.clear();
72 428776 : _mutex.unlock();
73 :
74 469645 : for (auto &it : callback) {
75 40869 : it.first();
76 : }
77 428776 : }
78 :
79 21 : void View::close() {
80 21 : _shouldQuit.clear();
81 21 : }
82 :
83 51748 : void View::performOnThread(Function<void()> &&func, Ref *target, bool immediate) {
84 51748 : if (immediate && std::this_thread::get_id() == _threadId) {
85 10791 : func();
86 : } else {
87 40957 : std::unique_lock<Mutex> lock(_mutex);
88 40957 : if (_running) {
89 40723 : _callbacks.emplace_back(move(func), target);
90 40723 : wakeup(lock);
91 234 : } else if (!_init) {
92 147 : _callbacks.emplace_back(move(func), target);
93 : }
94 40957 : }
95 51748 : }
96 :
97 21 : const Rc<Director> &View::getDirector() const {
98 21 : return _director;
99 : }
100 :
101 363 : void View::handleInputEvent(const InputEventData &event) {
102 363 : _mainLoop->performOnMainThread([this, event = event] () mutable {
103 363 : if (event.isPointEvent()) {
104 300 : event.point.density = _constraints.density;
105 : }
106 :
107 363 : switch (event.event) {
108 21 : case InputEventName::Background:
109 21 : _inBackground = event.getValue();
110 21 : onBackground(this, _inBackground);
111 21 : break;
112 21 : case InputEventName::PointerEnter:
113 21 : _pointerInWindow = event.getValue();
114 21 : break;
115 21 : case InputEventName::FocusGain:
116 21 : _hasFocus = event.getValue();
117 21 : onFocus(this, _hasFocus);
118 21 : break;
119 300 : default:
120 300 : break;
121 : }
122 363 : _director->getInputDispatcher()->handleInputEvent(event);
123 363 : }, this);
124 363 : setReadyForNextFrame();
125 363 : }
126 :
127 2708 : void View::handleInputEvents(Vector<InputEventData> &&events) {
128 2708 : _mainLoop->performOnMainThread([this, events = move(events)] () mutable {
129 7006 : for (auto &event : events) {
130 4298 : if (event.isPointEvent()) {
131 2850 : event.point.density = _constraints.density;
132 : }
133 :
134 4298 : switch (event.event) {
135 21 : case InputEventName::Background:
136 21 : _inBackground = event.getValue();
137 21 : onBackground(this, _inBackground);
138 21 : break;
139 37 : case InputEventName::PointerEnter:
140 37 : _pointerInWindow = event.getValue();
141 37 : break;
142 46 : case InputEventName::FocusGain:
143 46 : _hasFocus = event.getValue();
144 46 : onFocus(this, _hasFocus);
145 46 : break;
146 4194 : default:
147 4194 : break;
148 : }
149 4298 : _director->getInputDispatcher()->handleInputEvent(event);
150 : }
151 2708 : }, this, true);
152 2708 : setReadyForNextFrame();
153 2708 : }
154 :
155 21 : core::ImageInfo View::getSwapchainImageInfo() const {
156 21 : return getSwapchainImageInfo(_config);
157 : }
158 :
159 63 : core::ImageInfo View::getSwapchainImageInfo(const core::SwapchainConfig &cfg) const {
160 63 : core::ImageInfo swapchainImageInfo;
161 63 : swapchainImageInfo.format = cfg.imageFormat;
162 63 : swapchainImageInfo.flags = core::ImageFlags::None;
163 63 : swapchainImageInfo.imageType = core::ImageType::Image2D;
164 63 : swapchainImageInfo.extent = Extent3(cfg.extent.width, cfg.extent.height, 1);
165 63 : swapchainImageInfo.arrayLayers = core::ArrayLayers( 1 );
166 63 : swapchainImageInfo.usage = core::ImageUsage::ColorAttachment;
167 63 : if (cfg.transfer) {
168 63 : swapchainImageInfo.usage |= core::ImageUsage::TransferDst;
169 : }
170 63 : return swapchainImageInfo;
171 : }
172 :
173 63 : core::ImageViewInfo View::getSwapchainImageViewInfo(const core::ImageInfo &image) const {
174 63 : core::ImageViewInfo info;
175 63 : switch (image.imageType) {
176 21 : case core::ImageType::Image1D:
177 21 : info.type = core::ImageViewType::ImageView1D;
178 21 : break;
179 21 : case core::ImageType::Image2D:
180 21 : info.type = core::ImageViewType::ImageView2D;
181 21 : break;
182 21 : case core::ImageType::Image3D:
183 21 : info.type = core::ImageViewType::ImageView3D;
184 21 : break;
185 : }
186 :
187 126 : return image.getViewInfo(info);
188 : }
189 :
190 42 : uint64_t View::getLastFrameInterval() const {
191 42 : return _lastFrameInterval;
192 : }
193 9559 : uint64_t View::getAvgFrameInterval() const {
194 9559 : return _avgFrameIntervalValue;
195 : }
196 :
197 9538 : uint64_t View::getLastFrameTime() const {
198 9538 : return _frameEmitter->getLastFrameTime();
199 : }
200 21 : uint64_t View::getAvgFrameTime() const {
201 21 : return _frameEmitter->getAvgFrameTime();
202 : }
203 :
204 9538 : uint64_t View::getAvgFenceTime() const {
205 9538 : return _frameEmitter->getAvgFenceTime();
206 : }
207 :
208 : SP_COVERAGE_TRIVIAL
209 : Extent2 View::getExtent() const {
210 : return Extent2(_constraints.extent.width, _constraints.extent.height);
211 : }
212 :
213 21 : uint64_t View::getFrameInterval() const {
214 21 : std::unique_lock<Mutex> lock(_frameIntervalMutex);
215 21 : return _info.frameInterval;
216 21 : }
217 :
218 21 : void View::setFrameInterval(uint64_t value) {
219 21 : performOnThread([this, value] {
220 21 : std::unique_lock<Mutex> lock(_frameIntervalMutex);
221 21 : _info.frameInterval = value;
222 21 : _frameEmitter->setFrameInterval(value);
223 21 : onFrameRate(this, int64_t(_info.frameInterval));
224 21 : }, this, true);
225 21 : }
226 :
227 : SP_COVERAGE_TRIVIAL
228 : void View::setReadyForNextFrame() {
229 :
230 : }
231 :
232 : SP_COVERAGE_TRIVIAL
233 : void View::setRenderOnDemand(bool value) {
234 :
235 : }
236 :
237 : SP_COVERAGE_TRIVIAL
238 : bool View::isRenderOnDemand() const {
239 : return true;
240 : }
241 :
242 42 : void View::retainBackButton() {
243 42 : performOnThread([this] {
244 42 : ++ _backButtonCounter;
245 42 : }, this, true);
246 42 : }
247 :
248 42 : void View::releaseBackButton() {
249 42 : performOnThread([this] {
250 21 : -- _backButtonCounter;
251 21 : }, this, true);
252 42 : }
253 :
254 21 : uint64_t View::getBackButtonCounter() const {
255 21 : return _backButtonCounter;
256 : }
257 :
258 969 : void View::setDecorationTone(float) {
259 :
260 969 : }
261 :
262 105 : void View::setDecorationVisible(bool) {
263 :
264 105 : }
265 :
266 21 : uint64_t View::retainView() {
267 21 : return retain();
268 : }
269 :
270 21 : void View::releaseView(uint64_t id) {
271 21 : release(id);
272 21 : }
273 :
274 : SP_COVERAGE_TRIVIAL
275 : void View::setContentPadding(const Padding &padding) {
276 : _constraints.contentPadding = padding;
277 : setReadyForNextFrame();
278 : }
279 :
280 : }
|