Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
vsync.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qarkui/vsync.h>
5
6#include <cstdint>
7#include <functional>
8#include <map>
9#include <memory>
10#include <native_vsync/native_vsync.h>
11#include <native_window/external_window.h>
12#include <qarkui/qarkuiutils.h>
13#include <qohosplugincore.h>
14#include <qohosutils.h>
15#include <render/qohosbatchingrequestshandler.h>
16#include <unordered_set>
17#include <utility>
18
19using VsyncId = QtOhos::TypedId<std::uintptr_t, struct VsyncIdTag>;
20
21template<>
23{
24 std::size_t operator()(const VsyncId &vsyncId) const noexcept;
25};
26
27QT_BEGIN_NAMESPACE
28
29namespace QArkUi {
30
31namespace {
32
33VsyncId generateVsyncId()
34{
35 static std::uint64_t lastIdValue = 0;
36 static_assert(sizeof(std::uint64_t) == sizeof(std::uintptr_t), "uintptr_t size mismatch");
37 auto vsyncIdValue = lastIdValue;
38 lastIdValue++;
39 return VsyncId(vsyncIdValue);
40}
41
42std::string generateVSyncName(::OHNativeWindow *nativeWindow, VsyncId id)
43{
44 return QtOhos::printfToString("__qt_vsync_%p_%lu", nativeWindow, id.value());
45}
46
47class QOhosVSyncRegistry
48{
49public:
50 static QOhosVSyncRegistry &instance();
51
52 std::function<void()> create(
53 ::OHNativeWindow *nativeWindow, std::function<void()> vsyncFrameReadyFunc);
54
55private:
56 static void frameCallback(long long timestamp, void *userData);
57
58 struct VSyncContext
59 {
60 std::function<void()> vsyncFrameReadyFunc;
61 std::shared_ptr<::OH_NativeVSync> vsync;
62 };
63
64 QOhosVSyncRegistry();
65 void notifyFrameReadyFromAnyThread(VsyncId id);
66
67 std::map<VsyncId, std::shared_ptr<VSyncContext>> m_registry;
68 QOhosConsumer<VsyncId> m_notifyFrameReadyFromAnyThread;
69};
70
71QOhosVSyncRegistry &QOhosVSyncRegistry::instance()
72{
73 static QOhosVSyncRegistry result;
74 return result;
75}
76
77void QOhosVSyncRegistry::frameCallback(long long, void *userData)
78{
79 auto vsyncId = VsyncId(reinterpret_cast<std::uintptr_t>(userData));
80 instance().m_notifyFrameReadyFromAnyThread(vsyncId);
81}
82
83std::function<void()> QOhosVSyncRegistry::create(
84 ::OHNativeWindow *nativeWindow, std::function<void()> vsyncFrameReadyFunc)
85{
86 auto vsyncId = generateVsyncId();
87 auto vsyncName = generateVSyncName(nativeWindow, vsyncId);
88
89 std::uint64_t surfaceId = 0;
90 callArkUiOrFailOnErrorResult(
91 Q_OHOS_NAMED_FUNC(::OH_NativeWindow_GetSurfaceId),
92 nativeWindow, &surfaceId);
93
94 auto vsync = std::shared_ptr<::OH_NativeVSync>(
95 callArkUiOrFailOnNullResult(
96 Q_OHOS_NAMED_FUNC(::OH_NativeVSync_Create_ForAssociatedWindow),
97 surfaceId, vsyncName.c_str(), vsyncName.length()),
98 [](::OH_NativeVSync *vsync) {
99 callArkUi(
100 Q_OHOS_NAMED_FUNC(::OH_NativeVSync_Destroy),
101 vsync);
102 });
103
104 auto context = QtOhos::moveToSharedPtr(
105 VSyncContext{
106 .vsyncFrameReadyFunc = std::move(vsyncFrameReadyFunc),
107 .vsync = vsync,
108 });
109
110 m_registry.emplace(vsyncId, context);
111
112 auto contextWithDeleter =
113 QtOhos::makeSharedPtrWithAttachedExtraData(
114 context,
115 QtOhos::makeDestroyNotifier(
116 [this, vsyncId]() {
117 std::ignore = m_registry.erase(vsyncId);
118 }));
119
120 return [vsyncId, contextWithDeleter]() {
121 callArkUiOrFailOnErrorResult(
122 Q_OHOS_NAMED_FUNC(::OH_NativeVSync_RequestFrame),
123 contextWithDeleter->vsync.get(), &QOhosVSyncRegistry::frameCallback,
124 reinterpret_cast<void *>(vsyncId.value()));
125 };
126}
127
128QOhosVSyncRegistry::QOhosVSyncRegistry()
129{
130 auto vsyncFrameReadyHandler = makeQtOhosBatchingMTRequestsHandler<std::unordered_set<VsyncId>>(
131 [](std::function<void()> task) {
132 QtOhos::invokeInJsThread(
133 [task = std::move(task)](QtOhos::JsState &){
134 task();
135 });
136 },
137 [this](std::unordered_set<VsyncId> &&vsyncIds) {
138 for (auto vsyncId: vsyncIds) {
139 auto vsyncContextIt = m_registry.find(vsyncId);
140 if (vsyncContextIt != m_registry.end()) {
141 auto vsyncContext = vsyncContextIt->second;
142 vsyncContext->vsyncFrameReadyFunc();
143 }
144 }
145 });
146
147 m_notifyFrameReadyFromAnyThread = [vsyncFrameReadyHandler = std::move(vsyncFrameReadyHandler)](VsyncId vsyncId) {
148 vsyncFrameReadyHandler(
149 [&](std::unordered_set<VsyncId> &vsyncIds) {
150 vsyncIds.insert(vsyncId);
151 });
152 };
153}
154
155}
156
157std::function<void()> makeVSyncFrameRequester(
158 ::OHNativeWindow *nativeWindow, std::function<void()> vsyncFrameReadyFunc)
159{
160 return QOhosVSyncRegistry::instance().create(nativeWindow, std::move(vsyncFrameReadyFunc));
161}
162
163}
164
165std::size_t std::hash<VsyncId>::operator()(const VsyncId &vsyncId) const noexcept
166{
167 return vsyncId.value();
168}
169
170QT_END_NAMESPACE
std::function< void()> makeVSyncFrameRequester(::OHNativeWindow *nativeWindow, std::function< void()> vsyncFrameReadyFunc)
Definition vsync.cpp:157
std::size_t operator()(const VsyncId &vsyncId) const noexcept
Definition vsync.cpp:165
QtOhos::TypedId< std::uintptr_t, struct VsyncIdTag > VsyncId
Definition vsync.cpp:19