| 1 | // Copyright (C) 2020 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 "qquickgraphicsdevice_p.h" |
| 5 | |
| 6 | QT_BEGIN_NAMESPACE |
| 7 | |
| 8 | /*! |
| 9 | \class QQuickGraphicsDevice |
| 10 | \since 6.0 |
| 11 | \inmodule QtQuick |
| 12 | |
| 13 | \brief The QQuickGraphicsDevice class provides an opaque container for |
| 14 | native graphics objects representing graphics devices or contexts. |
| 15 | |
| 16 | \sa QQuickWindow::setGraphicsDevice(), QQuickRenderTarget |
| 17 | */ |
| 18 | |
| 19 | /*! |
| 20 | Constructs a default QQuickGraphicsDevice that does not reference any native |
| 21 | objects. |
| 22 | */ |
| 23 | QQuickGraphicsDevice::QQuickGraphicsDevice() |
| 24 | : d(new QQuickGraphicsDevicePrivate) |
| 25 | { |
| 26 | } |
| 27 | |
| 28 | /*! |
| 29 | \internal |
| 30 | */ |
| 31 | void QQuickGraphicsDevice::detach() |
| 32 | { |
| 33 | qAtomicDetach(d); |
| 34 | } |
| 35 | |
| 36 | /*! |
| 37 | \internal |
| 38 | */ |
| 39 | QQuickGraphicsDevice::QQuickGraphicsDevice(const QQuickGraphicsDevice &other) |
| 40 | : d(other.d) |
| 41 | { |
| 42 | d->ref.ref(); |
| 43 | } |
| 44 | |
| 45 | /*! |
| 46 | \internal |
| 47 | */ |
| 48 | QQuickGraphicsDevice &QQuickGraphicsDevice::operator=(const QQuickGraphicsDevice &other) |
| 49 | { |
| 50 | qAtomicAssign(d, x: other.d); |
| 51 | return *this; |
| 52 | } |
| 53 | |
| 54 | /*! |
| 55 | Destructor. |
| 56 | */ |
| 57 | QQuickGraphicsDevice::~QQuickGraphicsDevice() |
| 58 | { |
| 59 | if (!d->ref.deref()) |
| 60 | delete d; |
| 61 | } |
| 62 | |
| 63 | /*! |
| 64 | \return true if this is a default constructed graphics device that |
| 65 | does not reference any native objects. |
| 66 | */ |
| 67 | bool QQuickGraphicsDevice::isNull() const |
| 68 | { |
| 69 | return d->type == QQuickGraphicsDevicePrivate::Type::Null; |
| 70 | } |
| 71 | |
| 72 | /*! |
| 73 | \return a new QQuickGraphicsDevice referencing an existing OpenGL \a context. |
| 74 | |
| 75 | This factory function is suitable for OpenGL. |
| 76 | |
| 77 | \note It is up the caller to ensure that \a context is going to be |
| 78 | compatible and usable with the QQuickWindow. Platform-specific mismatches in |
| 79 | the associated QSurfaceFormat, or threading issues due to attempting to use |
| 80 | \a context on multiple threads are up to the caller to avoid. |
| 81 | */ |
| 82 | #if QT_CONFIG(opengl) || defined(Q_QDOC) |
| 83 | QQuickGraphicsDevice QQuickGraphicsDevice::fromOpenGLContext(QOpenGLContext *context) |
| 84 | { |
| 85 | QQuickGraphicsDevice dev; |
| 86 | QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(p: &dev); |
| 87 | d->type = QQuickGraphicsDevicePrivate::Type::OpenGLContext; |
| 88 | d->u.context = context; |
| 89 | return dev; |
| 90 | } |
| 91 | #endif |
| 92 | |
| 93 | /*! |
| 94 | \return a new QQuickGraphicsDevice describing a DXGI adapter and D3D feature level. |
| 95 | |
| 96 | This factory function is suitable for Direct3D 11 and 12, particularly in |
| 97 | combination with OpenXR. \a adapterLuidLow and \a adapterLuidHigh together |
| 98 | specify a LUID, while a featureLevel specifies a \c{D3D_FEATURE_LEVEL_} |
| 99 | value. \a featureLevel can be set to 0 if it is not intended to be |
| 100 | specified, in which case the scene graph's defaults will be used. |
| 101 | |
| 102 | \note With Direct 3D 12 \a featureLevel specifies the \c minimum feature |
| 103 | level passed on to D3D12CreateDevice(). |
| 104 | */ |
| 105 | #if defined(Q_OS_WIN) || defined(Q_QDOC) |
| 106 | QQuickGraphicsDevice QQuickGraphicsDevice::fromAdapter(quint32 adapterLuidLow, |
| 107 | qint32 adapterLuidHigh, |
| 108 | int featureLevel) |
| 109 | { |
| 110 | QQuickGraphicsDevice dev; |
| 111 | QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(&dev); |
| 112 | d->type = QQuickGraphicsDevicePrivate::Type::Adapter; |
| 113 | d->u.adapter = { adapterLuidLow, adapterLuidHigh, featureLevel }; |
| 114 | return dev; |
| 115 | } |
| 116 | #endif |
| 117 | |
| 118 | /*! |
| 119 | \return a new QQuickGraphicsDevice referencing a native device and context |
| 120 | object. |
| 121 | |
| 122 | This factory function is suitable for Direct3D 11. \a device is expected to |
| 123 | be a \c{ID3D11Device*}, \a context is expected to be a |
| 124 | \c{ID3D11DeviceContext*}. |
| 125 | |
| 126 | It also supports Direct 3D 12, if that is the 3D API used at run time. With |
| 127 | D3D12 \a context is unused and can be set to null. \a device is expected to |
| 128 | be a \c{ID3D12Device*}. |
| 129 | |
| 130 | \note the resulting QQuickGraphicsDevice does not own any native resources, |
| 131 | it merely contains references. It is the caller's responsibility to ensure |
| 132 | that the native resource exists as long as necessary. |
| 133 | */ |
| 134 | #if defined(Q_OS_WIN) || defined(Q_QDOC) |
| 135 | QQuickGraphicsDevice QQuickGraphicsDevice::fromDeviceAndContext(void *device, void *context) |
| 136 | { |
| 137 | QQuickGraphicsDevice dev; |
| 138 | QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(&dev); |
| 139 | d->type = QQuickGraphicsDevicePrivate::Type::DeviceAndContext; |
| 140 | d->u.deviceAndContext = { device, context }; |
| 141 | return dev; |
| 142 | } |
| 143 | #endif |
| 144 | |
| 145 | /*! |
| 146 | \return a new QQuickGraphicsDevice referencing an existing \a device and |
| 147 | \a commandQueue object. |
| 148 | |
| 149 | This factory function is suitable for Metal. |
| 150 | |
| 151 | \note the resulting QQuickGraphicsDevice does not own any native resources, |
| 152 | it merely contains references. It is the caller's responsibility to ensure |
| 153 | that the native resource exists as long as necessary. |
| 154 | |
| 155 | */ |
| 156 | #if QT_CONFIG(metal) || defined(Q_QDOC) |
| 157 | QQuickGraphicsDevice QQuickGraphicsDevice::fromDeviceAndCommandQueue(MTLDevice *device, |
| 158 | MTLCommandQueue *commandQueue) |
| 159 | { |
| 160 | QQuickGraphicsDevice dev; |
| 161 | QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(&dev); |
| 162 | d->type = QQuickGraphicsDevicePrivate::Type::DeviceAndCommandQueue; |
| 163 | d->u.deviceAndCommandQueue = { device, commandQueue }; |
| 164 | return dev; |
| 165 | } |
| 166 | #endif |
| 167 | |
| 168 | /*! |
| 169 | \return a new QQuickGraphicsDevice referencing an existing \a physicalDevice. |
| 170 | |
| 171 | This factory function is suitable for Vulkan, particularly in combination |
| 172 | with OpenXR. |
| 173 | |
| 174 | \note the resulting QQuickGraphicsDevice does not own any native resources, |
| 175 | it merely contains references. It is the caller's responsibility to ensure |
| 176 | that the native resource exists as long as necessary. |
| 177 | */ |
| 178 | #if QT_CONFIG(vulkan) || defined(Q_QDOC) |
| 179 | QQuickGraphicsDevice QQuickGraphicsDevice::fromPhysicalDevice(VkPhysicalDevice physicalDevice) |
| 180 | { |
| 181 | QQuickGraphicsDevice dev; |
| 182 | QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(p: &dev); |
| 183 | d->type = QQuickGraphicsDevicePrivate::Type::PhysicalDevice; |
| 184 | d->u.physicalDevice = { .physicalDevice: physicalDevice }; |
| 185 | return dev; |
| 186 | } |
| 187 | #endif |
| 188 | |
| 189 | /*! |
| 190 | \return a new QQuickGraphicsDevice referencing an existing \a device object. |
| 191 | |
| 192 | This factory function is suitable for Vulkan. \a physicalDevice, \a device |
| 193 | and \a queueFamilyIndex must always be provided. \a queueIndex is optional |
| 194 | since the default value of 0 is often suitable. |
| 195 | |
| 196 | \note the resulting QQuickGraphicsDevice does not own any native resources, |
| 197 | it merely contains references. It is the caller's responsibility to ensure |
| 198 | that the native resource exists as long as necessary. |
| 199 | */ |
| 200 | #if QT_CONFIG(vulkan) || defined(Q_QDOC) |
| 201 | QQuickGraphicsDevice QQuickGraphicsDevice::fromDeviceObjects(VkPhysicalDevice physicalDevice, |
| 202 | VkDevice device, |
| 203 | int queueFamilyIndex, |
| 204 | int queueIndex) |
| 205 | { |
| 206 | QQuickGraphicsDevice dev; |
| 207 | QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(p: &dev); |
| 208 | d->type = QQuickGraphicsDevicePrivate::Type::DeviceObjects; |
| 209 | d->u.deviceObjects = { .physicalDevice: physicalDevice, .device: device, .queueFamilyIndex: queueFamilyIndex, .queueIndex: queueIndex }; |
| 210 | return dev; |
| 211 | } |
| 212 | #endif |
| 213 | |
| 214 | /*! |
| 215 | \return a new QQuickGraphicsDevice referencing an existing \a rhi object. |
| 216 | |
| 217 | \note Similarly to fromOpenGLContext(), the caller must be careful to only |
| 218 | share a QRhi (and so the underlying graphics context or device) between |
| 219 | QQuickWindows that are known to be compatible, not breaking the underlying |
| 220 | graphics API's rules when it comes to threading, pixel formats, etc. |
| 221 | |
| 222 | \since 6.6 |
| 223 | */ |
| 224 | QQuickGraphicsDevice QQuickGraphicsDevice::fromRhi(QRhi *rhi) |
| 225 | { |
| 226 | QQuickGraphicsDevice dev; |
| 227 | QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(p: &dev); |
| 228 | d->type = QQuickGraphicsDevicePrivate::Type::Rhi; |
| 229 | d->u.rhi = rhi; |
| 230 | return dev; |
| 231 | } |
| 232 | |
| 233 | QQuickGraphicsDevicePrivate::QQuickGraphicsDevicePrivate() |
| 234 | : ref(1) |
| 235 | { |
| 236 | } |
| 237 | |
| 238 | QQuickGraphicsDevicePrivate::QQuickGraphicsDevicePrivate(const QQuickGraphicsDevicePrivate &other) |
| 239 | : ref(1), |
| 240 | type(other.type), |
| 241 | u(other.u) |
| 242 | { |
| 243 | } |
| 244 | |
| 245 | QT_END_NAMESPACE |
| 246 | |