1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qwindowsdirect2dcontext.h"
41 #include "qwindowsdirect2dhelpers.h"
42 #include "qwindowsdirect2dintegration.h"
43 
44 #include <d3d11_1.h>
45 #include <d2d1_1.h>
46 #include <d2d1_1helper.h>
47 #include <dxgi1_2.h>
48 #include <wrl.h>
49 #include <dwrite.h>
50 
51 using Microsoft::WRL::ComPtr;
52 
53 QT_BEGIN_NAMESPACE
54 
55 class QWindowsDirect2DContextPrivate
56 {
57 public:
init()58     bool init()
59     {
60         HRESULT hr;
61 
62         D3D_FEATURE_LEVEL level;
63 
64         D3D_DRIVER_TYPE typeAttempts[] = {
65             D3D_DRIVER_TYPE_HARDWARE,
66             D3D_DRIVER_TYPE_WARP
67         };
68         const int ntypes = int(sizeof(typeAttempts) / sizeof(typeAttempts[0]));
69 
70         for (int i = 0; i < ntypes; i++) {
71             hr = D3D11CreateDevice(nullptr,
72                                    typeAttempts[i],
73                                    nullptr,
74                                    D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT,
75                                    nullptr,
76                                    0,
77                                    D3D11_SDK_VERSION,
78                                    &d3dDevice,
79                                    &level,
80                                    &d3dDeviceContext);
81 
82             if (SUCCEEDED(hr))
83                 break;
84         }
85 
86         if (FAILED(hr)) {
87             qWarning("%s: Could not create Direct3D Device: %#lx", __FUNCTION__, hr);
88             return false;
89         }
90 
91         ComPtr<IDXGIDevice1> dxgiDevice;
92         ComPtr<IDXGIAdapter> dxgiAdapter;
93 
94         hr = d3dDevice.As(&dxgiDevice);
95         if (FAILED(hr)) {
96             qWarning("%s: DXGI Device interface query failed on D3D Device: %#lx", __FUNCTION__, hr);
97             return false;
98         }
99 
100         // Ensure that DXGI doesn't queue more than one frame at a time.
101         dxgiDevice->SetMaximumFrameLatency(1);
102 
103         hr = dxgiDevice->GetAdapter(&dxgiAdapter);
104         if (FAILED(hr)) {
105             qWarning("%s: Failed to probe DXGI Device for parent DXGI Adapter: %#lx", __FUNCTION__, hr);
106             return false;
107         }
108 
109         hr = dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory));
110         if (FAILED(hr)) {
111             qWarning("%s: Failed to probe DXGI Adapter for parent DXGI Factory: %#lx", __FUNCTION__, hr);
112             return false;
113         }
114 
115         D2D1_FACTORY_OPTIONS options = {};
116 
117 #ifdef QT_D2D_DEBUG_OUTPUT
118         qDebug("Turning on Direct2D debugging messages");
119         options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
120 #endif // QT_D2D_DEBUG_OUTPUT
121 
122         hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, options, d2dFactory.GetAddressOf());
123         if (FAILED(hr)) {
124             qWarning("%s: Could not create Direct2D Factory: %#lx", __FUNCTION__, hr);
125             return false;
126         }
127 
128         hr = d2dFactory->CreateDevice(dxgiDevice.Get(), &d2dDevice);
129         if (FAILED(hr)) {
130             qWarning("%s: Could not create D2D Device: %#lx", __FUNCTION__, hr);
131             return false;
132         }
133 
134         hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
135                                  static_cast<IUnknown **>(&directWriteFactory));
136         if (FAILED(hr)) {
137             qWarning("%s: Could not create DirectWrite factory: %#lx", __FUNCTION__, hr);
138             return false;
139         }
140 
141         hr = directWriteFactory->GetGdiInterop(&directWriteGdiInterop);
142         if (FAILED(hr)) {
143             qWarning("%s: Could not create DirectWrite GDI Interop: %#lx", __FUNCTION__, hr);
144             return false;
145         }
146 
147         return true;
148     }
149 
150     ComPtr<ID3D11Device>  d3dDevice;
151     ComPtr<ID2D1Factory1> d2dFactory;
152     ComPtr<ID2D1Device>   d2dDevice;
153     ComPtr<IDXGIFactory2>  dxgiFactory;
154     ComPtr<ID3D11DeviceContext> d3dDeviceContext;
155     ComPtr<IDWriteFactory> directWriteFactory;
156     ComPtr<IDWriteGdiInterop> directWriteGdiInterop;
157 };
158 
QWindowsDirect2DContext()159 QWindowsDirect2DContext::QWindowsDirect2DContext()
160     : d_ptr(new QWindowsDirect2DContextPrivate)
161 {
162 }
163 
164 QWindowsDirect2DContext::~QWindowsDirect2DContext() = default;
165 
init()166 bool QWindowsDirect2DContext::init()
167 {
168     Q_D(QWindowsDirect2DContext);
169     return d->init();
170 }
171 
instance()172 QWindowsDirect2DContext *QWindowsDirect2DContext::instance()
173 {
174     return QWindowsDirect2DIntegration::instance()->direct2DContext();
175 }
176 
d3dDevice() const177 ID3D11Device *QWindowsDirect2DContext::d3dDevice() const
178 {
179     Q_D(const QWindowsDirect2DContext);
180     return d->d3dDevice.Get();
181 }
182 
d2dDevice() const183 ID2D1Device *QWindowsDirect2DContext::d2dDevice() const
184 {
185     Q_D(const QWindowsDirect2DContext);
186     return d->d2dDevice.Get();
187 }
188 
d2dFactory() const189 ID2D1Factory1 *QWindowsDirect2DContext::d2dFactory() const
190 {
191     Q_D(const QWindowsDirect2DContext);
192     return d->d2dFactory.Get();
193 }
194 
dxgiFactory() const195 IDXGIFactory2 *QWindowsDirect2DContext::dxgiFactory() const
196 {
197     Q_D(const QWindowsDirect2DContext);
198     return d->dxgiFactory.Get();
199 }
200 
d3dDeviceContext() const201 ID3D11DeviceContext *QWindowsDirect2DContext::d3dDeviceContext() const
202 {
203     Q_D(const QWindowsDirect2DContext);
204     return d->d3dDeviceContext.Get();
205 }
206 
dwriteFactory() const207 IDWriteFactory *QWindowsDirect2DContext::dwriteFactory() const
208 {
209     Q_D(const QWindowsDirect2DContext);
210     return d->directWriteFactory.Get();
211 }
212 
dwriteGdiInterop() const213 IDWriteGdiInterop *QWindowsDirect2DContext::dwriteGdiInterop() const
214 {
215     Q_D(const QWindowsDirect2DContext);
216     return d->directWriteGdiInterop.Get();
217 }
218 
219 QT_END_NAMESPACE
220