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