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
qdxgivsyncservice_p.h
Go to the documentation of this file.
1// Copyright (C) 2024 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#ifndef QDXGIVSYNCSERVICE_P_H
5#define QDXGIVSYNCSERVICE_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QWindow>
19#include <QMutex>
20#include <QHash>
21
22#include <dxgi1_6.h>
23
24QT_BEGIN_NAMESPACE
25
26class QDxgiVSyncThread;
27
28class Q_GUI_EXPORT QDxgiVSyncService
29{
30public:
31 // The public functions can be called on any thread. (but not at all from inside a callback)
32
33 static QDxgiVSyncService *instance();
34
35 // We want to know what adapters are in use by all the active QRhi instances
36 // at any time. This is to avoid blind EnumAdapters calls to enumerate the
37 // world every time a window is created. To be called by create()/destroy()
38 // of the QRhi D3D11/12 backends.
39 void refAdapter(LUID luid);
40 void derefAdapter(LUID luid);
41
42 // To be called from QRhi's beginFrame. Used to check if the factory is stale.
43 void beginFrame(LUID luid);
44
45 // Registering the windows can be done either by the QRhi swapchain in the
46 // backends, or e.g. in the platformwindow implementation based on the
47 // surfaceType.
48 void registerWindow(QWindow *window);
49 void unregisterWindow(QWindow *window);
50
51 // The catch is that in some cases (using an adapter such as WARP) there are
52 // no IDXGIOutputs at all, by design (even though there is very definitely a
53 // QScreen etc. from our perspective), so none of this VSyncService is
54 // functional. Hence this can never be the only way to drive updates for
55 // D3D-based windows.
56 //
57 // A requestUpdate implementation can call this function on every request in
58 // order to decide if it can rely on the callback from this service, or it
59 // should use the traditional timer-based approach for a particular window.
60 // For windows not registered the result is always false.
61 bool supportsWindow(QWindow *window);
62
63 // Callbacks are invoked on a vsync watcher thread. Whatever is done in
64 // there, it must be fast and cheap. Ideally fire a notification for the
65 // main thread somehow, and nothing else.
66 using CallbackWindowList = QVarLengthArray<QWindow *, 16>;
67 using Callback = std::function<void(const CallbackWindowList &windowList, qint64 timestampNs)>;
68 qsizetype registerCallback(Callback cb); // result is an id, always >= 1
69 void unregisterCallback(qsizetype id);
70
71private:
72 QDxgiVSyncService();
73 ~QDxgiVSyncService();
74 void destroy();
75 void teardownDxgi();
76 static void global_destroy();
77
78 struct AdapterData {
79 int ref;
80 LUID luid;
81 IDXGIAdapter *adapter;
82 struct NotifierData {
83 IDXGIOutput *output;
84 QDxgiVSyncThread *thread;
85 };
86 QHash<HMONITOR, NotifierData> notifiers;
87 };
88
89 struct WindowData {
90 IDXGIOutput *output;
91 HMONITOR monitor;
92 float reportedRefreshIntervalMs;
93 };
94
95 void cleanupAdapterData(AdapterData *a);
96 void cleanupWindowData(WindowData *w);
97 void updateWindowData(QWindow *window, WindowData *w);
98
99 bool disableService = false;
100 bool cleanupRegistered = false;
101 IDXGIFactory2 *dxgiFactory = nullptr;
102 QMutex mutex;
103 QVector<AdapterData> adapters;
104 QHash<QWindow *, WindowData> windows;
105 QVector<Callback> callbacks;
106};
107
108QT_END_NAMESPACE
109
110#endif
QDxgiVSyncThread(IDXGIOutput *output, float vsyncIntervalMsReportedForScreen, Callback callback)
void run() override
static IDXGIOutput * outputForWindow(QWindow *w, IDXGIAdapter *adapter)