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
18using VsyncId = QtOhos::TypedId<std::uintptr_t, struct VsyncIdTag>;
19
20template<>
22{
23 std::size_t operator()(const VsyncId &vsyncId) const noexcept;
24};
25
26QT_BEGIN_NAMESPACE
27
28namespace QArkUi {
29
30namespace {
31
32VsyncId generateVsyncId()
33{
34 static std::uint64_t lastIdValue = 0;
35 static_assert(sizeof(std::uint64_t) == sizeof(std::uintptr_t), "uintptr_t size mismatch");
36 auto vsyncIdValue = lastIdValue;
37 lastIdValue++;
38 return VsyncId(vsyncIdValue);
39}
40
41std::string generateVSyncName(::OHNativeWindow *nativeWindow, VsyncId id)
42{
43 return QtOhos::printfToString("__qt_vsync_%p_%lu", nativeWindow, id.value());
44}
45
46class QOhosVSyncRegistry
47{
48public:
49 static QOhosVSyncRegistry &instance();
50
51 std::function<void()> create(
52 ::OHNativeWindow *nativeWindow, std::function<void()> vsyncFrameReadyFunc);
53
54private:
55 static void frameCallback(long long timestamp, void *userData);
56
57 struct VSyncContext
58 {
59 std::function<void()> vsyncFrameReadyFunc;
60 std::shared_ptr<::OH_NativeVSync> vsync;
61 };
62
63 QOhosVSyncRegistry();
64 void notifyFrameReadyFromAnyThread(VsyncId id);
65
66 std::map<VsyncId, std::shared_ptr<VSyncContext>> m_registry;
67 QOhosConsumer<VsyncId> m_notifyFrameReadyFromAnyThread;
68};
69
70QOhosVSyncRegistry &QOhosVSyncRegistry::instance()
71{
72 static QOhosVSyncRegistry result;
73 return result;
74}
75
76void QOhosVSyncRegistry::frameCallback(long long, void *userData)
77{
78 auto vsyncId = VsyncId(reinterpret_cast<std::uintptr_t>(userData));
79 instance().m_notifyFrameReadyFromAnyThread(vsyncId);
80}
81
82std::function<void()> QOhosVSyncRegistry::create(
83 ::OHNativeWindow *nativeWindow, std::function<void()> vsyncFrameReadyFunc)
84{
85 auto vsyncId = generateVsyncId();
86 auto vsyncName = generateVSyncName(nativeWindow, vsyncId);
87
88 std::uint64_t surfaceId = 0;
89 callArkUiOrFailOnErrorResult(
90 Q_OHOS_NAMED_FUNC(::OH_NativeWindow_GetSurfaceId),
91 nativeWindow, &surfaceId);
92
93 auto vsync = std::shared_ptr<::OH_NativeVSync>(
94 callArkUiOrFailOnNullResult(
95 Q_OHOS_NAMED_FUNC(::OH_NativeVSync_Create_ForAssociatedWindow),
96 surfaceId, vsyncName.c_str(), vsyncName.length()),
97 [](::OH_NativeVSync *vsync) {
98 callArkUi(
99 Q_OHOS_NAMED_FUNC(::OH_NativeVSync_Destroy),
100 vsync);
101 });
102
103 auto context = QtOhos::moveToSharedPtr(
104 VSyncContext{
105 .vsyncFrameReadyFunc = std::move(vsyncFrameReadyFunc),
106 .vsync = vsync,
107 });
108
109 m_registry.emplace(vsyncId, context);
110
111 auto contextWithDeleter =
112 QtOhos::makeSharedPtrWithAttachedExtraData(
113 context,
114 QtOhos::makeDestroyNotifier(
115 [this, vsyncId]() {
116 std::ignore = m_registry.erase(vsyncId);
117 }));
118
119 return [vsyncId, contextWithDeleter]() {
120 callArkUiOrFailOnErrorResult(
121 Q_OHOS_NAMED_FUNC(::OH_NativeVSync_RequestFrame),
122 contextWithDeleter->vsync.get(), &QOhosVSyncRegistry::frameCallback,
123 reinterpret_cast<void *>(vsyncId.value()));
124 };
125}
126
127QOhosVSyncRegistry::QOhosVSyncRegistry()
128{
129 auto vsyncFrameReadyHandler = makeQtOhosBatchingMTRequestsHandler<std::unordered_set<VsyncId>>(
130 [](std::function<void()> task) {
131 QtOhos::invokeInJsThread(
132 [task = std::move(task)](QtOhos::JsState &){
133 task();
134 });
135 },
136 [this](std::unordered_set<VsyncId> &&vsyncIds) {
137 for (auto vsyncId: vsyncIds) {
138 auto vsyncContextIt = m_registry.find(vsyncId);
139 if (vsyncContextIt != m_registry.end()) {
140 auto vsyncContext = vsyncContextIt->second;
141 vsyncContext->vsyncFrameReadyFunc();
142 }
143 }
144 });
145
146 m_notifyFrameReadyFromAnyThread = [vsyncFrameReadyHandler = std::move(vsyncFrameReadyHandler)](VsyncId vsyncId) {
147 vsyncFrameReadyHandler(
148 [&](std::unordered_set<VsyncId> &vsyncIds) {
149 vsyncIds.insert(vsyncId);
150 });
151 };
152}
153
154}
155
156std::function<void()> makeVSyncFrameRequester(
157 ::OHNativeWindow *nativeWindow, std::function<void()> vsyncFrameReadyFunc)
158{
159 return QOhosVSyncRegistry::instance().create(nativeWindow, std::move(vsyncFrameReadyFunc));
160}
161
162}
163
164std::size_t std::hash<VsyncId>::operator()(const VsyncId &vsyncId) const noexcept
165{
166 return vsyncId.value();
167}
168
169QT_END_NAMESPACE
std::function< void()> makeVSyncFrameRequester(::OHNativeWindow *nativeWindow, std::function< void()> vsyncFrameReadyFunc)
Definition vsync.cpp:156
std::size_t operator()(const VsyncId &vsyncId) const noexcept
Definition vsync.cpp:164
QtOhos::TypedId< std::uintptr_t, struct VsyncIdTag > VsyncId
Definition vsync.cpp:18